#include "hud.h"
#include "cl_util.h"

#include "const.h"
#include "entity_state.h"
#include "cl_entity.h"
#include "triangleapi.h"

#include "com_model.h"
#include "studio_util.h"
#include "vrml.h"
#include <fstream>
#include "r_studioint.h"

#include "studio_util.h"
#include "r_studioint.h"
#include "StudioModelRenderer.h"
#include "GameStudioModelRenderer.h"

extern engine_studio_api_t IEngineStudio;
extern CGameStudioModelRenderer g_StudioRenderer;

using namespace std;



int FindVertices(const char *buffer, VRMLData &info)
{	const char *pCoord = strstr(buffer,"coordinate3");
	if (!pCoord)
		return 0;
	const char *pPoint = strstr(pCoord,"point");
	if (!pPoint)
		return 0;
	const char *pOpenBracket = strstr(pPoint,"[");
	if (!pOpenBracket)
		return 0;
	pOpenBracket++;


	const char *pVerticeEnd = strstr(pOpenBracket,"]");
	if (!pVerticeEnd)
		return 0;
	
	char *pSeparatedPoints = new char [pVerticeEnd-pOpenBracket+1];
	strncpy(pSeparatedPoints,pOpenBracket,pVerticeEnd-pOpenBracket);
	pSeparatedPoints[pVerticeEnd-pOpenBracket] = '\0';
	
	char *pNumber = strtok(pSeparatedPoints," \n\t");
	int iNumberOfPoints = 0;
	int i = 0;	
	while (pNumber && iNumberOfPoints<MAX_VERTICES)
	{	
		while(pNumber && i<3)
		{	info.flVertices[iNumberOfPoints][i]=(float)atof(pNumber);
			pNumber = strtok(NULL,", \n\t");			
			i++;
		}
		i = 0;
		iNumberOfPoints++;
	}  
	info.iNumberOfVertices = iNumberOfPoints;
	
	delete[] pSeparatedPoints;
	return 1;
}

int FindTextureCoords(const char *buffer, VRMLData &info)
{	const char *pCoord = strstr(buffer,"texturecoordinate2");
	if (!pCoord)
		return 0;
	const char *pPoint = strstr(pCoord,"point");
	if (!pPoint)
		return 0;	
	const char *pOpenBracket = strstr(pPoint,"[");
	if (!pOpenBracket)
		return 0;	
	pOpenBracket++;
	const char *pTextureEnd = strstr(pOpenBracket,"]");
	if (!pTextureEnd)
		return 0;
	
	char *pSeparatedPoints = new char [pTextureEnd-pOpenBracket+1];
	strncpy(pSeparatedPoints,pOpenBracket,pTextureEnd-pOpenBracket);
	pSeparatedPoints[pTextureEnd-pOpenBracket] = '\0';
	
	char *pNumber = strtok(pSeparatedPoints," \n\t");
	int iNumberOfPoints = 0;
	int i = 0;	
	while (pNumber && iNumberOfPoints<MAX_VERTICES)
	{	
		while(pNumber && i<2)
		{	info.flTextureCoords[iNumberOfPoints][i]=(float)atof(pNumber);
			pNumber = strtok(NULL,", \n\t");			
			i++;
		}
		i = 0;
		iNumberOfPoints++;
	}
	
	delete[] pSeparatedPoints;
	info.iNumberOfTexCoords=iNumberOfPoints;
	return 1;
}

int FindIndices(const char *buffer, VRMLData &info)
{	const char *pCoord = strstr(buffer,"indexedfaceset");
	if (!pCoord)
		return 0;
	const char *pPoint = strstr(pCoord,"coordindex");
	if (!pPoint)
		return 0;
	const char *pOpenBracket = strstr(pPoint,"[");
	if (!pOpenBracket)
		return 0;
	pOpenBracket++;
	const char *pIndicesEnd = strstr(pOpenBracket,"]");
	char *pSeparatedPoints = new char [pIndicesEnd-pOpenBracket+1];
	strncpy(pSeparatedPoints,pOpenBracket,pIndicesEnd-pOpenBracket);
	pSeparatedPoints[pIndicesEnd-pOpenBracket] = '\0';
	
	char *pNumber = strtok(pSeparatedPoints,", \n\t");
	int iNumberOfPoints = 0;
	int i = 0;	
	while (pNumber && iNumberOfPoints<MAX_POLYS)
	{	
		while(pNumber && i<3)
		{	info.iIndices[iNumberOfPoints][i]=atoi(pNumber);
			pNumber = strtok(NULL,", \n\t");			
			i++;
		}
		i = 0;
		//ignore -1
		pNumber = strtok (NULL, ", \n\t");
		iNumberOfPoints++;
	}  
	info.iNumberOfPolys = iNumberOfPoints;
	delete[] pSeparatedPoints;
	return 1;
}

int FindTextureIndices(const char *buffer, VRMLData &info)
{	const char *pCoord = strstr(buffer,"indexedfaceset");
	if (!pCoord)
		return 0;
	const char *pPoint = strstr(pCoord,"texturecoordindex");
	if (!pPoint)
		return 0;
	const char *pOpenBracket = strstr(pPoint,"[");
	if (!pOpenBracket)
		return 0;
	pOpenBracket++;
	const char *pIndicesEnd = strstr(pOpenBracket,"]");
	char *pSeparatedPoints = new char [pIndicesEnd-pOpenBracket+1];
	strncpy(pSeparatedPoints,pOpenBracket,pIndicesEnd-pOpenBracket);
	pSeparatedPoints[pIndicesEnd-pOpenBracket] = '\0';
	
	char *pNumber = strtok(pSeparatedPoints,", \n\t");
	int iNumberOfPoints = 0;
	int i = 0;	
	while (pNumber && iNumberOfPoints<MAX_POLYS)
	{	
		while(pNumber && i<3)
		{	info.iTextureIndices[iNumberOfPoints][i]=atoi(pNumber);
			pNumber = strtok(NULL,", \n\t");			
			i++;
		}
		i = 0;
		//ignore -1
		pNumber = strtok (NULL, ", \n\t");
		iNumberOfPoints++;
	}  
	delete[] pSeparatedPoints;	
	if (info.iNumberOfPolys != iNumberOfPoints)
	{	return 0;
	}
	return 1;
}

void ToLowerCase(char *buffer)
{	for (unsigned i=0;i<strlen(buffer);i++)
	{	if(buffer[i]>='A'&&buffer[i]<='Z')
		{	buffer[i]+= ('a'-'A');
		}
	}
}

void ParseVRML(const char *filename, VRMLData &info)
{
	// Only parse it if it hasnt been parsed before
	if(!info.blVRMLParsed)
		info.blVRMLParsed = true;
	else
		return;
	fstream f;
	
	char pFileName[255];
	sprintf(pFileName,"%s/%s",gEngfuncs.pfnGetGameDirectory(),filename);
	f.open(pFileName,ios::in||ios::binary);
	if(!f.is_open())
	{
		info.iNumberOfPolys = 0;
		info.iNumberOfVertices = 0;
		ConsolePrint("Can't open model");
		ConsolePrint(pFileName);
		ConsolePrint("\n");
		return;
	}
	
	// get length of file:
	f.seekg (0, ios::end);
	int iLength = f.tellg();
	f.seekg (0, ios::beg);

	// read complete file
	string sBuffer="";
	char c;
	while(!f.eof())
	{
		f.read(&c,1);
		if(c>='A' && c<='Z')
		{
			c-='A'-'a';
		}
		sBuffer += c;
	}
	f.close();
		
	//ToLowerCase(pBuffer);
	
	const char *pBuffer = sBuffer.c_str();
	
	FindVertices(pBuffer, info);
	FindTextureCoords(pBuffer, info);
	FindIndices(pBuffer, info);
	FindTextureIndices(pBuffer, info);			
}

void ScaleVRML(VRMLData &dest, const VRMLData &src, float alpha)
{	dest.iNumberOfPolys = src.iNumberOfPolys;
	dest.iNumberOfVertices = src.iNumberOfVertices;
	dest.iNumberOfTexCoords= src.iNumberOfTexCoords;
	int i=0;	

	//copy polygon coords and texture indices
	for(i = 0;i<src.iNumberOfPolys;i++)
	{	for(int j = 0;j<3;j++)
		{	dest.iIndices[i][j]=src.iIndices[i][j];
			dest.iTextureIndices[i][j] = src.iTextureIndices[i][j];
		}
	}
	
	//copy texture coords			
	for (i=0;i<src.iNumberOfTexCoords;i++)
	{	for(int k=0;k<2;k++)
		{	dest.flTextureCoords[i][k] = src.flTextureCoords[i][k];
		}
	}

	//copy polygon coords
	for(i = 0;i<src.iNumberOfPolys;i++)
	{	for(int j = 0;j<3;j++)
		{	dest.iIndices[i][j]=src.iIndices[i][j];
		}
	}

	//scale vertices			
	for(i = 0;i<src.iNumberOfVertices;i++)
	{	for(int j = 0;j<3;j++)
		{	dest.flVertices[i][j]=src.flVertices[i][j]*alpha;			
		}
	}	
}

void RotateVRML(VRMLData &dest, const VRMLData &src, float *angles)
{	dest.iNumberOfPolys = src.iNumberOfPolys;
	dest.iNumberOfVertices = src.iNumberOfVertices;
	dest.iNumberOfTexCoords= src.iNumberOfTexCoords;

	float rmatrix[3][4];
	AngleMatrix(angles,rmatrix);
	int i=0;
	
	//copy polygon coords, and texture indices
	for(i = 0;i<src.iNumberOfPolys;i++)
	{	for(int j = 0;j<3;j++)
		{	dest.iIndices[i][j]=src.iIndices[i][j];
			dest.iTextureIndices[i][j] = src.iTextureIndices[i][j];
		}
	}
	
	//rotate vertices
	for(i = 0;i<src.iNumberOfVertices;i++)
	{	VectorTransform(src.flVertices[i], rmatrix, dest.flVertices[i]);		
	}
	
	//copy texture coords			
	for (i=0;i<src.iNumberOfTexCoords;i++)
	{	for(int k=0;k<2;k++)
		{	dest.flTextureCoords[i][k] = src.flTextureCoords[i][k];
		}
	}	
}

void DrawVRML (const VRMLData &info,vec3_t pos, int rendermode, TRICULLSTYLE tricullstyle, int r, int g, int b, int a)
{	gEngfuncs.pTriAPI->RenderMode( rendermode );
	gEngfuncs.pTriAPI->CullFace( tricullstyle );
	gEngfuncs.pTriAPI->Begin( TRI_TRIANGLES);
	gEngfuncs.pTriAPI->Color4ub(r,g,b,a);
	vec3_t vecTemp;
	for (int i = 0;i<info.iNumberOfPolys;i++)
	{	for (int j = 0;j<3;j++)
		{	int iIndex = info.iIndices[i][j];
			int iTextureIndex = info.iTextureIndices[i][j];
			if(iIndex<info.iNumberOfVertices && iTextureIndex<info.iNumberOfTexCoords)
			{
				gEngfuncs.pTriAPI->TexCoord2f( info.flTextureCoords[iTextureIndex][0], info.flTextureCoords[iTextureIndex][1]);
				vecTemp = pos + Vector(info.flVertices[iIndex][0],info.flVertices[iIndex][1],info.flVertices[iIndex][2]);
				gEngfuncs.pTriAPI->Vertex3f( vecTemp.x, vecTemp.y, vecTemp.z );
			}
			else
			{
				ConsolePrint("Invalid model index\n");
			}			
		}
	}
	gEngfuncs.pTriAPI->End();
}

void DrawVRML (const VRMLData &info,vec3_t pos, HSPRITE sprite, int rendermode, TRICULLSTYLE tricullstyle, int frame, int r, int g, int b, int a)
{	
	if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( sprite ), frame))
	{	return;
	}
	DrawVRML(info,pos,rendermode,tricullstyle,r,g,b,a);
}

void DrawVRMLSVSprite (const VRMLData &info,vec3_t pos, int sprite, int rendermode, TRICULLSTYLE tricullstyle, int frame, int r, int g, int b, int a)
{
	if ( !gEngfuncs.pTriAPI->SpriteTexture( IEngineStudio.GetModelByIndex(sprite), frame))
	{	ConsolePrint("Can't find texture sprite\n");
		return;
	}
	DrawVRML(info,pos,rendermode,tricullstyle,r,g,b,a);
}