#include <stdio.h>
#include <windows.h>
#include "DOGExport.h"
#include "deActor.hpp"
#include "msLib.h"

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
	lpReserved;
	hModule;
    switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH:
		case DLL_THREAD_ATTACH:
		case DLL_THREAD_DETACH:
		case DLL_PROCESS_DETACH:
			break;
    }
    return TRUE;
}

cMsPlugIn *CreatePlugIn()
{
	return new cPlugIn();
}

cPlugIn::cPlugIn()
{
	strcpy(szTitle, "Destiny 3D DOG...");
}

cPlugIn::~cPlugIn()
{
}

int cPlugIn::GetType()
{
	return cMsPlugIn::eTypeExport;
}

const char *cPlugIn::GetTitle()
{
	return szTitle;
}

int cPlugIn::Execute(msModel *pModel)
{
	FILE					*stream = NULL;
	DOGFileHeader			header;
	OPENFILENAME			ofn;
	char					szFile[MS_MAX_PATH];
	char					szFileTitle[MS_MAX_PATH];
	char					szDefaultExt[32] = "dog";
	char					szFilter[128] = "DOG Files (*.dog)\0*.dog\0\0";
	msMesh					*pMesh = NULL;
	int						i, j;

	//Check the validity of the model
	if (!pModel)
		return -1;

	//Make sure there is at least one mesh
	if (msModel_GetMeshCount(pModel) == 0)
	{
		MessageBox(NULL, "At least one mesh is required to export to the Destiny Object Geometry format!!", "Destiny DOG Exporter...", 48);
		return 0;
	}

	//Clear the memory for the file header
	memset(&header, 0, sizeof(DOGFileHeader));

	//Clear the memory for the OPENFILENAME struct
	memset(&ofn, 0, sizeof(OPENFILENAME));

	//Set the szFile and szFileTitle strings to NULL
	szFile[0] = '\0';
	szFileTitle[0] = '\0';

	//Fill in the OPENFILENAME struct
	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.lpstrDefExt = szDefaultExt;
	ofn.lpstrFilter = szFilter;
	ofn.lpstrFile = szFile;
	ofn.nMaxFile = MS_MAX_PATH;
	ofn.lpstrFileTitle = szFileTitle;
	ofn.nMaxFileTitle = MS_MAX_PATH;
	ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
	ofn.lpstrTitle = "Export Destiny Object Geometry...";

	if (!GetSaveFileName(&ofn))
	{
		MessageBox(NULL, "Critical error.  Cannot continue!!", "Destiny DOG Exporter...", 48);
		return 0;
	}

	//Create the file
	stream = fopen(szFile, "wb");
	if (!stream)
	{
		MessageBox(NULL, "Could not create the file!!", "Destiny DOG Exporter...", 48);
		return 0;
	}

	strcpy(header.Identifier, "DACTOR");
	header.version = 1;

	header.NumBones = 0;
	header.NumFaces = 0;
	header.NumTextures = 0;
	header.NumVerts = 0;

	header.NumBones = msModel_GetBoneCount(pModel);
	header.NumTextures = msModel_GetMaterialCount(pModel);

	//Calculate the number of vertices
	for (i = 0; i < msModel_GetMeshCount(pModel); i++)
	{
		pMesh = msModel_GetMeshAt(pModel, i);
		header.NumVerts += msMesh_GetVertexCount(pMesh);
		header.NumFaces += msMesh_GetTriangleCount(pMesh);
	}
	
	//Write the header to file
	fwrite(&header, 1, sizeof(DOGFileHeader), stream);

	//Write the vertices to file
	for (i = 0; i < msModel_GetMeshCount(pModel); i++)
	{
		pMesh = msModel_GetMeshAt(pModel, i);
		for (j = 0; j < msMesh_GetVertexCount(pMesh); j++)
		{
			deActorVertex		v;
			msVec3				pos;
			msVec2				uv;

			memset(&v, 0, sizeof(deActorVertex));
			
			msVertex *vert = msMesh_GetVertexAt(pMesh, j);
			
			v.BoneID = msVertex_GetBoneIndex(vert);

			msVertex_GetVertex(vert, pos);

			v.Vertex.x = pos[0];
			v.Vertex.y = pos[1];
			v.Vertex.z = pos[2];

			msVertex_GetTexCoords(vert, uv);

			v.UV.u = uv[0];
			v.UV.v = uv[1];

			fwrite(&v, 1, sizeof(deActorVertex), stream);
		}
	}

	//Write the textures to file
	for (i = 0; i < msModel_GetMaterialCount(pModel); i++)
	{
		deActorTexture				texture;

		msMaterial *pMaterial = msModel_GetMaterialAt(pModel, i);
		msMaterial_GetDiffuseTexture(pMaterial, (char*)texture, 128);

		fwrite(texture, 1, sizeof(deActorTexture), stream);
	}

	//Write the bones to file
	for (i = 0; i < msModel_GetBoneCount(pModel); i++)
	{
		deActorBone					bone;
		msVec3						vec;

		msBone *b = msModel_GetBoneAt(pModel, i);

		memset(&bone, 0, sizeof(deActorBone));

		msBone_GetName(b, bone.Name, MAX_BONE_NAME);
		msBone_GetParentName(b, bone.ParentName, MAX_BONE_NAME);

		msBone_GetPosition(b, vec);

		bone.Position.x = vec[0];
		bone.Position.y = vec[1];
		bone.Position.z = vec[2];

		msBone_GetRotation(b, vec);

		bone.Rotation.x = vec[0];
		bone.Rotation.y = vec[1];
		bone.Rotation.z = vec[2];

		bone.Mins.x = 0.0f;
		bone.Mins.y = 0.0f;
		bone.Mins.z = 0.0f;

		bone.Maxs.x = 0.0f;
		bone.Maxs.y = 0.0f;
		bone.Maxs.z = 0.0f;

		fwrite(&bone, 1, sizeof(deActorBone), stream);
	}

	//Write the faces to file
	for (i = 0; i < msModel_GetMeshCount(pModel); i++)
	{
		pMesh = msModel_GetMeshAt(pModel, i);

		for (j = 0; j < msMesh_GetTriangleCount(pMesh); j++)
		{
			deActorFace				face;
			unsigned short			vec[3];

			msTriangle *tri = msMesh_GetTriangleAt(pMesh, j);

			memset(&face, 0, sizeof(deActorFace));

			face.TexID = (short)msMesh_GetMaterialIndex(pMesh);
			
			msTriangle_GetVertexIndices(tri, vec);

			face.VertexIndices[0] = vec[0];
			face.VertexIndices[1] = vec[1];
			face.VertexIndices[2] = vec[2];

			fwrite(&face, 1, sizeof(deActorFace), stream);
		}
	}

	fclose(stream);
	stream = NULL;

	msModel_Destroy(pModel);

	return 0;
}
