 //////////////////////////////////////////////////////////////////////////////
//
// PocketFrog - The Game Library for Pocket PC Devices
// Copyright 2002  Thierry Tremblay
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation.  Thierry Tremblay makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
//
//////////////////////////////////////////////////////////////////////////////

#include "blit.h"
#include "resource.h"

using namespace Frog;

#ifndef ARM
	static char IDE_SEMAFORO_NAME[512];
#endif

//////////////////////////////////////////////////////////////////////////////
//
// _Module : This is needed to use ATL Windows
//
//////////////////////////////////////////////////////////////////////////////

CComModule _Module;


//////////////////////////////////////////////////////////////////////////////
//
// BlitSample
//
//////////////////////////////////////////////////////////////////////////////


BlitSample::BlitSample()
{
	loader=NULL;

#ifdef DRAW_NAG
	// azzera variabili check donateware
	donatecheck=false;

	// check su stringa per verificare se è una release donateware e dobbiamo togliere il bannerino
	char chk_str_don[20];
	strcpy(chk_str_don, "dovemistai");
	if (
		(chk_str_don[0]==CCRELCODE[0]) && (chk_str_don[1]==CCRELCODE[1]) && (chk_str_don[2]==CCRELCODE[2]) && (chk_str_don[3]==CCRELCODE[3]) && (chk_str_don[4]==CCRELCODE[4]) && 
		(chk_str_don[5]==CCRELCODE[5]) && (chk_str_don[6]==CCRELCODE[6]) && (chk_str_don[7]==CCRELCODE[7]) && (chk_str_don[8]==CCRELCODE[8]) && (chk_str_don[9]==CCRELCODE[9])
	) donatecheck=true;
#endif

	// carica settaggi dal file di ini
	GameSettings *settings=new GameSettings(_T("fba.ini"), true);
	settings->StartBufferedOperation();

	// su windows e non in modalità release (solo nell'editor), crea top most per facilitare debug nell'ide
#ifndef ARM
	#ifndef RELEASE_VERSION
		m_config.forceWindowsTopMost = settings->LoadBool("startup", "windowtopmost", true);
	#endif
	// su windows, continua a processare eventi anche quando non sei focusato
	m_config.doEventAlsoWhenNotFocused = true;
#endif

	// titolo finestra
    m_config.szWindowName = _T( FBASIC_VERSION );

	// dimensioni della finestra desktop
	m_config.desktopWidth=settings->LoadLong("startup", "windowswidth", 240);
	m_config.desktopHeight=settings->LoadLong("startup", "windowsheight", 320);

	// rotazione
	switch (settings->LoadLong("startup", "orientation", 0)) {
		case 1:
			m_config.orientation  = ORIENTATION_ROTATE180;
			break;
		case 2:
			m_config.orientation  = ORIENTATION_ROTATE90CW;
			break;
		case 3:
			m_config.orientation  = ORIENTATION_ROTATE90CCW;
			break;
		default:
			m_config.orientation  = ORIENTATION_NORMAL;
			break;
	}


	// colore di avvio del background
	configValues.startBGColor=Color(
			(unsigned char)settings->LoadLong("startup", "bgcolor_1", 0),
			(unsigned char)settings->LoadLong("startup", "bgcolor_2", 0),
			(unsigned char)settings->LoadLong("startup", "bgcolor_3", 0)
		);

	// colore trasparenza di default
	configValues.startTransColor=Color(
			(unsigned char)settings->LoadLong("startup", "trans_1", 0),
			(unsigned char)settings->LoadLong("startup", "trans_2", 0),
			(unsigned char)settings->LoadLong("startup", "trans_3", 0)
		);

	// segna fps
	configValues.wantedFps=(short)settings->LoadLong("startup", "fps", 60);

	// ci dice se iniziare o meno in modalità step by step
	configValues.startInStepByStep=settings->LoadBool("startup", "start-step-by-step", false);

	// ci dice se avviarci in modalità debug (log su socket)
	configValues.debug=settings->LoadBool("startup", "debug", false);

	// su quale porta ascoltare per il debug
	configValues.listenPort=(unsigned short)settings->LoadLong("startup", "debugport", 5555);

	// tempo di timeout connessione socket
	configValues.socketTimeout=settings->LoadLong("startup", "socket_timeout", configValues.wantedFps*10 /* 60*10 = 10 secondi */);

	// scripts .fba da ignorare negli includes, perchè vuoti!
	configValues.ignoredIncludeVoidScripts=settings->LoadShortString("startup", "ignore_include_void", "");

	// inizializza la hekkus
#ifdef ENABLE_AUDIO
	hss_speaker.open(
		settings->LoadLong("sound", "frequency", 44100),
		settings->LoadLong("sound", "bps", 16),
		settings->LoadBool("sound", "stereo", true),
		settings->LoadLong("sound", "maxmodchannels", 2),
		settings->LoadLong("sound", "maxsfxchannels", 16)
		);
#endif

	// chiudi file ini
	settings->EndBufferedOperation();
	delete settings;

	// ignore il draw del loader al primo step
	_firstStepIgnoreDraw = true;
}

BlitSample::~BlitSample()
{
#ifdef ENABLE_AUDIO
	// distruggi la hekkus
	hss_speaker.close();
#endif
	free(configValues.ignoredIncludeVoidScripts);
}

bool BlitSample::GameInit()
{
    Display* display = GetDisplay();
	PFrogConsole::instance()->init(0, display, Color(255,255,255), 
#ifdef DEBUG
		true,
#else
		false, 
#endif
	true);
	GameFPS::instance()->init(configValues.wantedFps, display);
	PFrogConsole::instance()->addconsole(0, "FIXING FPS: %d", configValues.wantedFps);
	util=NULL;

	
	// ok, qui abbiamo finito, aspetta il socket adesso
#ifndef RELEASE_VERSION
	dsock=new DebugSock(configValues.listenPort, configValues.debug);
	_waitingSocket=true;
	_waitSocketCount=0;
#endif

#ifdef DRAW_NAG
	// crea classe per nagtext
	nagcount=-0;
	nagtext=new SimpleTextSmall();
#endif

	// su windows, puoi cancellare il file semaforo dopo l'avvio
#ifndef ARM
	if (strlen(IDE_SEMAFORO_NAME) > 0) {
		unlink(IDE_SEMAFORO_NAME);
	}
#endif

	return true;

}



void BlitSample::GameEnd()
{
	// segnala quit al loader, se inizializzato
	if (loader)
		loader->SignalQuit();

#ifndef RELEASE_VERSION
	delete dsock;
#endif

#ifdef DRAW_NAG
	delete nagtext;
#endif
	delete util;
	delete loader; loader = NULL;
	PFrogConsole::instance()->destroy();
}

void BlitSample::GameLostFocus()
{
#ifdef ENABLE_AUDIO
	hss_speaker.suspend();
#endif
	if (loader)
		loader->GameLostFocus();
}
void BlitSample::GameGotFocus()
{
#ifdef ENABLE_AUDIO
	hss_speaker.resume();
#endif
	if (loader)
		loader->GameGotFocus();
}

void BlitSample::GameLoop()
{
    Display* display = GetDisplay();
    display->GetBackBuffer();

	// aggiorna lo stato del socket (attesa connessione)
	// nota: qui dentro inizializza anche lo script principale, quando il socket è pronto
	WaitSocketConnection(display);

	// esegui il loop
	if (loader && !loader->Shutdown()) {
		if (_firstStepIgnoreDraw) {
			display->Clear(configValues.startBGColor);
			_firstStepIgnoreDraw = false;
		} else {
			loader->draw(display);
		}
	}

#ifdef DRAW_NAG
	// mostra nagscreen finchè dobbiamo
	if ( !donatecheck )
		DrawNag(display);
#endif

	PFrogConsole::instance()->draw(display);
	GameFPS::instance()->beforescreenupdate(display);


	// Update screen
	display->Update();

	// se c'è il flag per l'uscite, o l'attesa socket è arrivata al timeout
	if ( 
#ifndef RELEASE_VERSION
		(!this->_waitingSocket && !dsock->isConnected()) || /* socket disconnesso */
		(this->_waitingSocket && configValues.socketTimeout < _waitSocketCount) || /* timeout attesa socket */
#endif
		(loader && loader->Shutdown()) /* applicazione ha chiesto di uscire */
		)
		Shutdown();
}



void BlitSample::StylusDown( Point stylus )
{
	PFrogConsole::instance()->StylusDown(stylus);
	if (loader)
		loader->StylusDown(stylus);
}




void BlitSample::StylusUp( Point stylus )
{
	PFrogConsole::instance()->StylusUp(stylus);
	if (loader)
		loader->StylusUp(stylus);
}



void BlitSample::StylusMove( Point stylus )
{
	if (loader)
		loader->StylusMove(stylus);
}

void BlitSample::ButtonUp( int button )
{
	if (loader)
		loader->ButtonUp(button);
}

void BlitSample::ButtonDown( int button )
{
	if (loader)
		loader->ButtonDown(button);
}

// aggiorna lo stato per l'attesa del socket
void BlitSample::WaitSocketConnection(Display *display)
{
#ifdef RELEASE_VERSION
	// in modalità release, istanzia subito le classi di utilità e il loader
	if (!util)
		util=new Utils();
	if (!loader) {
		loader=new Loader(
			configValues.startTransColor,
			display, 
#ifdef ENABLE_AUDIO
			&hss_speaker, 
#endif
			&m_keys, util,
			configValues.ignoredIncludeVoidScripts
			);
		loader->LoadMainScript( configValues.startInStepByStep );
	}
#else
	///////////////// ATTESA SOCKET ///////////////////
	// se stiamo aspettando il socket..
	if (this->_waitingSocket) {
		display->Clear( configValues.startBGColor );
		++_waitSocketCount;

		// il socket si è connesso, yeah !!!
		if (dsock->isConnected()) {

			// se il loader non è ancora inizializzato
			if (!loader) {

				// inizializza classe principale loader
				util=new Utils();

				loader=new Loader(
					configValues.startTransColor,
					dsock, display,
#ifdef ENABLE_AUDIO
					&hss_speaker, 
#endif
					&m_keys, util,
					configValues.ignoredIncludeVoidScripts
					);

				// send welcome message
				char buf[BUFFERSIZE];
				sprintf(buf, "001||%s", FBASIC_VERSION);
				dsock->socksend(0, buf);

			}
			
			// carica lo script principale appena l'editor da l'ok
			if (loader && loader->EditorIsReady()) {
				loader->LoadMainScript( configValues.startInStepByStep );
				// non dobbiamo piu' aspettare il socket
				this->_waitingSocket=false;
			}
		}
	}
	///////////////// ATTESA SOCKET ///////////////////
#endif
} // BlitSample::WaitSocketConnection()


#ifdef DRAW_NAG
// disegna il nagscreen
void BlitSample::DrawNag(Display *display)
{
	if (nagcount >= 0) {
		++nagcount;
		if (nagcount > 755)  {
			nagcount=-1;
			delete nagtext;
			nagtext=NULL;
			display->FillRect(display->GetWidth()-115, display->GetHeight()-10, display->GetWidth()-1, display->GetHeight()-1, Color(0,0,0));
			return;
		}
		display->FillRect(display->GetWidth()-115, display->GetHeight()-10, display->GetWidth()-2, display->GetHeight()-2, Color(255,255,255));
		if (nagcount >= 500)
			nagtext->drawstring(display, Color(0,0,0), display->GetWidth()-110, display->GetHeight()-9, "WWW.FBACREATOR.COM");
		else
			nagtext->drawstring(display, Color(0,0,0), display->GetWidth()-110, display->GetHeight()-9, "POWERED BY %s", FBASIC_VERSION);
		display->DrawRect(display->GetWidth()-115, display->GetHeight()-10, display->GetWidth()-2, display->GetHeight()-2, Color(200,200,200));
		if (nagcount < 255)
			display->SetBlending(255-nagcount);
		else if (nagcount >= 500)
			display->SetBlending(nagcount-500);
		else
			display->SetBlending(0);
		display->FillRect(display->GetWidth()-115, display->GetHeight()-10, display->GetWidth()-1, display->GetHeight()-1, Color(0,0,0));
		display->SetBlending(255);
	}
}
#endif

//////////////////////////////////////////////////////////////////////////////
//
// WinMain - Entry point
//
//////////////////////////////////////////////////////////////////////////////

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPTSTR argv, int argc)
{
	///////////////
	// CODICE RILEVAZIONE SECONDA ISTANZA (su pocketpc)
	//
#ifdef UNDER_CE

	HANDLE hMutexOneInstance = ::CreateMutex( 0, FALSE, _T(FBASIC_VERSION) );

	bool bAlreadyRunning = (GetLastError() == ERROR_ALREADY_EXISTS);

	if (bAlreadyRunning)
	{
		// If there is already an instance of this app running, give it focus and exit
		HWND hOther = ::FindWindow( _T(FBASIC_VERSION), NULL );
		// prova al contrario (O_o?)
		if (!hOther) hOther = ::FindWindow(NULL, _T(FBASIC_VERSION));

		if (hOther)
		{
			::SetForegroundWindow( hOther );

#if defined(UNDER_CE)
			if (::IsWindowEnabled( hOther ))
#else
			if (::IsIconic( hOther ))
#endif
				::ShowWindow( hOther, SW_RESTORE );
		}

		return 0;
	} // if (bAlreadyRunning)
	//
	// FINE CODICE RILEVAZIONE SECONDA ISTANZA
	///////////////
#endif


// su windows, salva nome per semaforo 
#ifndef ARM
	if (argc > 0) {
		strcpy(IDE_SEMAFORO_NAME, argv);
	} else {
		strcpy(IDE_SEMAFORO_NAME, "");
	}
#endif
	_Module.Init( 0, hInstance );
    BlitSample game;
	game.Run();
    return 0;
}
