/*****************************************************************************\

  Copyright (C) 2013, Solarix <solarix.one1 at gmail dot com>

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software subject to the 
  terms and conditions stated in Car Spawner - License.txt, and the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation is required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

\*****************************************************************************/
#include "SpeedoRender.h"
#include "SpeedoThread.h"
#include "Scripting.h"
#include "../ScriptHook/ScriptHookManager.h"
#include "resource.h"
#include "windows.h"
#include "ObjectList.h"
#include <AntTweakBar.h>
#include <assert.h>

using namespace Scripting;

#define SafeRelease( x ) if ((x) != NULL) { (x)->Release(); (x) = NULL; }

i32 width,height;
BOOL windowed;
HWND window;
TwBar *CarSpawnerBar;
TwBar *carBar1;
TwBar *carBar2;
POINT cursorPos;
RECT rcClip;
RECT rcWnd;
i32 wheelkeycount = 0;
i32 wheelmousecount = 0;
extern b8 D3DHookHaveRendered;
extern b8 NotInGame;
extern b8 bDeleteAllSpawnedCars;
extern b8 bDeleteLastSpawnedCar;
extern b8 Control;
extern u32 NumberOfVehicles;
extern eModel CarToSpawn;
extern b8 bSpawnCar;
extern u32 SpawnType;
extern b8 DisableMod;
extern b8 CarGodMode;
extern b8 SimpleCarGodMode;
extern b8 FrozenCars;
extern b8 bFixCars;
extern b8 bFlipCars;
extern b8 bFreezeCars;
extern b8 bUnfreezeCars;
extern b8 bAddGodMode;
extern b8 bAddSimpleGodMode;
extern b8 bRemoveGodMode;
extern b8 bTeleportCars;
extern b8 bNewColors;
extern b8 WaypointSpawning;
extern b8 Color;
extern u32 color1,color2,extra1,extra2;
extern b8 bLockUnlockAllCarDoors;
extern b8 bAddBlips;
extern b8 bDestroyEngines;

void TW_CALL BreakOnError(const char *errorMessage)
{ 
    assert(errorMessage==NULL); // show an assert message if an error occurred
}

void TW_CALL fSpawnCar(void *clientData)
{ 
	bSpawnCar = true;
	CarToSpawn = *(eModel*)clientData;
}

void TW_CALL fFixCars(void *clientData)
{ 
	bFixCars = true;
}

void TW_CALL fFlipCars(void *clientData)
{ 
	bFlipCars = true;
}

void TW_CALL fFreezeCars(void *clientData)
{ 
	bFreezeCars = true;
}

void TW_CALL fUnfreezeCars(void *clientData)
{ 
	bUnfreezeCars = true;
}

void TW_CALL fAddGodMode(void *clientData)
{ 
	bAddGodMode = true;
}

void TW_CALL fAddSimpleGodMode(void *clientData)
{ 
	bAddSimpleGodMode = true;
}

void TW_CALL fRemoveGodMode(void *clientData)
{ 
	bRemoveGodMode = true;
}

void TW_CALL fDeleteAllSpawnedCars(void *clientData)
{ 
	bDeleteAllSpawnedCars = true;
}

void TW_CALL fDeleteLastSpawnedCar(void *clientData)
{ 
	bDeleteLastSpawnedCar = true;
}

void TW_CALL fTeleportCars(void *clientData)
{ 
	bTeleportCars = true;
}

void TW_CALL fNewColors(void *clientData)
{ 
	bNewColors = true;
}

void TW_CALL fLockUnlockAllCarDoors(void *clientData)
{ 
	bLockUnlockAllCarDoors = true;
}

void TW_CALL fAddBlips(void *clientData)
{ 
	bAddBlips = true;
}

void TW_CALL fDestroyEngines(void *clientData)
{ 
	bDestroyEngines = true;
}

void TW_CALL fDisableMod(void *clientData)
{ 
	DisableMod = true;
} 

SpeedoRender::SpeedoRender()
{
	m_pSprite = NULL;
	m_pCursorTexture = NULL;
	m_bMenuVisible = false;
	bHaveSetTheCursorToMenu = false;
	m_nCursorColour = 0x00FFFFFF;
}

void SpeedoRender::InstallHook()
{
    ID3DHookService *pService = ScriptHookManager::RequestService<ID3DHookService>( "D3DHook" );
    pService->AddDeviceHook( this );
}

void SpeedoRender::RemoveHook()
{
    ID3DHookService *pService = ScriptHookManager::RequestService<ID3DHookService>( "D3DHook" );
    pService->RemoveDeviceHook( this );
}

Player SpeedoRender::GetPlayer()
{
	Player playerIndex = ConvertIntToPlayerIndex(GetPlayerId());
	return playerIndex;
}

Ped SpeedoRender::GetPlayerPed()
{
	Ped ped;
	GetPlayerChar(GetPlayer(), &ped);
	return ped;
}

void SpeedoRender::OnResetDevice( ID3DDevice *pDevice, PresentParameters *pPresentParameters )
{
	ch bLabel[512];
	u32 episode = GetCurrentEpisode();
	TwInit(TW_DIRECT3D9, pDevice);
	TwHandleErrors(BreakOnError);
	windowed = pPresentParameters->Windowed;
    TwWindowSize(pPresentParameters->BackBufferWidth, pPresentParameters->BackBufferHeight);
	if (windowed)
	{
		width = GetSystemMetrics(SM_CXSCREEN);
		height = GetSystemMetrics(SM_CYSCREEN);
		window = pPresentParameters->hDeviceWindow;
	}
	else
	{
		width = pPresentParameters->BackBufferWidth;
		height = pPresentParameters->BackBufferHeight;
	}
	
	ch tempstr[512];
	sprintf_s(tempstr, 512, " CarSpwn label='Car Spawner 1.25' position='%i %i' text=light size='%i %i' valueswidth=60 resizable=true ", width-855, 12, 350, height-500);
	CarSpawnerBar = TwNewBar("CarSpwn");
	TwDefine("CarSpwn color='110 160 0' alpha=128");
	TwDefine(" TW_HELP visible=false ");
	TwDefine(" GLOBAL iconalign=horizontal ");
	TwDefine(" GLOBAL iconmargin='16 16' ");
	TwDefine(tempstr);

	TwAddButton(CarSpawnerBar, "Option1",NULL,NULL,"label='Car options:'");
	TwAddVarRW(CarSpawnerBar, "Car god mode", TW_TYPE_BOOLCPP, &CarGodMode, " true=Enabled false=Disabled ");
	TwAddVarRW(CarSpawnerBar, "Simple car god mode (with visual damage)", TW_TYPE_BOOLCPP, &SimpleCarGodMode, " true=Enabled false=Disabled ");
	TwAddVarRW(CarSpawnerBar, "Frozen car", TW_TYPE_BOOLCPP, &FrozenCars, " true=Enabled false=Disabled ");
	TwAddVarRW(CarSpawnerBar, "Set custom colors", TW_TYPE_BOOLCPP, &Color, " true=Enabled false=Disabled ");
	TwAddVarRW(CarSpawnerBar, "Waypoint spawning", TW_TYPE_BOOLCPP, &WaypointSpawning, " true=Enabled false=Disabled ");
	TwAddSeparator(CarSpawnerBar,NULL,NULL);
	TwAddVarRW(CarSpawnerBar, "How much vehicles?", TW_TYPE_UINT32, &NumberOfVehicles, " min=1 max=32 ");
	TwAddVarRW(CarSpawnerBar, "Spawning mode", TW_TYPE_UINT32, &SpawnType, " min=1 max=4");
	TwAddVarRO(CarSpawnerBar, "Number of spawned vehicles", TW_TYPE_UINT32, &m_MenuNrSpawnedCars, NULL);
	TwAddVarRO(CarSpawnerBar, "Number of players", TW_TYPE_UINT32, &m_MenuNrPlayers, NULL);
	TwAddSeparator(CarSpawnerBar,NULL,NULL);
	TwAddButton(CarSpawnerBar, "Option2",NULL,NULL,"label='Actions on spawned cars:'");
	TwAddButton(CarSpawnerBar, "Fix all spawned vehicles", fFixCars, &bFixCars, NULL);
	TwAddButton(CarSpawnerBar, "Flip all spawned vehicles", fFlipCars, &bFlipCars, NULL);
	TwAddButton(CarSpawnerBar, "Add blips", fAddBlips, &bAddBlips, NULL);
	TwAddButton(CarSpawnerBar, "Destroy engines", fDestroyEngines, &bDestroyEngines, NULL);
	TwAddButton(CarSpawnerBar, "Lock/lock both sides/unlock all spawned vehicles", fLockUnlockAllCarDoors, &bLockUnlockAllCarDoors, NULL);
	TwAddButton(CarSpawnerBar, "Set new colors", fNewColors, &bNewColors, NULL);
	TwAddButton(CarSpawnerBar, "Teleport all spawned vehicles to waypoint/me", fTeleportCars, &bTeleportCars, NULL);
	TwAddButton(CarSpawnerBar, "Add god mode on all spawned vehicles", fAddGodMode, &bAddGodMode, NULL);
	TwAddButton(CarSpawnerBar, "Add simple god mode on all spawned vehicles", fAddSimpleGodMode, &bAddSimpleGodMode, NULL);
	TwAddButton(CarSpawnerBar, "Remove god mode on all spawned vehicles", fRemoveGodMode, &bRemoveGodMode, NULL);
	TwAddButton(CarSpawnerBar, "Freeze all spawned vehicles", fFreezeCars, &bFreezeCars, NULL);
	TwAddButton(CarSpawnerBar, "Unfreeze all spawned vehicles", fUnfreezeCars, &bUnfreezeCars, NULL);
	TwAddButton(CarSpawnerBar, "Delete last spawned vehicle", fDeleteLastSpawnedCar, &bDeleteLastSpawnedCar, NULL);
	TwAddButton(CarSpawnerBar, "Delete all spawned vehicles", fDeleteAllSpawnedCars, &bDeleteAllSpawnedCars, NULL);
	TwAddSeparator(CarSpawnerBar,NULL,NULL);
	TwAddVarRW(CarSpawnerBar, "Control player when menu is active", TW_TYPE_BOOLCPP, &Control, NULL);
	TwAddButton(CarSpawnerBar, "Turn off Car Spawner", fDisableMod, &DisableMod, NULL);
	TwAddSeparator(CarSpawnerBar,NULL,NULL);

	carBar1 = TwNewBar("CarBar1");
	sprintf_s(tempstr, 512, " CarBar1 label='Choose vehicle to spawn' position='%i %i' text=light size='%i %i' ", width-495, 12, 220, height-62);	
	TwDefine("CarBar1 color='10 92 245' alpha=128");
	TwDefine(tempstr);

    for (i32 o = 0; o < 85; o++) 
	{
        sprintf_s(bLabel, 512, " label='%s' group='Spawn Cars' ", CarList[o].name);
        TwAddButton(carBar1, CarList[o].name, fSpawnCar, (void*)&CarList[o].model,bLabel);
    }

	carBar2 = TwNewBar("CarBar2");
	sprintf_s(tempstr, 512, " CarBar2 label='Choose vehicle to spawn' position='%i %i' text=light size='%i %i' ", width-275, 12, 220, height-62);	
	TwDefine("CarBar2 color='10 92 245' alpha=128");
	TwDefine(tempstr);

	for (i32 o = 86; o < 108; o++) 
	{
        sprintf_s(bLabel, 512, " label='%s' group='Spawn Cars' ", CarList[o].name);
        TwAddButton(carBar2, CarList[o].name, fSpawnCar, (void*)&CarList[o].model,bLabel);
    }

	if (episode == 2) 
	{
		for (i32 o = 108; o < 126; o++) 
		{
			sprintf_s(bLabel, 512, " label='%s' group='Spawn Cars' ", CarList[o].name);
			TwAddButton(carBar2, CarList[o].name, fSpawnCar, (void*)&CarList[o].model,bLabel);
		}
	}

	if (episode == 1) 
	{
		for (i32 o = 126; o < 133; o++) 
		{
			sprintf_s(bLabel, 512, " label='%s' group='Spawn Cars' ", CarList[o].name);
			TwAddButton(carBar2, CarList[o].name, fSpawnCar, (void*)&CarList[o].model,bLabel);
        }
	}

	for (i32 o = 0; o < 7; o++) 
	{
        sprintf_s(bLabel, 512, " label='%s' group='Spawn Bikes' ", BikeList[o].name);
        TwAddButton(carBar2, BikeList[o].name, fSpawnCar, (void*)&BikeList[o].model,bLabel);
    }

	if (episode == 2) 
	{
		for (i32 o = 7; o < 14; o++) 
		{
			sprintf_s(bLabel, 512, " label='%s' group='Spawn Bikes' ", BikeList[o].name);
			TwAddButton(carBar2, BikeList[o].name, fSpawnCar, (void*)&BikeList[o].model,bLabel);
		}
	}

	if (episode == 1) 
	{
		for (i32 o = 14; o < 20; o++) 
		{
			sprintf_s(bLabel, 512, " label='%s' group='Spawn Bikes' ", BikeList[o].name);
			TwAddButton(carBar2, BikeList[o].name, fSpawnCar, (void*)&BikeList[o].model,bLabel);
		}
	}

    for (i32 o = 0; o < 8; o++) 
	{
		sprintf_s(bLabel, 512, " label='%s' group='Spawn Boats' ", BoatList[o].name);
		TwAddButton(carBar2, BoatList[o].name, fSpawnCar, (void*)&BoatList[o].model,bLabel);
	}

	if (episode == 2) 
	{
		for (i32 o = 8; o < 11; o++) 
		{
			sprintf_s(bLabel, 512, " label='%s' group='Spawn Boats' ", BoatList[o].name);
			TwAddButton(carBar2, BoatList[o].name, fSpawnCar, (void*)&BoatList[o].model,bLabel);
		}
	}

    for (i32 o = 0; o < 4; o++) 
	{
		sprintf_s(bLabel, 512, " label='%s' group='Spawn Helicopters' ", HelicopterList[o].name);
		TwAddButton(carBar2, HelicopterList[o].name, fSpawnCar, (void*)&HelicopterList[o].model,bLabel);
	}

	if (episode == 2) 
	{
		for (i32 o = 4; o < 7; o++) 
		{
			sprintf_s(bLabel, 512, " label='%s' group='Spawn Helicopters' ", HelicopterList[o].name);
			TwAddButton(carBar2, HelicopterList[o].name, fSpawnCar, (void*)&HelicopterList[o].model,bLabel);
        }
	}

	if (m_pCursorTexture == NULL)
		D3DXCreateTextureFromResourceEx(pDevice, m_hModule, MAKEINTRESOURCE(IDB_NEEDLE), 128, 128, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &m_pCursorTexture);

	if (m_pSprite == NULL)
        D3DXCreateSprite(pDevice, &m_pSprite);
}

void SpeedoRender::OnLostDevice( ID3DDevice *pDevice )
{
	SafeRelease(m_pSprite);
	SafeRelease(m_pCursorTexture);
	TwDeleteAllBars();
	TwWindowSize(0,0);
	TwTerminate();
}

b8 KeyPressed(int key)
{
	return (GetKeyState(key) & 0x80000000) != 0;
}

void SpeedoRender::OnRender( ID3DDevice *pDevice )
{
    D3DXMATRIX speedoMatrix;
	D3DHookHaveRendered = true;
    u32 episode = GetCurrentEpisode();

    if (NotInGame)
        return;
	
	if (IsPauseMenuActive() || IsScreenFadingOut() || IsScreenFadedOut() || !IsPlayerPlaying(ConvertIntToPlayerIndex(GetPlayerId()))|| IsInPlayerSettingsMenu() || IsScreenFadingIn() || IsFrontEndFading())
		return;

	if (m_bMenuVisible && (m_nCursorColour & 0xFF000000) != 0xFF000000)
	{
		m_nCursorColour += 0x05000000;
		if (!bHaveSetTheCursorToMenu) 
		{
			i32 barpos[2];
			TwGetParam(CarSpawnerBar, NULL, "position", TW_PARAM_INT32, 2, barpos);			
			SetCursorPos(barpos[0], barpos[1]);
			bHaveSetTheCursorToMenu = true;
		}
	}

	if ((!m_bMenuVisible) && ((m_nCursorColour & 0xFF000000) != 0)) 
	{
        m_nCursorColour -= 0x05000000;
		bHaveSetTheCursorToMenu = false;
    }
	
	if (m_bMenuVisible) 
	{
		if((episode == 1)||(episode == 2)) 
		{
			GetCursorPos(&cursorPos);
			HWND gtawnd = FindWindow(NULL, L"EFLC");
			ScreenToClient(gtawnd, &cursorPos);
			TwMouseMotion(cursorPos.x, cursorPos.y);
			GetWindowRect(gtawnd, &rcClip);
		}
		else
		{
			GetCursorPos(&cursorPos);
			HWND gtawnd = FindWindow(NULL, L"GTAIV");
			ScreenToClient(gtawnd, &cursorPos);
			TwMouseMotion(cursorPos.x, cursorPos.y);
			GetWindowRect(gtawnd, &rcClip);
		}

		i32 Wheel=0;
		GetMouseWheel(&Wheel);
		if(Wheel<0)
		{
			wheelmousecount+=3;
			TwMouseWheel(wheelmousecount);
		}
		else if(Wheel>0)
		{
			wheelmousecount-=3;
			TwMouseWheel(wheelmousecount);
		}

		if(KeyPressed(VK_UP))
		{
			++wheelkeycount;
			TwMouseWheel(wheelkeycount);
		}
		else if (KeyPressed(VK_DOWN))
		{
			--wheelkeycount;
			TwMouseWheel(wheelkeycount);
		}

		if (IsMouseButtonPressed(1)) 
		{
			if (IsMouseButtonJustPressed(1)) 
				TwMouseButton(TW_MOUSE_PRESSED, TW_MOUSE_LEFT);
		} 
		else if (IsMouseButtonPressed(2)) 
		{
			if (IsMouseButtonJustPressed(2)) 
				TwMouseButton(TW_MOUSE_PRESSED, TW_MOUSE_RIGHT);
		} 
		else 
		{
			TwMouseButton(TW_MOUSE_RELEASED, TW_MOUSE_LEFT);
			TwMouseButton(TW_MOUSE_RELEASED, TW_MOUSE_RIGHT);			
		}
		
		if(Color)
		{
			if(episode == 2)
			{
				TwAddButton(CarSpawnerBar, "Option3",NULL,NULL,"label='Custom colors:'");
				TwAddVarRW(CarSpawnerBar, "CarColor1", TW_TYPE_UINT32, &color1, " min=0 max=136 label ='Car color 1' ");
				TwAddVarRW(CarSpawnerBar, "CarColor2", TW_TYPE_UINT32, &color2, " min=0 max=136 label ='Car color 2' ");
				TwAddVarRW(CarSpawnerBar, "ExtraColor1", TW_TYPE_UINT32, &extra1, " min=0 max=136 label ='Extra car color 1' ");
				TwAddVarRW(CarSpawnerBar, "ExtraColor2", TW_TYPE_UINT32, &extra2, " min=0 max=136 label ='Extra car color 2' ");
			}
			else
			{
				TwAddButton(CarSpawnerBar, "Option3",NULL,NULL,"label='Custom colors:'");
				TwAddVarRW(CarSpawnerBar, "CarColor1", TW_TYPE_UINT32, &color1, " min=0 max=133 label ='Car color 1' ");
				TwAddVarRW(CarSpawnerBar, "CarColor2", TW_TYPE_UINT32, &color2, " min=0 max=133 label ='Car color 2' ");
				TwAddVarRW(CarSpawnerBar, "ExtraColor1", TW_TYPE_UINT32, &extra1, " min=0 max=133 label ='Extra car color 1' ");
				TwAddVarRW(CarSpawnerBar, "ExtraColor2", TW_TYPE_UINT32, &extra2, " min=0 max=133 label ='Extra car color 2' ");
			}
		}
		else
		{
			TwRemoveVar(CarSpawnerBar, "CarColor1");
			TwRemoveVar(CarSpawnerBar, "CarColor2");
			TwRemoveVar(CarSpawnerBar, "ExtraColor1");
			TwRemoveVar(CarSpawnerBar, "ExtraColor2");
		}

		TwDraw();
		D3DXMatrixIdentity(&speedoMatrix);
		m_CursorPosition = D3DXVECTOR3((f32)cursorPos.x-83, (f32)cursorPos.y-70, 0);
		m_pSprite->Begin(D3DXSPRITE_ALPHABLEND);	
		m_pSprite->SetTransform(&speedoMatrix);
		m_pSprite->Draw(m_pCursorTexture, NULL, NULL, &m_CursorPosition, m_nCursorColour);	
		m_pSprite->End();
		ClipCursor(&rcClip);
	}
}