

#include <assert.h>
#include "ScenegraphItemI.h"
#include "PajaTypes.h"
#include "BoneC.h"


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


BoneC::BoneC() :
	m_pPosCont( 0 ),
	m_pRotCont( 0 ),
	m_ui32BoneId( 0xffffffff )
{
	// empty
}

BoneC::~BoneC()
{
	delete m_pPosCont;
	delete m_pRotCont;
}

int32
BoneC::get_type()
{
	return CGITEM_BONE;
}

void
BoneC::set_bone_id( uint32 ui32Id )
{
	m_ui32BoneId = ui32Id;
}

uint32
BoneC::get_bone_id() const
{
	return m_ui32BoneId;
}


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


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

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

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


void
BoneC::eval_state( int32 i32Time )
{
	if( m_pPosCont )
		m_rPosition = m_pPosCont->get_value( i32Time );
	if( m_pRotCont )
		m_rRotation = m_pRotCont->get_value( i32Time );

	QuatC	rRot( m_rRotation );
	rRot[3] = -rRot[3];

	// Compose matrix
	m_rTM.set_rot( rRot );
	m_rTM[3] = m_rPosition;

//	if( m_pParent )
//		m_rTM *= m_pParent->get_tm();
}

void
BoneC::eval_geom( int32 i32Time )
{
	// empty
}

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

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

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

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

void
BoneC::update_dependencies( std::vector<ScenegraphItemI*> rScenegraph )
{
	uint32	i;
	// find parent
	m_pParent = 0;
	for( i = 0; i < rScenegraph.size(); i++ ) {
		if( m_sParentName.compare( rScenegraph[i]->get_name() ) == 0 ) {
			m_pParent = rScenegraph[i];
			break;
		}
	}
}

enum BoneChunksE {
	CHUNK_BONE_BASE				= 0x1000,
	CHUNK_BONE_STATIC			= 0x1001,
	CHUNK_BONE_ID				= 0x1002,
	CHUNK_BONE_CONT_POS			= 0x2000,
	CHUNK_BONE_CONT_ROT			= 0x2001,
};

const uint32	BONE_VERSION = 1;

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

	eval_state( 0 );

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

	// Save static transformation.
	pSave->begin_chunk( CHUNK_BONE_STATIC, BONE_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 ) );
	pSave->end_chunk();

	// bone id
	pSave->begin_chunk( CHUNK_BONE_ID, BONE_VERSION );
		ui32Error = pSave->write( &m_ui32BoneId, sizeof( m_ui32BoneId ) );
	pSave->end_chunk();

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

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

	return ui32Error;
}

uint32
BoneC::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_BONE_BASE:
			if( pLoad->get_chunk_version() == BONE_VERSION )
				ScenegraphItemI::load( pLoad );
			break;

		case CHUNK_BONE_STATIC:
			if( pLoad->get_chunk_version() == BONE_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];
			}
			break;

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

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

		case CHUNK_BONE_ID:
			if( pLoad->get_chunk_version() == BONE_VERSION ) {
				ui32Error = pLoad->read( &m_ui32BoneId, sizeof( m_ui32BoneId ) );
			}
			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;
}
