#pragma once

#include "GameObject3D.h"
#include "Sprite.h"
#include "GameWindow.h"
#include "InputData.h"
#include "Model.h"
//#include "Global.h"
#include "vertex_types.h"

#include <assimp.h>
#include <aiScene.h>        // root structure of the imported data
#include <aiMesh.h>
#include <DefaultLogger.h>

#include "Camera.h"
#include "AssimpRenderer.h"
#include "RenderOptions.h"

#include "PnxUtility.h"

class MyLogStream;

//#pragma comment (lib, "dxerr9.lib")             // brauch man für getErrorString

class DxWrapper
{

public:    

	// Singleton
	static DxWrapper* Instance(void);
	static bool LoadModel(Model* model, LPCTSTR file, LPCTSTR path);

    GAMEWINDOW m_GameWindow;
	AssimpRendererD3d::Camera m_Camera;
	AssimpRendererD3d::AssimpRenderer* assimpRenderer;

	//time calculation
	DWORD timeStampAtStart;

    // matrices
    D3DXMATRIX matView;          // the view (look at) matrix containing camera position and view direction
    D3DXMATRIX matProjection;    // the projection transform matrix
    D3DXMATRIX matWorldTransform;         // rotation and translation of the current Object in world space

    // Direct 3D
    LPDIRECT3D9 d3d;
    LPDIRECT3DDEVICE9 d3ddev;
    D3DPRESENT_PARAMETERS d3dpp;
    LPD3DXSPRITE d3dspt;
    LPDIRECT3DSURFACE9 z_buffer;    // the pointer to the z-buffer
    
    LPD3DXFONT dxfont;              // the pointer to the font object
 
    // DirectInput
    LPDIRECTINPUT8 din;
    LPDIRECTINPUTDEVICE8 dinkeyboard;
    LPDIRECTINPUTDEVICE8 dinmouse; 
       
    TCHAR* applicationBaseDirectory;       // das Verzeichnis, in dem die Applikation gestartet wurde

    aiMatrix4x4 g_mWorld;
    aiMatrix4x4 g_mWorldRotate;   
    // 
    void InitDirect3D(GAMEWINDOW* gw);
    void InitDirect3DSprite();
    void InitFont(int size);
    void InitLight();
    void RenderText(wchar_t* text, int posX , int posY);
    void RenderText(const std::string &text, int posX , int posY);
    void CloseDirect3D();
    void ClearScreen();
    bool BeginScene();
    void EndScene();
    void StartRender2D();
    void EndRender2D();
    void DisplayFrame();
    void RenderObject(GameObject3D *obj);
    void LoadSprite(SPRITE* pSprite, LPCTSTR File, LPCTSTR Path, int width, int height, int cols, int rows);
    void RenderBoundingBox(const IvOBB& obb);
    void RenderLine(const CPos& pointA, const CPos& pointB);
    void RenderLine(const IvVector3 pointA, const IvVector3 pointB, int r=0, int g=0, int b=0);
    bool RenderVertexListAsLines(SVertex*, int numVerts);
    void RenderSprite(const SPRITE* pSprite, int Frame, float x, float y, float z);
	void SetCamera(const AssimpRendererD3d::Camera& sourceCamera);
    void SetProjection(int fieldOfViewDegrees);
    void SetWorldTransform(float posX, float posY, float posZ, float rotX, float rotY, float rotZ);
    void SetWorldTransform(const GameObject3D& obj);
    void SetLight(D3DLIGHT9& light, int lightIndex);

    void ResetDevice(void);

    // DirectInput.cpp
    void InitDirectInput(HINSTANCE hInstance, GAMEWINDOW* gw);
    void GetKeys(BYTE* KeyState);
    void GetMouse(DIMOUSESTATE* MouseState);
    void CloseDirectInput(void);

    // Input.cpp
    void Input(INPUTDATA* InputData, HWND hWnd);

    // Debugging Logger
    bool m_showLog;
    int m_logFontSize;
    std::vector<std::string> vecLog;
    void LogWrite(std::string str, boolean addTimeStamp = true);
    void LogClear();

	DWORD GetTimestampSinceStart();
    static std::string GetCurrentDir();

    // other flags
    bool m_DrawBoundingBoxes;

private:
    static DxWrapper* mInstance;
	MyLogStream* myLogStream;
    DxWrapper();
    ~DxWrapper();

};
