//////////////////////////////////////////////////
//* Custom Firmware Extender For 3.71 Firmware *//
//////////////////////////////////////////////////

#include <psptypes.h>
#include <pspkernel.h>

#include <string.h>
#include "../include/systemctrl_se.h"
#include "../include/pspmodulemgr_kernel.h"
#include "../include/systemctrl.h"
#include "../include/pspsysmem_kernel.h"

#include "main.h"
#include "screenshot.h"
#include "conf.h"
#include "translateButtons.h"

#include "blit.h"

PSP_MODULE_INFO("cfe_game_mod", 0x1000, 1, 1);
PSP_MAIN_THREAD_ATTR(0);
PSP_MAIN_THREAD_STACK_SIZE_KB(0);

#define HOSTFSDRIVER_NAME "USBHostFSDriver"
#define HOSTFSDRIVER_PID  (0x1C9)

#define PSP_USBBUS_DRIVERNAME "USBBusDriver"
#define PSP_USBSTOR_DRIVERNAME "USBStor_Driver"
#define PSP_USB_ACTIVATED              0x200

char strBuf0[64];
char strBuf1[64];
char strBuf2[64];
char strBuf3[64];
char strBuf4[64];
char strBuf5[64];
char strBuf6[64];
char strBuf7[64];
char strBuf8[64];
char strBuf9[64];

char strMsg[128];

int showMsg = 0;
int showHelp = 0;

int cpuSpeed = 222;
int firstBoot = 0;
int menuDone = 0;
int kill_display = 0;

int usePspSlim = 0;

char fullpath[30][128];
int num = 0;
int remotejoy =0;

SceCtrlData pad;
SceCtrlData padIso;
unsigned int pad_old;

SceUID main_thid;
SceUID display_thid;

CONFIGFILE config;

int build_args(char *args, const char *execfile, int argc, char **argv)
{
	int loc = 0;
	int i;

	strcpy(args, execfile);
	loc += strlen(execfile) + 1;
	for(i = 0; i < argc; i++)
	{
		strcpy(&args[loc], argv[i]);
		loc += strlen(argv[i]) + 1;
	}

	return loc;
}

int loadStartModule(const char *name, int argc, char **argv)
{
	SceUID modid;
	int status;
	char args[1024];
	int len;

	modid = sceKernelLoadModule(name, 0, NULL);
	if(modid >= 0)
	{
		len = build_args(args, name, argc, argv);
		modid = sceKernelStartModule(modid, len, (void *) args, &status, NULL);
	}
	else
	{
		printf("lsm: Error loading module %s\n", name);
	}

	return modid;
}

int unloadStopModule(char *modname)
{
	SceModule *mod;

	while ((mod = sceKernelFindModuleByName(modname)))
	{
		sceKernelStopModule(mod->modid, 0, NULL, NULL, NULL);
		sceKernelUnloadModule(mod->modid);
	}

	return 0;

}

int doBlit(char *msg)
{
	strcpy(strMsg, msg);
	showMsg=1;
	return 0;
}	

int display_thread(SceSize args, void *argp)
{
    while(1) 
	{
		if(kill_display) 
		{
			sceKernelExitDeleteThread(0);
		}
		
		if(showMsg)
		{
			blit_string(1,33,strMsg,0xffffff,0x000000);
			showMsg++;
			if(showMsg==600) showMsg=0;			
		}
		
		if(showHelp)
		{
			blit_string(1, 13, "Custom Firmware Extender 1.8",0xffffff,0x000000);
			blit_string(1, 14, "==========================================",0xffffff,0x000000);
			blit_string(1, 16, strBuf0,0xffffff,0x000000);
			blit_string(1, 18, strBuf1,0xffffff,0x000000);
			blit_string(1, 20, strBuf2,0xffffff,0x000000);
			blit_string(1, 22, strBuf3,0xffffff,0x000000);
			blit_string(1, 24, strBuf4,0xffffff,0x000000);
			blit_string(1, 26, strBuf5,0xffffff,0x000000);
			blit_string(1, 28, strBuf6,0xffffff,0x000000);
			blit_string(1, 30, strBuf7,0xffffff,0x000000);
			blit_string(1, 32, "Circle = Hide This Help",0xffffff,0x000000);
		}

		sceKernelDelayThread(2000);
    }
	return 0;
}

void setCpuSpeed(void)
{
	switch(cpuSpeed) {

		case 111:
			sctrlHENSetSpeed(111,55);
			cpuSpeed=222;
			sceKernelDelayThread(10000);
			if(!firstBoot) {
				sprintf(strBuf0,"Cpu/Bus Speed => %03d/%03d",scePower_driver_FDB5BFE9(),scePower_driver_1688935C());
				doBlit(strBuf0);
			}			
			break;		
	
		case 222:
			sctrlHENSetSpeed(222,111);
			cpuSpeed=266;
			sceKernelDelayThread(10000);
			if(!firstBoot) {
				sprintf(strBuf0,"Cpu/Bus Speed => %03d/%03d",scePower_driver_FDB5BFE9(),scePower_driver_1688935C());
				doBlit(strBuf0);
			}			
			break;
					
		case 266:
			sctrlHENSetSpeed(266,133);
			cpuSpeed=333;
			sceKernelDelayThread(10000);
			if(!firstBoot) {
				sprintf(strBuf0,"Cpu/Bus Speed => %03d/%03d",scePower_driver_FDB5BFE9(),scePower_driver_1688935C());
				doBlit(strBuf0);
			}
			break;
	
		case 333:
			sctrlHENSetSpeed(333,166);
			cpuSpeed=66;
			sceKernelDelayThread(10000);
			if(!firstBoot) {
				sprintf(strBuf0,"Cpu/Bus Speed => %03d/%03d",scePower_driver_FDB5BFE9(),scePower_driver_1688935C());
				doBlit(strBuf0);
			}
			break;
	
		case 66:
			sctrlHENSetSpeed(66,33);
			cpuSpeed=111;
			sceKernelDelayThread(10000);
			if(!firstBoot) {
				sprintf(strBuf0,"Cpu/Bus Speed => %03d/%03d",scePower_driver_FDB5BFE9(),scePower_driver_1688935C());
				doBlit(strBuf0);
			}
			break;
	}
}


/*int hookWait2 = 0;

void cleanBeforeExit() {

	if(hookWait2>0) hookWait2--;
	
	if(!hookWait2)
	{
		SceUID thids[50];
		int thid_count = 0;
		int i;
		SceKernelThreadInfo thinfo;

		sceKernelGetThreadmanIdList(SCE_KERNEL_TMID_Thread,thids,50,&thid_count);
		for(i=0;i<thid_count;i++)
			{
			memset(&thinfo,0,sizeof(SceKernelThreadInfo));
			thinfo.size = sizeof(SceKernelThreadInfo);
            
			sceKernelReferThreadStatus(thids[i],&thinfo);

			if(strcmp(&thinfo.name[0],"SceKernelLoadExecThread")==0)
			{
				menuDone = 1;
				kill_display=1;
				sceKernelTerminateDeleteThread(main_thid);
				sctrlHENSetSpeed(222,111);
				sceKernelSelfStopUnloadModule(0, 0, NULL); 
			}
		}
		hookWait2 = 200;
		
	}
}*/

int helpMenu() 
{	
	menuDone=0;
	
	sprintf(strBuf0, "%s + %s = Shutdown PSP", config.comboButton, config.poweroffButton);
	sprintf(strBuf1, "%s + %s = Reboot PSP", config.comboButton, config.resetButton);
	sprintf(strBuf2, "%s + %s = Change Cpu Speed", config.comboButton, config.cpuspeedButton);
	sprintf(strBuf3, "%s + %s = Set Max Brightness", config.comboButton, config.maxBrightnessButton);
	sprintf(strBuf4, "%s + %s = Start/Stop Usb Mass", config.comboButton, config.startStopUsbmassButton);
	sprintf(strBuf5, "%s + %s = Take Screenshot", config.comboButton, config.takeScreenshotButton);
	sprintf(strBuf6, "%s + %s = Start video capture", config.comboButton, config.captureButton);
	sprintf(strBuf7, "%s + %s = Show this help", config.comboButton, config.showHelpButton);	
		
	while(!menuDone)
	{
		//cleanBeforeExit();
		
		showHelp=1;
		
		sceDisplay_driver_B685BA36();		
		
		sceCtrl_driver_C4AAD55F(&pad, 1);
		if (pad.Buttons != pad_old)
		{	
			if(pad.Buttons & PSP_CTRL_CIRCLE) 
			{
				showHelp=0;
				menuDone=1;
			}
		}
	}
	pad_old = pad.Buttons;
	sceKernelDelayThread(1000);
	return 0;
}

void setBrightness(int x)
{
	sceDisplay_driver_776ADFDB(x,0);
}

int threadMain(SceSize args, void *argp)
{
	firstBoot = 1;
	
	read_config("fatms0:/seplugins/cfe/cfe.config", &config);
	sceKernelDelayThread(10000);
	
	while(!translateButtons()) {
		printf("waiting\n");
	}
	
	cpuSpeed=config.defaultCpuSpeedGame;
	setCpuSpeed();

	sceKernelDelayThread(30*100000);
	
	setBrightness(config.defaultBrightnessGame);
	
	firstBoot=0;

	while(1) {
	
		//cleanBeforeExit();

		sceCtrl_driver_C4AAD55F(&pad, 1);
		
		if (pad.Buttons != pad_old)
		{		
			if(poweroffEnable) 
			{
				if((pad.Buttons & (poweroffButton_i | comboButton_i)) == (poweroffButton_i | comboButton_i))				
				{
					scePower_driver_9B1A9C5F();
				}
			}

			if(resetEnable) 
			{	
				if((pad.Buttons & (resetButton_i | comboButton_i)) == (resetButton_i | comboButton_i))
				{
					scePower_driver_E65F00BD();
				}	
			}
			
			if(cpuspeedEnable) {
				if((pad.Buttons & (cpuspeedButton_i | comboButton_i)) == (cpuspeedButton_i | comboButton_i))			
				{
					setCpuSpeed();
				}
			}
	
			if(maxBrightnessEnable) 
			{	
				if((pad.Buttons & (maxBrightnessButton_i | comboButton_i)) == (maxBrightnessButton_i | comboButton_i))
				{
					setBrightness(99);
					doBlit("Brightness set to maximum value");
				}
			}
			
			if(takeScreenshotEnable) 
			{
				if((pad.Buttons & (takeScreenshotButton_i | comboButton_i)) == (takeScreenshotButton_i | comboButton_i))			
				{
					//screenshot(config.captureFolder);
					screenshot();
					sprintf(strBuf0,"Screenshot saved to %s", file);
					doBlit(strBuf0);
				}	
			}
			
			if(showHelpEnable)
			{
				if((pad.Buttons & (showHelpButton_i | comboButton_i)) == (showHelpButton_i | comboButton_i))
				{
					helpMenu();
				}
			}
			
			//if(config.usePspSlim)
			//{
				if(captureEnable) 
				{
					if((pad.Buttons & (captureButton_i | comboButton_i)) == (captureButton_i | comboButton_i))
					{
						if(!remotejoy) {
							doBlit("Starting remotejoy video capture plugin");
							
							loadStartModule("ms0:/seplugins/cfe/usbhostfs.prx", 0, NULL);	
							sceKernelDelayThread(5*100000);	
							loadStartModule("ms0:/seplugins/cfe/remotejoy_371.prx", 0, NULL);
							
							remotejoy=1;	
							doBlit("Done");
							
						} 
						else
						{
							doBlit("Stoping remotejoy video capture plugin");
							
							SceUID thids[50];
							int thid_count = 0;
							int i;
							SceKernelThreadInfo thinfo;

							sceKernelGetThreadmanIdList(SCE_KERNEL_TMID_Thread,thids,50,&thid_count);
							for(i=0;i<thid_count;i++)
							{
								memset(&thinfo,0,sizeof(SceKernelThreadInfo));
								thinfo.size = sizeof(SceKernelThreadInfo);
            
								sceKernelReferThreadStatus(thids[i],&thinfo);

								if(strcmp(&thinfo.name[0],"ScreenThread")==0)
								{
									sceKernelTerminateDeleteThread(thids[i]);
								}
								if(strcmp(&thinfo.name[0],"RemoteJoy")==0)
								{
									sceKernelTerminateDeleteThread(thids[i]);
								}
							}
							//unloadStopModule("RemoteJoy");
							//unloadUsbhost();
							remotejoy=0;
						}
					}
				}
			//}	
		}
		pad_old = pad.Buttons;
		sceKernelDelayThread(1000);
	}
	return 0;
}

int module_start(SceSize args, void *argp)
{
	
	display_thid = sceKernelCreateThread("cfe_game_display", display_thread, 8, 0x200, 0, NULL);
	if(display_thid >= 0) sceKernelStartThread(display_thid, args, argp);
	
	nkLoad();
	
	main_thid = sceKernelCreateThread("cfe_game_main", threadMain, 6, 0x1000, 0, NULL);
	if(main_thid >= 0) sceKernelStartThread(main_thid, args, argp);

	return 0;

	sceKernelExitDeleteThread(0);
}

int module_stop(SceSize args, void *argp)
{
	return 0;
}
