
#include "Mesh3DC.h"
#include "PajaTypes.h"
#include "GeomListC.h"
#include "Vector3C.h"
#include <vector>
#include <string>
#include <assert.h>

using namespace PajaTypes;
using namespace FileIO;
using namespace std;


Mesh3DC::Mesh3DC() :
	m_bBBoxValid( false ),
	m_bBBoxEmpty( false ),
	m_rMin( 0, 0, 0 ),
	m_rMax( 0, 0, 0 ),
	m_ui32DisplaylistName( 0 )
{	
	// empty
}

Mesh3DC::~Mesh3DC()
{
	for( uint32 i = 0; i < m_rLists.size(); i++ )
		delete m_rLists[i];
	m_rLists.clear();
}

uint32
Mesh3DC::get_geomlist_count()
{
	return m_rLists.size();
}

GeomListC*
Mesh3DC::add_geomlist( GeomListC* pGeomList )
{
	m_bBBoxValid = false;

	if( !pGeomList )
		pGeomList = new GeomListC();

	m_rLists.push_back( pGeomList );

	return pGeomList;
}

void
Mesh3DC::insert_geomlist( uint32 ui32Index, GeomListC* pGeomList )
{
	m_bBBoxValid = false;

	if( !pGeomList )
		pGeomList = new GeomListC();

	m_rLists.insert( m_rLists.begin() + ui32Index, pGeomList );
}

void
Mesh3DC::erase_geomlist( uint32 ui32Index )
{
	assert( ui32Index < m_rLists.size() );
	//Free it...
	delete m_rLists[ui32Index];
	m_rLists.erase( m_rLists.begin() + ui32Index );
}

void
Mesh3DC::replace_geomlist( uint32 ui32Index, GeomListC* pGeomList )
{
	assert( ui32Index < m_rLists.size() );

	m_bBBoxValid = false;

	delete m_rLists[ui32Index];

	m_rLists[ui32Index] = pGeomList;
}

GeomListC*
Mesh3DC::get_geomlist( uint32 ui32Index )
{
	if( ui32Index < m_rLists.size() )
		return m_rLists[ui32Index];
	return 0;
}


bool
Mesh3DC::get_bounds( Vector3C& rMin, Vector3C& rMax )
{
	if( !m_bBBoxValid)
		update_bounds();

	rMin = m_rMin;
	rMax = m_rMax;

	return m_bBBoxEmpty;
}

void
Mesh3DC::update_bounds()
{
	m_bBBoxValid = true;
	bool	bFirst = true;

	m_rMin = m_rMax = Vector3C( 0, 0, 0 );
	m_bBBoxEmpty = true;

	if( m_rLists.size() > 0 ) {

		Vector3C	rListMin, rListMax;

		//Get bounds of first list..
		if( bFirst ) {
			m_rLists[0]->get_bounds( m_rMin, m_rMax );
			bFirst = false;
		}

		//And then the others...
		for( uint32 i = 1; i < m_rLists.size(); i++ ) {
			m_rLists[i]->get_bounds( rListMin, rListMax );
			for( uint32 k = 0; k < 3; k++ ) {
				if( rListMin[k] < m_rMin[k] ) m_rMin[k] = rListMin[k];
				if( rListMax[k] > m_rMax[k] ) m_rMax[k] = rListMax[k];
			}		
		}
		
		m_bBBoxEmpty = false;
	}
}

const char*
Mesh3DC::get_name()
{
	return m_sName.c_str();
}

void
Mesh3DC::set_name( const char* szName )
{
	m_sName = szName;
}

uint32
Mesh3DC::get_displist_name()
{
	return m_ui32DisplaylistName;
}

void
Mesh3DC::set_displist_name( uint32 ui32Name )
{
	m_ui32DisplaylistName = ui32Name;
}

void
Mesh3DC::set_id( uint32 ui32ID )
{
	m_ui32ID = ui32ID;
}

uint32
Mesh3DC::get_id() const
{
	return m_ui32ID;
}

uint32
Mesh3DC::get_triangle_count()
{
	int	i32TriCount = 0;

	if( m_rLists.size() > 0 )
		for( uint32 i = 0; i < m_rLists.size(); i++ )
			i32TriCount += m_rLists[i]->get_index_count();

	return i32TriCount / 3;
}

uint32
Mesh3DC::get_vertex_count()
{
	int	i32VertCount = 0;

	if( m_rLists.size() > 0 )
		for( uint32 i = 0; i < m_rLists.size(); i++ )
			i32VertCount += m_rLists[i]->get_vertex_count();

	return i32VertCount;
}


enum Mesh3DChunksE {
	CHUNK_MESH3D_NAME			= 0x1000,
	CHUNK_MESH3D_GEOMLIST		= 0x2000,
};

const uint32	MESH3D_VERSION = 1;


uint32
Mesh3DC::save( SaveC* pSave )
{
	uint32	ui32Error = IO_OK;
	std::string	sStr;

	// write name
	pSave->begin_chunk( CHUNK_MESH3D_NAME, MESH3D_VERSION );
		sStr = m_sName;
		if( sStr.size() > 255 )
			sStr.resize( 255 );
		ui32Error = pSave->write_str( sStr.c_str() );
	pSave->end_chunk();

	// write geomlists
	for( uint32 i = 0; i < m_rLists.size(); i++ ) {
		pSave->begin_chunk( CHUNK_MESH3D_GEOMLIST, MESH3D_VERSION );
			ui32Error = m_rLists[i]->save( pSave );
		pSave->end_chunk();
	}

	return ui32Error;
}

uint32
Mesh3DC::load( LoadC* pLoad )
{
	uint32	ui32Error = IO_OK;
	char	szStr[256];

	while( (ui32Error = pLoad->open_chunk()) == IO_OK ) {

		switch( pLoad->get_chunk_id() ) {

		case CHUNK_MESH3D_NAME:
			{
				if( pLoad->get_chunk_version() == MESH3D_VERSION ) {
					ui32Error = pLoad->read_str( szStr );
					m_sName = szStr;
				}
			}
			break;

		case CHUNK_MESH3D_GEOMLIST:
			{
				if( pLoad->get_chunk_version() == MESH3D_VERSION ) {
					GeomListC*	pList = new GeomListC;
					ui32Error = pList->load( pLoad );
					m_rLists.push_back( pList );
				}
			}
			break;

		default:
			assert( 0 );
		}

		pLoad->close_chunk();

		if( ui32Error != IO_OK && ui32Error != IO_END ) {
			return ui32Error;
		}
	}

	if( ui32Error != IO_OK && ui32Error != IO_END ) {
		return ui32Error;
	}

	return IO_OK;
}
