#include "main.h"

void file_write(const char *file, int val);
int file_read(const char *file);
    
static int debug = 0;

#define DBG(args...) if (debug) fprintf(stderr, ##args)

static debug_dump_res_states(Resource *r)
{
   int i;
   
   if (!debug) return;
   fprintf(stderr, "Resource states for \"%s\"\n", r->res);
   for (i = 0; i < r->reqs_num; i++)
     fprintf(stderr, "  \"%s\" -> \"%s\"\n", r->reqs[i].src, r->reqs[i].state);
}

static Resource *res_cpu = NULL;

static void
res_init(void)
{
   res_cpu = resource_init("cpu");
}

static void
res_cpu_state_eval(void)
{
   const char *state;
   
   state = resource_evaluate(res_cpu);
   if (!state) return;
   if (!strcmp(state, "off"))
     {
	DBG("action: State evaluation of \"cpu\" demands suspend. Suspending\n");
	cpu_suspend();
	DBG("action: End Suspend/off state of \"cpu\"\n");
	DBG("action: Clearing requested states of \"cpu\"\n");
	resource_state_requests_clear(res_cpu);
	DBG("action: Cleared requested states of \"cpu\"\n");
     }
}

static void
res_state_req_add(const char *res, const char *src, const char *state)
{
   if (strcmp(res, "cpu")) return;
   if (resource_state_request_add(res_cpu, src, state))
     {
	debug_dump_res_states(res_cpu);
	res_cpu_state_eval();
     }
   else
     debug_dump_res_states(res_cpu);
}

static void
res_state_req_del(const char *res, const char *src)
{
   if (strcmp(res, "cpu")) return;
   if (resource_state_request_del(res_cpu, src))
     {
	debug_dump_res_states(res_cpu);
	res_cpu_state_eval();
     }
   else
     debug_dump_res_states(res_cpu);
}

static const char *
res_state_get(const char *res)
{
   if (strcmp(res, "cpu")) return "unknown";
   debug_dump_res_states(res_cpu);
   return "on";
}

#define SERVICE_NAME  "org.openmoko.Power"
#define SERVICE_PATH  "/"
#define SERVICE_IFACE "Core"

static E_DBus_Connection *conn = NULL;
static E_DBus_Object *obj = NULL;

static DBusMessage *
_req_ListResources(E_DBus_Object *obj, DBusMessage *msg)
{
   DBusMessage *reply;
   DBusMessageIter iter, array, item;
   const char *str;
   
   // (only 1 resource supported right now) list:
   //   cpu
   DBG("request: ListResources\n");
   reply = dbus_message_new_method_return(msg);
   dbus_message_iter_init_append(reply, &iter);
   dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(s)", &array);
   
   dbus_message_iter_open_container(&array, DBUS_TYPE_STRUCT, NULL, &item);
   str = "cpu";
   dbus_message_iter_append_basic(&item, DBUS_TYPE_STRING, &(str));
   dbus_message_iter_close_container(&array, &item);
   
   dbus_message_iter_close_container(&iter, &array);
   return reply;
}

static DBusMessage *
_req_GetResourceState(E_DBus_Object *obj, DBusMessage *msg)
{
   DBusMessage *reply;
   DBusMessageIter iter;
   const char *res = NULL;
   
   dbus_message_iter_init(msg, &iter);
   dbus_message_iter_get_basic(&iter, &res);
   
   reply = dbus_message_new_method_return(msg);
   DBG("request: GetResourceState(\"%s\")\n", res);
   if (res)
     {
	const char *state = NULL;
	
	state = res_state_get(res);
	if (state)
	  {
	     dbus_message_iter_init_append(reply, &iter);
	     dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &state);
	  }
     }
   return reply;
}

static DBusMessage *
_req_RequestResourceState(E_DBus_Object *obj, DBusMessage *msg)
{
   DBusMessageIter iter;
   const char *res = NULL, *src = NULL, *state = NULL;
   
   dbus_message_iter_init(msg, &iter);
   dbus_message_iter_get_basic(&iter, &res);
   dbus_message_iter_next(&iter);
   dbus_message_iter_get_basic(&iter, &src);
   dbus_message_iter_next(&iter);
   dbus_message_iter_get_basic(&iter, &state);
   DBG("request: RequestResourceState(\"%s\", \"%s\", \"%s\")\n", res, src, state);
   if (res && src && state)
     res_state_req_add(res, src, state);
   return dbus_message_new_method_return(msg);
}

static DBusMessage *
_req_RemoveRequestedResourceState(E_DBus_Object *obj, DBusMessage *msg)
{
   DBusMessageIter iter;
   const char *res = NULL, *src = NULL;
   
   dbus_message_iter_init(msg, &iter);
   dbus_message_iter_get_basic(&iter, &res);
   dbus_message_iter_next(&iter);
   dbus_message_iter_get_basic(&iter, &src);
   DBG("request: RemoveRequestedResourceState(\"%s\", \"%s\")\n", res, src);
   if (res && src)
     res_state_req_del(res, src);
   return dbus_message_new_method_return(msg);
}

static void
_request_service(void *data, DBusMessage *msg, DBusError *err)
{
   E_DBus_Interface *iface;
   
   if (dbus_error_is_set(err))
     {
	fprintf(stderr, "%s\n", err->message);
	exit(-1);
     }
   DBG("Init interface\n");
   obj = e_dbus_object_add(conn, SERVICE_PATH, NULL);
   iface = e_dbus_interface_new(SERVICE_NAME"."SERVICE_IFACE);
   
   e_dbus_interface_method_add(iface, "ListResources", "", "a(s)", _req_ListResources);
   e_dbus_interface_method_add(iface, "GetResourceState", "s", "s", _req_GetResourceState);
   e_dbus_interface_method_add(iface, "RequestResourceState", "sss", "", _req_RequestResourceState);
   e_dbus_interface_method_add(iface, "RemoveRequestedResourceState", "ss", "", _req_RemoveRequestedResourceState);
   
   e_dbus_object_interface_attach(obj, iface);
   
   DBG("Init resource\n");
   res_init();
}

static void
_declare_iface(E_DBus_Connection *c)
{
   conn = c;
   e_dbus_request_name(conn, SERVICE_NAME, 0, _request_service, NULL);
}

int
main(int argc, char **argv)
{
   E_DBus_Connection *c;
   int i;
   
   for (i = 0; i < argc; i++)
     {
	if (!strcmp(argv[i], "-h"))
	  {
	     printf("Usage:\n"
		    "  -h     This help\n"
		    "  -d     Enable debugging\n");
	     exit(0);
	  }
	else if (!strcmp(argv[i], "-d"))
	  {
	     debug = 1;
	  }
     }
   
   ecore_init();
   ecore_string_init();
   ecore_app_args_set(argc, (const char **)argv);
   e_dbus_init();

   c = e_dbus_bus_get(DBUS_BUS_SYSTEM);
   if (!c)
     {
	fprintf(stderr, "ERROR: can't connect to system session\n");
	exit(-1);
     }

   _declare_iface(c);

   DBG("Beginning main loop\n");
   
   ecore_main_loop_begin();

   e_dbus_connection_close(c);
   e_dbus_shutdown();
   ecore_string_shutdown();
   ecore_shutdown();
   
   return 0;
}
