#include <pspkernel.h>
#include <pspdebug.h>
#include <pspdisplay.h>
#include <pspctrl.h>
#include <stdio.h>
#include <string.h>
#include <pspirkeyb.h>
#include <pspirkeyb_rawkeys.h>
#include "../sdk/inputdriver.h"
#include "../sdk/inputframework.h"

PSP_MODULE_INFO("piKeyIR", 0x1000, 1, 1);
PSP_NO_CREATE_MAIN_THREAD();

#define	DRIVERVER	"1"
#define REQUIREDVER	1

SceUID irthread;

int gcurrmode;

int getDriverInfo(DRIVERINFO *infostruct) {
	strcpy(infostruct->driverVersion, DRIVERVER);
	if(infostruct->apiVersion < REQUIREDVER) return PIKEY_ERROR_VERSION;
	else {
		strcpy(infostruct->driverName, "IR");
		infostruct->apiVersion = PIKEY_THIS_VERSION;
		infostruct->unicodeSupported = FALSE;
		return PIKEY_SUCCESS;
	}
}

#define CONFIG_FILE  "ms0:/seplugins/pikey/pspirkeyb.ini"

SceUID threadid;
void               *buffer;
SIrKeybScanCodeData scancodebuffer[255];
unsigned char       vt100buffer[255];

SceUID load_module(const char *path, int flags, int type)
{
	SceKernelLMOption option;
	SceUID mpid;

	/* If the type is 0, then load the module in the kernel partition, otherwise load it
	   in the user partition. */
	if (type == 0) {
		mpid = 1;
	} else {
		mpid = 2;
	}

	memset(&option, 0, sizeof(option));
	option.size = sizeof(option);
	option.mpidtext = mpid;
	option.mpiddata = mpid;
	option.position = 0;
	option.access = 1;

	return sceKernelLoadModule(path, flags, type > 0 ? &option : NULL);
}

int main_thread(SceSize args, void *argp) {
	int ret;

	// delay to be sure everything is initialised elsewhere
	sceKernelDelayThread(100000);

	int status;
	// We have to load the IRDA PRX if we're in VSH mode.
  // if (!waitForModule("sceSIRCS_IrDA_Driver"))
	if (isVshMode())
	{
		sioPrint("Need to load IRDA\r\n");

		// load the IRDA module.
		SceUID modid = load_module("flash0:/kd/irda.prx", 0, 0);
		if (modid > 0)
		{
			ret = sceKernelStartModule(modid, 0, NULL, &status, NULL);
			if (ret < 0)
			{
				sioPrint("failed to start IRDA: ");
				sioPrintWord(ret);
				sioPrint("\r\n");
				return ret;
			}
		}
		else
		{
			sioPrint("failed to load IRDA: ");
			sioPrintWord(ret);
			sioPrint("\r\n");
		  return 4;
		}
	}

	sioPrint("Starting libpspirkeyb\r\n");
	ret = pspIrKeybInit( CONFIG_FILE, 1 );
	if( ret != PSP_IRKBD_RESULT_OK )
	{
		sioPrint("!! libpspirkeyb failed !!\r\n");
		return 0;
	}

	sioPrint("IR in ready.\r\n");

	gcurrmode = -1;

	for(;;) {	
		// avoid tight loops
		sceKernelDelayThread(1000);

		// check which mode the framework is in, and switch the IR lib accordingly
		int lmode = getMode();
		if (lmode != gcurrmode)
		{
			if (lmode == PIKEY_KEYMODE_VT100STREAM)
			{
				pspIrKeybOutputMode( PSP_IRKBD_OUTPUT_MODE_VT100 );
				buffer = vt100buffer;
			}
			else if (lmode == PIKEY_KEYMODE_KEYPRESS)
			{
				pspIrKeybOutputMode( PSP_IRKBD_OUTPUT_MODE_SCANCODE );
				buffer = scancodebuffer;
			}
			gcurrmode = lmode;
		}

    int length, ii;

    ret = pspIrKeybReadinput(buffer, &length);

		// returns 0 for success, all errors are negative
    if((ret >= 0) && (length > 0))
    {
			for (ii = 0; ii < length; ii++)
			{
				if (gcurrmode == PIKEY_KEYMODE_VT100STREAM)
				{
					putNextChar(vt100buffer[ii]);
				}
				else if (gcurrmode == PIKEY_KEYMODE_KEYPRESS)
				{
					sendKeyPress(scancodebuffer[ii].raw,
									     scancodebuffer[ii].pressed,
											 scancodebuffer[ii].shift,
											 scancodebuffer[ii].ctrl,
											 scancodebuffer[ii].alt);
				}
			}
    }
	}

	return 0;
}

// called by module_start
int main(void) {
	threadid = sceKernelCreateThread("IRumode", main_thread, 16, 0xA000, 0, NULL);
	if (threadid >= 0) sceKernelStartThread(threadid, 0, NULL);
	else return threadid;

	return 0;
}

SceSize sceKernelMaxFreeMemSize()
{
	return 0x4000;
}

