
#include <windows.h>
#include <assert.h>
#include "ScenegraphItemI.h"
#include "PajaTypes.h"
#include "HelperC.h"


static
void
TRACE( const char* szFormat, ...  )
{
	char	szMsg[256];
	va_list	rList;
	va_start( rList, szFormat );
	_vsnprintf( szMsg, 255, szFormat, rList );
	va_end( rList );
	OutputDebugString( szMsg );
}

using namespace Composition;
using namespace PajaTypes;
using namespace FileIO;
using namespace Import;


HelperC::HelperC() :
	m_pPosCont( 0 ),
	m_pRotCont( 0 ),
	m_pScaleCont( 0 ),
	m_f32Radius( 0 )
{
	// empty
}

HelperC::~HelperC()
{
	delete m_pPosCont;
	delete m_pRotCont;
	delete m_pScaleCont;
}

int32
HelperC::get_type()
{
	return CGITEM_HELPER;
}

void
HelperC::set_position( const Vector3C& rPos )
{
	m_rPosition = rPos;
}


const
Vector3C&
HelperC::get_position()
{
	return m_rPosition;
}

void
HelperC::set_scale( const Vector3C& rScale )
{
	m_rScale = rScale;
}

const
Vector3C&
HelperC::get_scale()
{
	return m_rScale;
}

void
HelperC::set_rotation( const QuatC& rRot )
{
	m_rRotation = rRot;
}

const
QuatC&
HelperC::get_rotation()
{
	return m_rRotation;
}


void
HelperC::eval_state( int32 i32Time )
{
	if( m_pPosCont )
		m_rPosition = m_pPosCont->get_value( i32Time );
	if( m_pScaleCont )
		m_rScale = m_pScaleCont->get_value( i32Time );
	if( m_pRotCont )
		m_rRotation = m_pRotCont->get_value( i32Time );
}

void
HelperC::set_position_controller( ContVector3C* pCont )
{
	m_pPosCont = pCont;
}

ContVector3C*
HelperC::get_position_controller()
{
	return m_pPosCont;
}

void
HelperC::set_rotation_controller( ContQuatC* pCont )
{
	m_pRotCont = pCont;
}

ContQuatC*
HelperC::get_rotation_controller()
{
	return m_pRotCont;
}

void
HelperC::set_scale_controller( ContVector3C* pCont )
{
	m_pScaleCont = pCont;
}

ContVector3C*
HelperC::get_scale_controller()
{
	return m_pScaleCont;
}

void
HelperC::set_center( Vector3C rCenter )
{
	m_rCenter = rCenter;
}

void
HelperC::set_radius( float32 f32Radius )
{
	m_f32Radius = f32Radius;
}

const Vector3C&
HelperC::get_center() const
{
	return m_rCenter;
}

float32
HelperC::get_radius()
{
	return m_f32Radius;
}

enum HelperChunksE {
	CHUNK_MESH_BASE				= 0x1000,
	CHUNK_MESH_STATIC			= 0x1001,
	CHUNK_MESH_CONT_POS			= 0x2000,
	CHUNK_MESH_CONT_ROT			= 0x2001,
	CHUNK_MESH_CONT_SCALE		= 0x2002,
};

const uint32	MESH_VERSION = 1;

uint32
HelperC::save( SaveC* pSave )
{
	uint32	ui32Error = IO_OK;
	float32	f32Temp3[3];
	float32	f32Temp4[4];

	eval_state( 0 );

	// Sace scenegraphitem base.
	pSave->begin_chunk( CHUNK_MESH_BASE, MESH_VERSION );
		ScenegraphItemI::save( pSave );
	pSave->end_chunk();

	// Save static transformation.
	pSave->begin_chunk( CHUNK_MESH_STATIC, MESH_VERSION );
		// position
		f32Temp3[0] = m_rPosition[0];
		f32Temp3[1] = m_rPosition[1];
		f32Temp3[2] = m_rPosition[2];
		ui32Error = pSave->write( f32Temp3, sizeof( f32Temp3 ) );
		// rotation
		f32Temp4[0] = m_rRotation[0];
		f32Temp4[1] = m_rRotation[1];
		f32Temp4[2] = m_rRotation[2];
		f32Temp4[3] = m_rRotation[3];
		ui32Error = pSave->write( f32Temp4, sizeof( f32Temp4 ) );
		// scale
		f32Temp3[0] = m_rScale[0];
		f32Temp3[1] = m_rScale[1];
		f32Temp3[2] = m_rScale[2];
		ui32Error = pSave->write( f32Temp3, sizeof( f32Temp3 ) );
		// center
		f32Temp3[0] = m_rCenter[0];
		f32Temp3[1] = m_rCenter[1];
		f32Temp3[2] = m_rCenter[2];
		ui32Error = pSave->write( f32Temp3, sizeof( f32Temp3 ) );
		// radius
		ui32Error = pSave->write( &m_f32Radius, sizeof( m_f32Radius ) );
	pSave->end_chunk();


	// pos controller
	if( m_pPosCont ) {
		pSave->begin_chunk( CHUNK_MESH_CONT_POS, MESH_VERSION );
			m_pPosCont->save( pSave );
		pSave->end_chunk();
	}

	// rot controller
	if( m_pRotCont ) {
		pSave->begin_chunk( CHUNK_MESH_CONT_ROT, MESH_VERSION );
			m_pRotCont->save( pSave );
		pSave->end_chunk();
	}

	// scale controller
	if( m_pScaleCont ) {
		pSave->begin_chunk( CHUNK_MESH_CONT_SCALE, MESH_VERSION );
			m_pScaleCont->save( pSave );
		pSave->end_chunk();
	}

	return ui32Error;
}

uint32
HelperC::load( LoadC* pLoad )
{
	uint32	ui32Error = IO_OK;
	float32	f32Temp3[3];
	float32	f32Temp4[4];

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

		switch( pLoad->get_chunk_id() ) {

		case CHUNK_MESH_BASE:
			if( pLoad->get_chunk_version() <= MESH_VERSION )
				ScenegraphItemI::load( pLoad );
			break;

		case CHUNK_MESH_STATIC:
			if( pLoad->get_chunk_version() <= MESH_VERSION ) {

				// position
				ui32Error = pLoad->read( f32Temp3, sizeof( f32Temp3 ) );
				m_rPosition[0] = f32Temp3[0];
				m_rPosition[1] = f32Temp3[1];
				m_rPosition[2] = f32Temp3[2];

				// rotation
				ui32Error = pLoad->read( f32Temp4, sizeof( f32Temp4 ) );
				m_rRotation[0] = f32Temp4[0];
				m_rRotation[1] = f32Temp4[1];
				m_rRotation[2] = f32Temp4[2];
				m_rRotation[3] = f32Temp4[3];

				// scale
				ui32Error = pLoad->read( f32Temp3, sizeof( f32Temp3 ) );
				m_rScale[0] = f32Temp3[0];
				m_rScale[1] = f32Temp3[1];
				m_rScale[2] = f32Temp3[2];

				// center
				ui32Error = pLoad->read( f32Temp3, sizeof( f32Temp3 ) );
				m_rCenter[0] = f32Temp3[0];
				m_rCenter[1] = f32Temp3[1];
				m_rCenter[2] = f32Temp3[2];

				// radius
				ui32Error = pLoad->read( &m_f32Radius, sizeof( m_f32Radius ) );
			}
			break;

		case CHUNK_MESH_CONT_POS:
			if( pLoad->get_chunk_version() <= MESH_VERSION ) {
				ContVector3C*	pCont = new ContVector3C;
				ui32Error = pCont->load( pLoad );
				m_pPosCont = pCont;
			}
			break;

		case CHUNK_MESH_CONT_ROT:
			if( pLoad->get_chunk_version() <= MESH_VERSION ) {
				ContQuatC*	pCont = new ContQuatC;
				ui32Error = pCont->load( pLoad );
				m_pRotCont = pCont;
			}
			break;

		case CHUNK_MESH_CONT_SCALE:
			if( pLoad->get_chunk_version() <= MESH_VERSION ) {
				ContVector3C*	pCont = new ContVector3C;
				ui32Error = pCont->load( pLoad );
				m_pScaleCont = pCont;
			}
			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;
}
