#pragma once

#include "dllinterface.h"
#include "..\Utilities\XString.h"
#include "..\Utilities\util.h"
#include "..\Utilities\clock.h"
#include "..\Utilities\fastmath.h"

#include <d3d9.h>
#include <D3DX9Math.h>
#include <mmsystem.h>

class DeviceStateManager;
class DXSwapChain;

#ifdef SWIG
	void wlog(char *str,...);
#else
	void DXFUNCTIONS_API wlog(char *str,...);
#endif

#ifndef SWIG
	BOOL CALLBACK DDProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);

	void OnSelectAdapter(HWND hwndDlg);
	void OnSelectResolution(HWND hwndDlg);

	struct STMode
	{
		DWORD Width,Height;
		LList<UINT> RefreshRates;

		~STMode(void){RefreshRates.Clear();}
	};

	struct STAdapter
	{
		D3DADAPTER_IDENTIFIER9 AdapterInfo;
		DWORD FSAntialiasing16,WDAntialiasing16; //fullscreen and windowed
		DWORD FSAntialiasing32,WDAntialiasing32; //fullscreen and windowed
		LList<STMode> Modes16;
		LList<STMode> Modes32;

		~STAdapter(void){Modes16.Clear();Modes32.Clear();}
	};

#endif

struct DXFUNCTIONS_API STSelMode
{
	unsigned long Adapter;
	bool Windowed;
	unsigned long Width,Height;
	unsigned long RefreshRate;
	bool VSync;
	bool BB32Bit;
	unsigned long Antialiasing;

	STSelMode(void){ZeroMemory(this,sizeof(STSelMode));}
	~STSelMode(void){}

	bool Open(XString fn);
	bool Save(XString fn);
	void SetDefault(void);

	//initialize the present params from the mode
	void InitPresentParam(D3DPRESENT_PARAMETERS& pp, HWND hWnd);
};

class DXFUNCTIONS_API D3DApp
{
private:
	LPDIRECT3D9				m_pD3D;
	LPDIRECT3DDEVICE9		m_pD3DDevice;
	D3DPRESENT_PARAMETERS	m_PresentParam;

	HWND					m_hWnd;
	bool					m_bDeviceLost;
	LList<STAdapter>		m_lAdapters;	
	STSelMode				m_CurrentMode;

	void EnumAdapters(void);

protected:

	DeviceStateManager*		m_Device;
	CClock				m_Clock;

	bool				m_Run;
	bool				m_Active;
	
public:
		
	D3DApp(void);
	virtual ~D3DApp(void);

	void Render(void);
	
	void Init3D(int wnd,const STSelMode& mode, bool multithreaded);
	HRESULT Reset3D(const STSelMode& mode);
	virtual void RenderScene(void){}
	virtual void UpdateScene(void){}
	virtual void Restore(void){}
	virtual void Invalidate(void){}
	virtual void OnCreateDevice(void){}

	HRESULT Run(void);

	bool SelectDeviceSettings(HWND hwnd,bool allowfullscreen,STSelMode*selmode);

	STSelMode GetCurrentMode(void){return m_CurrentMode;}
	bool DeviceLost(void){return m_bDeviceLost;}

	DeviceStateManager* GetDevice(void) const {return m_Device;}

	void Exit(void) { m_Run = false;}

	CClock& GetClock(void) {return m_Clock;}
};
