#include "stdAfx.h"
#include <math.h>
#include "face.h"
#include "facegroup.h"
#include "vector3d.h"
#include "vector3dgroup.h"
#include "mesh.h"
#include "off_loader.h"

void OFFLoader::load( char *pFileName, Mesh **ppInMesh )
{
	// open the OFF file

	hFile = CreateFile( pFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );

	if ( hFile == INVALID_HANDLE_VALUE )
	{
		MessageBox( NULL, "face","face", MB_OK );//throw( "OFF file does not exist" );
	}

	// put file in temporary buffer for fast access

	iBufSize = GetFileSize( hFile, NULL );

	pBuf = new char[ iBufSize ];

	unsigned long iActualRead;

	ReadFile( hFile, pBuf, iBufSize, &iActualRead, NULL );

	// close the OFF file

	CloseHandle( hFile );

	// start reading the buffer

	ppMesh = ppInMesh;

	iCursor = 0;

	readHeader();
	readMaxParams();

	// instantiate mesh class

	(*ppMesh) = new Mesh( iMaxVert, iMaxFace );

	readVertexList();
	readFaceList();
	delete pBuf;
}

void OFFLoader::readVertexList()
{
	float fX, fY, fZ;

	if ( iOption_N || iOption_C )
	{
		delete (*ppMesh);
		MessageBox( NULL, "face","face", MB_OK );//throw( "current OFF loader version can't read colors or normals" );
	}

	for ( int i = 0; i < iMaxVert; i++ )
	{
		eatWhiteSpace();
		read3Floats( fX, fY, fZ );
		(*ppMesh)->getVector3DGroupPtr()->addElement( Vector3D( fX, fY, fZ ) );
	}
}

void OFFLoader::readFaceList()
{
	int iMaxIndex;
	int iIndex;

	Face *pFace;

	FaceGroup *pFaceGroup = (*ppMesh)->getFaceGroupPtr();

	for ( int i = 0; i < iMaxFace; i++ )
	{
		eatWhiteSpace();
		iMaxIndex = readIntegerFromBuffer();

		pFace = new Face( iMaxIndex );		

		for ( int j = 0; j < iMaxIndex; j++ )
		{
			iIndex = readIntegerFromBuffer();
			pFace->addVertexIndex( iIndex );
		}

		pFaceGroup->addElement( *pFace );

		delete pFace;

		readEOL();
	}
}

void OFFLoader::readMaxParams()
{
	iMaxVert = readIntegerFromBuffer();
	iMaxFace = readIntegerFromBuffer();
	iMaxEdge = readIntegerFromBuffer();
	eatWhiteSpace();
	readEOL();
}

void OFFLoader::read3Floats( float &fA, float &fB, float &fC )
{
	fA = readFloatFromBuffer();
	fB = readFloatFromBuffer();
	fC = readFloatFromBuffer();

	eatWhiteSpace();
	readEOL();
}

int OFFLoader::readIntegerFromBuffer()
{
	char cNum[ 16 ];
	int  iLen = 0;
	int iRet = 0;

	while( pBuf[ iCursor ] != ' ' && pBuf[ iCursor ] != 13 && pBuf[ iCursor ] != '\t' )
	{
		cNum[ iLen++ ] = pBuf[ iCursor++ ];
	}

	for ( int i = iLen-1; i >= 0; i-- )
	{
		iRet += ( cNum[i] - 48 ) * pow( 10, iLen - i - 1 );
	}

	eatWhiteSpace();

	return iRet;
}

float OFFLoader::readFloatFromBuffer()
{
	char cNum[ 16 ];
	int  iLen = 0;
	float fRet = 0;

	while( pBuf[ iCursor ] != ' ' && pBuf[ iCursor ] != 13 && pBuf[ iCursor ] != '\t')
	{
		cNum[ iLen++ ] = pBuf[ iCursor++ ];
	}

	fRet = atof( cNum );

	eatWhiteSpace();

	return fRet;
}

void OFFLoader::readEOL()
{
	while( pBuf[ iCursor ] != '\n') {// && pBuf[ iCursor+1 ] != 13 && pBuf[ iCursor ] != '\t')
		iCursor ++;//
	} //= 2;
	iCursor++;
}

void OFFLoader::readHeader()
{
	iOption_N = iOption_C = iOption_4 = 0;

	for ( int i = 0; i < 5; i++ )
	{
		eatWhiteSpace();

		switch( pBuf[iCursor] )
		{
			case 'C':
			{
				iOption_C = 1;
			}break;
			case 'N':
			{
				iOption_N = 1;
			}break;
			case '4':
			{
				iOption_4 = 1;
			}break;
			case 'O':
			{
				iCursor += 3;
				eatWhiteSpace();
				readEOL();
				return;
			}break;
			default:
				return;
		}

		iCursor++;
	}

	MessageBox( NULL, "face","face", MB_OK );//throw( "unexpected OFF format" );
}

void OFFLoader::eatWhiteSpace()
{
	while( pBuf[ iCursor ] == ' ' || pBuf[ iCursor ] == '\t' )
	{
		iCursor++;
	}
}