#include "comm.h"
#include "osdbase.h"
#include "menu.h"
#include "menuitems.h"
#include "common.h"
#include <vdr/tools.h>
#include <vdr/skins.h>
#include <vdr/interface.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

cPerlComm::cPerlComm(FILE *Pipe):
		mPipe(Pipe)
{
}

cPerlComm::~cPerlComm()
{
}

void cPerlComm::SendAction(const char *Format, ...)
{
	va_list ap;
	va_start(ap, Format);
	vfprintf(mPipe, Format, ap);
	va_end(ap);

	fprintf(mPipe, "\n");
	fflush(mPipe);
}

void cPerlComm::ReadAction(const char *Until)
{
	char *buffer = NULL;
	size_t len;
	do {
		fprintf(stderr, "ReadAction\n");
		int result = getline(&buffer, &len, mPipe);
		if (result == -1) {
			esyslog("ERROR: Communication with scripting host broken: %m");
			break;
		}

		buffer[strlen(buffer) - 1] = '\0';
		fprintf(stderr, "ReadAction: %s\n", buffer);
		HandleAction(buffer);
	} while (strchr(Until, buffer[0]) == NULL);
	free(buffer);
}

void cPerlComm::HandleAction(const char *Action) 
{
	char action = Action[0];
	const char *opts = skipspace(Action + 1);

	switch (action) {
	case 'I': InterfaceAction(opts); break;

	case 'C': CreateObject(opts); break;

	case 'M': ObjectMethod(opts); break;
	}
}

void cPerlComm::InterfaceAction(const char *Opts)
{
	char **params = SplitParameters(Opts, 2);

	if      (strcmp(params[0], "Message") == 0) {
		Skins.Message(mtStatus, params[1]);
	}
	else if (strcmp(params[0], "ReadKey") == 0) {
		eKeys key = Interface->Wait(atoi(params[1]));
		SendAction("i %d", key);
	}
	
	FreeParameters(params, 2);
}

void cPerlComm::CreateObject(const char *Opts)
{
	void *object = NULL;
	char **params = SplitParameters(Opts, 1);

	if (params == NULL) return;
	if      (strcmp(params[0], "OsdMenu") == 0) {
		char **opts = SplitParameters(params[1], 1, false);
		object = new cPerlOsdMenu(mPipe, opts[0]);
		FreeParameters(opts, 1);
	}
	else if (strcmp(params[0], "OsdItem") == 0) {
		char **opts = SplitParameters(params[1], 2, false);
		object = new cPerlOsdItem(mPipe, opts[0], opts[1] 
		                          ? (eOSState)atoi(opts[1]) : osUnknown);
		FreeParameters(opts, 2);
	}
	else if (strcmp(params[0], "MenuText") == 0) {
		char **opts = SplitParameters(params[1], 1, false);
		object = new cPerlMenuText(mPipe, opts[0]);
		FreeParameters(opts, 1);
	}
	else if (strcmp(params[0], "MenuEditStrItem") == 0) {
		char **opts = SplitParameters(params[1], 4, false);
		object = new cPerlMenuEditStrItem(mPipe, opts[0], opts[1], opts[2] 
		                                  ? atoi(opts[2]) : 0, opts[3]);
		FreeParameters(opts, 4);
	}
	else if (strcmp(params[0], "MenuEditStraItem") == 0) {
		char **opts = SplitParameters(params[1], 2);

		int count = 0;
		char **strings = NULL;
		char **words = SplitParameters(opts[2], 1);
		while (words) {
			strings = (char**)realloc(strings, sizeof(char*) * (count + 1));
			strings[count++] = strdup(words[0]);

			char **temp = words;
			words = temp[1] != NULL ? SplitParameters(temp[1], 1) : NULL;
			FreeParameters(temp, 1);
		}
		object = new cPerlMenuEditStraItem(mPipe, opts[0], atoi(opts[1]), 
		                                   count, strings);
		FreeParameters(opts, 2);
	}

	SendAction("c %s=%p", params[0], object);
	FreeParameters(params, 1);
}

void cPerlComm::ObjectMethod(const char *Opts)
{
	BEGIN_OBJECT_MAP(Opts, 
		MAP_OBJECT(OsdMenu)
		MAP_OBJECT(OsdItem)
		MAP_OBJECT(MenuText)
	);
}
		
