/* ================================================================
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL DINGOO GAMES OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ====================================================================
 */ 

///////////////////////////////////////////////////////////////////////////////
// Wonderswan emulator
////////////////////////////////////////////////////////////////////////////////
//
// 13.04.2002: Fixed a small bug causing crashes
//
//
//
//
//////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <string.h>
#include <windows.h>

#include <io.h>
#include <fcntl.h>

#include "../inc/GameEngine.h"

int16 *backbuffer=(int16*)malloc(224*144*sizeof(int16));
int16 *linesbuffer=(int16*)malloc(224*144*sizeof(int16));

//--------------------------------------------------------------------------------------------------------
GameEngine::GameEngine( void* userdata [] ) : 
					Engine( userdata )
{
	m_pAudioData = NULL;
 
	A320_SCREEN_WIDTH = 224;
	A320_SCREEN_HEIGHT = 144;

	app_gameRunning=0;
	app_terminate=0;
	app_fullscreen=0;

	app_rotated=0;

	ws_videoEnhancementType=0;
	ws_colourScheme=COLOUR_SCHEME_DEFAULT;
	ws_system=WS_SYSTEM_AUTODETECT;
	
	//ws_rom_path = "F:\\EMUGAMES\\WONDERSWAN COLOR\\Roms\\0033 - Final Fantasy II (JP).wsc";
	ws_rom_path = "F:\\EMUGAMES\\WONDERSWAN COLOR\\Roms\\0171 - Hunter X Hunter - Greed Island (JP).wsc";
}
//--------------------------------------------------------------------------------------------------------
GameEngine::~GameEngine( void )
{
	Free();
}
//--------------------------------------------------------------------------------------------------------
/// init all resources
result	GameEngine::Init( void )
{
	InitDLRes();
	// 16 FPS
	SetFPS( 24 );

	ws_colourScheme = 0;

	if (ws_rom_path)
	{
		if (ws_init(ws_rom_path))
		{
			m_pAudioData = new AudioData[15];

			app_rotated=ws_rotated();
			app_gameRunning=1;
			ws_set_system(ws_system);
			ws_set_colour_scheme(ws_colourScheme);
			ws_reset();

			nNormalLast=0;
			nNormalFrac=0; 
			nTime=0;
			nCount=0;

			memset(backbuffer,0x00,224*144*sizeof(int16));

			totalFrames=0;
			startTime=clock();
			nNormalLast=0; // Last value of timeGetTime()
			nNormalFrac=0; // Extra fraction we did
			nNormalLast=timeGetTime();
		}
	}

	return S2D_OK;
}
//--------------------------------------------------------------------------------------------------------
/// free all resources
void	GameEngine::Free( void )
{
	ReleaseDLRes();
	SAFE_DELETE_ARRAY( m_pAudioData );
}
//--------------------------------------------------------------------------------------------------------
/// game logic before render
void	GameEngine::Exec( void )
{

}
//--------------------------------------------------------------------------------------------------------
/// game logic after render
void	GameEngine::Exec2( void )
{

}
//--------------------------------------------------------------------------------------------------------
/// pre-render proccess
void	GameEngine::PreRender( void )
{

}
//--------------------------------------------------------------------------------------------------------
/// render
void	GameEngine::Render( void )
{
	ws_emulate_standard(); 

	static int16	temp[224*144];
	memcpy(temp,linesbuffer,224*144*2);

	for (int line=0;line<144;line++)
		for (int column=0;column<224;column++)
			PutPixel(line,column,temp[column+(line<<7)+(line<<6)+(line<<5)]);
}
//--------------------------------------------------------------------------------------------------------
void	GameEngine::PostRender( void )
{
}

//--------------------------------------------------------------------------------------------------------
void	GameEngine::DispDebugInfo( void )
{
}

//--------------------------------------------------------------------------------------------------------
void	GameEngine::EnterGame( s32 MapId )
{ 

}
//--------------------------------------------------------------------------------------------------------
void	GameEngine::PlayMusic(u32 ID,bool bRep)
{
	if(!m_bUseAudio){
		return;
	}
	if(ID>=m_AudioCnt){
		return;
	}
	m_pAudioPlayer->Play(&m_pAudioData[ID],0,m_pAudioData[ID].GetLength(),255,bRep);
}

//--------------------------------------------------------------------------------------------------------
void	GameEngine::StopMusic()
{
	m_pAudioPlayer->Stop(0);
}

//--------------------------------------------------------------------------------------------------------
void	GameEngine::PlaySound(u32 ID)
{
	if(!m_bUseAudio){
		return;
	}
	if(ID>=m_AudioCnt){
		return;
	}
	for(s32 i=1;i<AudioPlayer::MaxChannels;i++){
		if(m_pAudioPlayer->GetState(i) != AUDIO_PLAYING){
			m_pAudioPlayer->Play(&m_pAudioData[ID],i,m_pAudioData[ID].GetLength(),255,false);
			return;
		}
	}
}	


//--------------------------------------------------------------------------------------------------------
void	GameEngine::StopAllSound()
{
	m_bUseAudio = false;
	m_pAudioPlayer->StopAll();
}
//--------------------------------------------------------------------------------------------------------
void	GameEngine::ExitGame( void )
{
	Exit();
}

//--------------------------------------------------------------------------------------------------------
void	GameEngine::LoadCfg(void)
{
	// get full filename with path
	Char fullname[256];
	s2d::strcpy( fullname, _LS(".\\lltconfig.sdt") );

	s2d::FILE* m_fp = s2d::fopen( fullname, _LS("rb") );

	if(m_fp == NULL){
		return;
	}

	// read file to memory
	fseek( m_fp, 0, SEEK_END );
	s32 size =  ftell(m_fp);

	s32* mem = (s32*)  malloc( size );
	s32* pstar = mem;

	fseek(m_fp, 0, SEEK_SET );
	fread( mem, size,m_fp );
	fclose(m_fp);

	s32 Scene = *(s32*)mem;

	free( pstar );
}
//--------------------------------------------------------------------------------------------------------
void	GameEngine::SaveCfg(void)
{
	// get full filename with path
	Char fullname[256];
	s2d::strcpy( fullname, _LS(".\\lltconfig.sdt") );

	s2d::FILE* m_fp = s2d::fopen( fullname, _LS("wb+") );

	if(m_fp == NULL){
		return;
	}

	s32 Scene=5;
	fwrite(&Scene, sizeof(s32),m_fp );

	// close file
	fclose(m_fp);
}

//--------------------------------------------------------------------------------------------------------
void	GameEngine::PutPixel(int x, int y, int32 color)
{
	Pixel* ptr = m_pDraw2D->GetVRAMPtr();

	int r,g,b,a;

	WORD red_mask = 0x7C00;
	WORD green_mask = 0x3E0;
	WORD blue_mask = 0x1F;

	r = (color & red_mask) >> 10;
	g = (color & green_mask) >> 5;
	b = (color & blue_mask);

	// Expand to 8-bit values:
	BYTE red   = r << 3;
	BYTE green = g << 3;
	BYTE blue  = b << 3;

	Pixel color1(red,green,blue);
	s32 ofs = (x*A320_SCREEN_WIDTH) + (y);

	ptr[ofs] = color1;
}

//--------------------------------------------------------------------------------------------------------
void	GameEngine::ws_rotate_backbuffer(int16 *backbuffer)
{
}

//--------------------------------------------------------------------------------------------------------
void	GameEngine::ws_emulate_standard(void)
{
	nTime=timeGetTime()-nNormalLast;					  // calcule le temps écoulé depuis le dernier affichage
	// nTime est en mili-secondes.
	// détermine le nombre de trames à passer + 1
	nCount=(nTime*600 - nNormalFrac) /10000; 	

	// si le nombre de trames à passer + 1 est nul ou négatif,
	// ne rien faire pendant 2 ms
	if (nCount<=0) 
	{ 
		Sleep(2); 
	} // No need to do anything for a bit
	else
	{
		nNormalFrac+=nCount*10000;				// 
		nNormalLast+=nNormalFrac/600;				// add the duration of nNormalFrac frames
		nNormalFrac%=600;							// 

		// Pas plus de 9 (10-1) trames non affichées 
		if (nCount>10) 
			nCount=10; 

		int ws_key_esc=0;

		ws_key_esc=0;
		ws_key_start=0;
		ws_key_left=0;
		ws_key_right=0;
		ws_key_up=0;
		ws_key_down=0;
		ws_key_button_1=0;
		ws_key_button_2=0;

		if( m_pInput->IsKeyClick(KEY_R1) ){
			ws_key_esc = 1;
		}
		if( m_pInput->IsKeyClick(KEY_UP) ){
			ws_key_up = 1;
		}
		if( m_pInput->IsKeyClick(KEY_DN) ){
			ws_key_down = 1;
		}
		if( m_pInput->IsKeyClick(KEY_RT) ){
			ws_key_right = 1;
		}
		if( m_pInput->IsKeyClick(KEY_LF) ){
			ws_key_left = 1;
		}
		if( m_pInput->IsKeyClick(KEY_OK) ){
			ws_key_start = 1;
		}

		if( m_pInput->IsKeyClick(KEY_0) ){
			ws_key_button_1 = 1;
		}
		if( m_pInput->IsKeyClick(KEY_1) ){
			ws_key_button_2 = 1;
		}
		if( m_pInput->IsKeyClick(KEY_2) ){
			ws_cyclesByLine+=10;
		}
		if( m_pInput->IsKeyClick(KEY_3) ){
			ws_cyclesByLine-=10;
		}

		if (ws_key_esc)
		{
			//regresamos al menu main
		}

		for (i=0;i<nCount-1;i++) 
			while (!ws_executeLine(backbuffer,0));

		while (!ws_executeLine(backbuffer,1));
			totalFrames++;

		memcpy(linesbuffer,backbuffer,224*144*sizeof(int16));
	}
}




//--------------------------------------------------------------------------------------------------------
Input*	GameEngine::GetInput( void )
{ 
	return m_pInput;
}