int psp=0;

///////////////////////////////////////////////////////////////////////////////
// Wonderswan emulator
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <time.h>
#include <syscall.h>
#include <define.h>
#include "pg.h"
//#include "sound.h"
#include "button.h"
#include "nec/nec.h"
#include "gpu.h"
#include "io.h"
#include "ws.h"

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
int			app_gameRunning=0;
int			app_rotated=0;
int			ws_colourScheme=COLOUR_SCHEME_DEFAULT;
int			ws_system=WS_SYSTEM_AUTODETECT;

char		ws_rom_path[MAX_PATH];
char		old_rom_path[MAX_PATH];
char		ws_app_path[MAX_PATH];
char		ws_rom_name[MAX_NAME];
char		ws_save_path[MAX_PATH];

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
// COMMENT 後でEnhanceする！！！
int bSleep = 0;
int bExit = 1;

int exit_callback(void) 
{ 
#if 0
	scePowerSetClockFrequency(222, 222, 111);
#endif

	bSleep=1;
    bExit=0;
    
//	// Cleanup the games resources etc (if required) 
//	ws_saveSRAM(ws_save_path);
//
//	// Exit game 
//	sceKernelExitGame(); 

	return 0;
}

void power_callback(int unknown, int pwrflags) 
{
	int cbid;

#if 0
	scePowerSetClockFrequency(222, 222, 111);
#endif

	// Combine pwrflags and the above defined masks 
	if(pwrflags & POWER_CB_POWER){
		bSleep=1;
		ws_saveSRAM(ws_save_path);
	}
	
	// コールバック関数の再登録
	cbid = sceKernelCreateCallback("Power Callback", power_callback);
	scePowerRegisterCallback(0, cbid);
} 

// Thread to create the callbacks and then begin polling 
//int CallbackThread(void *arg) 
int CallbackThread(int args, void *argp)
{ 
	int cbid; 

	cbid = sceKernelCreateCallback("Exit Callback", exit_callback); 
	SetExitCallback(cbid); 
	cbid = sceKernelCreateCallback("Power Callback", power_callback); 
	scePowerRegisterCallback(0, cbid); 

	KernelPollCallbacks(); 
} 

/* Sets up the callback thread and returns its thread id */ 
int SetupCallbacks(void) 
{ 
	int thid = 0; 

	thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0); 
	if(thid >= 0) 
	{ 
		sceKernelStartThread(thid, 0, 0); 
	} 

	return thid; 
} 


////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
//signed short backbuffer[224*144*16];

#ifdef GPU_ALIGN
signed short backbuffer[256*256];
#else
signed short backbuffer[224*144];
#endif

extern SETTING setting;
void renderer_update_pad()
{
    ctrl_data_t	paddata;

    if(psp) sceCtrlPeek(&paddata, 1);
    else    sceCtrlRead(&paddata, 1);

#if 1
    ws_key = 0;

    if( paddata.buttons & CTRL_LTRIGGER ) ws_key|=0x80000000;

    extern uint8 ws_key_flipped;
    uint32 key_x=0;
    uint32 key_y=0;
    uint32 key_b=0;

#define UP     1
#define DOWN   4
#define RIGHT  2
#define LEFT   8
#define START  2
#define BT_A   4
#define BT_B   8
    
    if(ws_key_flipped) {
        if( paddata.buttons & CTRL_UP)    key_y |= RIGHT;
        if( paddata.buttons & CTRL_RIGHT) key_y |= DOWN;
        if( paddata.buttons & CTRL_DOWN)  key_y |= LEFT;
        if( paddata.buttons & CTRL_LEFT)  key_y |= UP;
        
//        if(psp){
//            if( paddata.Lx< 43 ) w |= 1; // left
//            if( paddata.Lx>211 ) ws_key |= 2; // right
//            if( paddata.Ly< 43 ) ws_key |= 4; // up
//            if( paddata.Ly>211 ) ws_key |= 8; // down
//        }
        
        if( paddata.buttons & CTRL_TRIANGLE) key_x |= RIGHT;
        if( paddata.buttons & CTRL_CIRCLE)   key_x |= DOWN;
        if( paddata.buttons & CTRL_CROSS)    key_x |= LEFT;
        if( paddata.buttons & CTRL_SQUARE)   key_x |= UP;

        
        if( paddata.buttons & CTRL_START)    key_b |= START;
    } else {
        if( paddata.buttons & CTRL_UP)    key_x |= UP;
        if( paddata.buttons & CTRL_RIGHT) key_x |= RIGHT;
        if( paddata.buttons & CTRL_DOWN)  key_x |= DOWN;
        if( paddata.buttons & CTRL_LEFT)  key_x |= LEFT;
        
        if(psp){
            if( paddata.Lx< 43 ) key_x |= LEFT;  // left
            if( paddata.Lx>211 ) key_x |= RIGHT; // right
            if( paddata.Ly< 43 ) key_x |= UP;    // up
            if( paddata.Ly>211 ) key_x |= DOWN;  // down
        }
        
        //    if( paddata.buttons & CTRL_TRIANGLE) ws_key |= 1<<(0+sh);
        if( paddata.buttons & CTRL_START)    key_b |= START;
        if( paddata.buttons & CTRL_CIRCLE)   key_b |= BT_A;
        if( paddata.buttons & CTRL_CROSS)    key_b |= BT_B;
        //    if( paddata.buttons & CTRL_SQUARE)   ws_key |= 1<<(3+sh);
    }

    ws_key = (key_y<<8) | (key_x<<4) | key_b;

    if(paddata.buttons & CTRL_LTRIGGER) {
        ws_key |= 0x80000000;
    }
#else
    ws_key_up		= 0;
	ws_key_down		= 0;
	ws_key_left		= 0;
	ws_key_right	= 0;
	ws_key_button_1	= 0;
	ws_key_button_2	= 0;
	ws_key_start	= 0;
	ws_key_menu		= 0;
#endif
    


}

void render_screen()
{
	if (app_rotated) {
		pgBitBltN1v((SCREEN_WIDTH - 144) / 2, (SCREEN_HEIGHT - 224) / 2, (unsigned long *)backbuffer);
	} else {
		pgBitBltN1h((SCREEN_WIDTH - 224) / 2, (SCREEN_HEIGHT - 144) / 2, (unsigned long *)backbuffer);
	}
    
    {
        static unsigned int lasttick=0,framerate = 0;
        register DWORD curtick = sceKernelLibcClock();
        int fps;
        char fpstring[8];
        
        if(lasttick > curtick) {
            lasttick = curtick;
        }
        
        framerate = (framerate + (curtick-lasttick))/2;
        if(framerate==0) fps = 0;
        else             fps = ((10000000/(framerate))+9)/10;
        lasttick = curtick;

        sprintf(fpstring,"%3d",fps);
        pgPrintBG(0,5,31,fpstring);
    }

}

extern SETTING setting;
void ws_emulate_standard(void)
{
	unsigned long startTime, endTime, totalFrames;
	unsigned int nNormalLast=0;
	int nNormalFrac=0;
	int nTime=0,nCount=0; int i=0;
	int surfacePitch;
	
	char buf[128];
//	memset(backbuffer,0x00,224*144*sizeof(signed short));
    memset(backbuffer,0x00,sizeof(backbuffer));
	totalFrames=0;
	nNormalLast=0;
	nNormalFrac=0;
	
//	ws_loadSRAM(ws_save_path); // -> menu
	
	const unsigned int sync_time=16666;
	unsigned long prev_time, cur_time, diff_time = 1000000;
	unsigned long framecount = 0;

    if(psp) {
        scePowerSetClockFrequency(333,333,166);
    }
    
	while(bExit) {

        //pgFillvram(0);

#if 0
		nTime = sceKernelLibcClock()/1000 - nNormalLast;
		nCount=(nTime*600 - nNormalFrac) /10000;
		nNormalFrac+=nCount*10000;
		nNormalLast+=nNormalFrac/600;
		nNormalFrac%=600;
		
		renderer_update_pad();
		
		if (nCount>5)
			nCount=5; // Original 10
		for (i=0;i<nCount-1;i++)
			while (!ws_executeLine(backbuffer,0));
		while (!ws_executeLine(backbuffer,1));
		totalFrames++;
#else
		
		renderer_update_pad();
		
        while (!ws_executeLine(backbuffer,(totalFrames%5)>=0));
		totalFrames++;
#endif

#if 1
		if (ws_key & 0x80000000) {
#else
		if (ws_key_menu == 1) {
#endif
            // 
//            wavoutStopPlay0();
			main_menu(0);
//			if(setting.sound)
//				wavoutStartPlay0(&wavinfo_bg);
			
			// 調整
		}
		
        pgScreenFlip();
        
//		if(bSleep){
//			wavoutStopPlay0();
//			pgWaitVn(220);
			
//			if(setting.sound)
//            wavoutStartPlay0(&wavinfo_bg);
//			bSleep=0;
//		}
	}

    sceKernelExitGame(); 
}

extern char LastPath[MAX_PATH];
int xmain(int argc, char *argv)
{

	// set path info
	int n;
	char *p;

    if(argc==1) {
        psp = 0;
        strcpy(ws_app_path, "ms0:/psp/game/pswan/eboot.pbp");
        strcpy(LastPath,"ms0:/psp/game/pswan/");
    } else {
        psp = 1;
        n = argc;
        if (n > sizeof(ws_app_path) - 1) n = sizeof(ws_app_path) - 1;
        memcpy(ws_app_path, argv, n);
        ws_app_path[sizeof(ws_app_path) - 1] = 0;
        strcpy(ws_app_path, argv);
        p = strrchr(ws_app_path, '/');
        *++p = 0;
        strcpy(LastPath, ws_app_path);
    }

	// Initialize screen
	pgScreenInit();

	// Initialize controler
	pgControlInit();
	
	// Set Callback
	int tid;
	tid = SetupCallbacks();

    // Initialize wave
    //wavoutInit();

	pgScreenClear();

	load_config(); // call before getFilePath()

	// Load ROM
//	while (!getFilePath(ws_rom_path))
//		;
	main_menu(1);

/*
	p = strrchr(ws_rom_path, '/');
	strcpy(ws_rom_name, ++p);
	strcpy(ws_save_path, ws_rom_path);
	p = strrchr(ws_save_path, '/');
	*++p = 0;
	strcat(ws_save_path, ws_rom_name);
	p = strrchr(ws_save_path, '.');
	*++p = 0;
	strcat(ws_save_path, "sav");
*/

//	pgScreenClear();


#if 0
scePowerSetClockFrequency(333,333,166);
char buf[128];
int freq = scePowerGetCpuClockFrequency();
sprintf(buf, "scePowerGetCpuClockFrequency() = %d", freq);
pgMessage(buf, MSG_DEBUG, 100);
#endif

/* 場所変更 -> menu
	if (ws_init(ws_rom_path)) {
		app_rotated=ws_rotated();
		app_gameRunning=1;
		ws_set_system(ws_system);
		ws_set_colour_scheme(ws_colourScheme);
		ws_reset();
		
		ws_emulate_standard();
	}
*/
	ws_emulate_standard();

	ws_done();

	return(0);
}

