#pragma once

#include <iostream>
#include <functional>
#include <vector>
#include <map>
#include <hash_map>
#include <string>
#include <D3DX9.h>
#include <tchar.h>

#include "tagIdents.h"

using namespace std;
using namespace stdext;

enum FloatPrecision
{
	PRECISION_32BIT,
	PRECISION_64BIT
};

enum FileType
{
	TYPE_GEOMETRY,
	TYPE_MATERIAL,
	TYPE_TEXTURE
};

enum Unit
{
	UNIT_INCHES,
	UNIT_MILLIMETERS
};

struct BIZ_IDENTTAG
{
	unsigned short identity : 12;
	unsigned short RESERVED : 1;
	unsigned short configBit : 1;
	unsigned short headerSize : 2;
};

struct HeaderInfo
{
	char verMajor;
	char verMinor;

	char dateDay;
	char dateMon;
	char dateYear;

	char timeHour;
	char timeMin;

	float scale;

	FloatPrecision precision;

	FileType type;

	Unit unit;
};

struct DivVertex
{
	char mask;
	float x,y,z;
	
	float Nx,Ny,Nz;
	
	float r,g,b;
	float l;
	float a;

	float u,v;
	float w;
};

struct ConList
{
	unsigned char sideCount;
	int numIndices;
	int *indices;
};

struct Triangle
{
	int indices[3];
};

struct SurfaceProps
{
	char *name;

	char f_material_type;
	char *f_material_name;

	char b_material_type;//Slinky has too much comments
	char *b_material_name;

	char plane;

	char drawmode;
	char drawmode_width;

	int decal_offset;

	char faceted;

	char vertex_mask;

	char *specialInst;

	char locks;

	bool isImmune;

	bool drawSpheres;
};

struct DivPatch
{
   vector<Triangle> frontTriangles;
   vector<Triangle> backTriangles;
   SurfaceProps surface;
};

struct DivObject
{
   char *objName;

   vector<DivVertex> vertices;
   vector<DivPatch*> patches;
};

struct DivMaterial
{
	char *name;

	unsigned char tex_type;
	char *tex_name;

	unsigned char env_type;
	char *env_name;

	float amb_r, amb_g, amb_b;	//Ambient
	float dif_r, dif_g, dif_b;	//Diffuse
	float spe_r, spe_g, spe_b, spe_p;	//Specular
	float emi_r, emi_g, emi_b;	//Emissive
	float opa_r, opa_g, opa_b;	//Opacity

	char *ramp_name;

	bool isImmune;
};

struct RGBA
{
	unsigned char r, g, b, a;
};

struct TexBuffer
{
	int height, width;
	RGBA **m_buffer;
};

struct DivTexture
{
	char *name;
	
	TexBuffer *texBuffer;

	unsigned char minify;
	unsigned char magnify;
	unsigned char alpha;
	unsigned char wrap_u;
	unsigned char wrap_v;

	unsigned char detail_type;
	char *detail_name;

	bool doScroll;
	float scrollU;
	float scrollV;
};

struct DivRamp
{
	float r1, g1, b1;
	float r2, g2, b2;
};

class VGCDivLoader
{
public:
	VGCDivLoader();
	~VGCDivLoader();

   static void FindObject(hyper hashValue);

	void parse(LPDIRECT3DDEVICE9 device, char *fileName);

   static hash_map< string , DivMaterial* > mMaterials;
	static hash_map< string , DivTexture* > mTextures;
	static hash_map< string , DivRamp* > mRamps;
   static hash_map< string, DivObject*> mObjects;

protected:
	HeaderInfo mHeaderInfo;

	void precacheMaterial(char *name);
	//void precacheTexture(char *name, FILE *matFile);
	TexBuffer *LoadVTXFile(char *fileName, DivTexture *tex);
	TexBuffer *LoadBSLFile(char *fileName, char channelIndex, DivTexture *tex);

	void parseHeader(FILE *file, unsigned int len);
	void parseTexture(FILE *file, unsigned int len);
	bool parseMaterial(FILE *file, unsigned int len, char *filename);
	void parseRamp(FILE *file, unsigned int len);
	void parseObject(FILE *file, unsigned int len, char *fileName);

	void parseLOD(DivObject *obj, FILE *file, unsigned int len);
	void parsePatch(DivObject *obj, FILE *file, unsigned int len);
	void parseSurface(FILE *file, BIZ_IDENTITIES ident, unsigned int len, SurfaceProps &props);

	void parsePMesh(FILE *file, unsigned int len, DivPatch *patch, DivObject *obj);
	DivVertex *parseVList(FILE *file, unsigned int len, unsigned char vertTypeMask, int &n);

	int getVertex(DivVertex vert, DivObject *obj);
	void addPolygon(int *indices, int numIndices, DivPatch *patch);

	int floatSize();

	int getBlock(FILE *file, BIZ_IDENTITIES &id, unsigned int &length);

	SurfaceProps mMasterProps;
	std::vector<DivVertex> mVertices;
};