#include "PajaTypes.h"
#include "Vector3C.h"
#include "ControllerC.h"
#include "CameraC.h"
#include "ContFloatC.h"
#include "ContVector3C.h"
#include "KeyC.h"

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


CameraC::CameraC() :
	m_rPos( 0, 0, 0 ),
	m_rTgt( 0, 0, 1 ),
	m_f32FOV( 60 / 180 * M_PI  ),
	m_f32NearPlane( 0 ),
	m_f32FarPlane( 1 ),
	m_pPosCont( 0 ),
	m_pTgtCont( 0 )
{
	// empty
}

CameraC::~CameraC()
{
	delete m_pPosCont;
	delete m_pTgtCont;
}

int32
CameraC::get_type()
{
	return CGITEM_CAMERA;
}

void
CameraC::set_position( const Vector3C& rPos )
{
	m_rPos = rPos;
}

const
Vector3C&
CameraC::get_position()
{
	return m_rPos;
}

void
CameraC::set_target_position( const Vector3C& rPos )
{
	m_rTgt = rPos;
}

const
Vector3C&
CameraC::get_target_position()
{
	return m_rTgt;
}

void
CameraC::set_fov( const float32 f32Val )
{
	m_f32FOV = f32Val;
}

const
float32
CameraC::get_fov()
{
	return m_f32FOV;
}

void
CameraC::set_near_plane( const float32 f32Val )
{
	m_f32NearPlane = f32Val;
}

const
float32
CameraC::get_near_plane()
{
	return m_f32NearPlane;
}

void
CameraC::set_far_plane( const float32 f32Val )
{
	m_f32FarPlane = f32Val;
}

const
float32
CameraC::get_far_plane()
{
	return m_f32FarPlane;
}

void
CameraC::eval_state( int32 i32Time )
{
	if( m_pPosCont )
		m_rPos = m_pPosCont->get_value( i32Time ); 

	if( m_pTgtCont )
		m_rTgt = m_pTgtCont->get_value( i32Time ); 
}

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

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

void
CameraC::set_target_position_controller( ContVector3C* pCont )
{
	m_pTgtCont = pCont;
}

ContVector3C*
CameraC::get_target_position_controller()
{
	return m_pTgtCont;
}

enum CameraChunksE {
	CHUNK_CAMERA_BASE			= 0x1000,
	CHUNK_CAMERA_STATIC			= 0x1001,
	CHUNK_CAMERA_CONT_POS		= 0x2000,
	CHUNK_CAMERA_CONT_TGT		= 0x2001,
};

const uint32	CAMERA_VERSION_1 = 1;
const uint32	CAMERA_VERSION = 2;


uint32
CameraC::save( SaveC* pSave )
{
	uint32	ui32Error = IO_OK;

	float32	f32Temp[3];

	// camera base
	pSave->begin_chunk( CHUNK_CAMERA_BASE, CAMERA_VERSION );
		ScenegraphItemI::save( pSave );
	pSave->end_chunk();

	// camera base (static)
	pSave->begin_chunk( CHUNK_CAMERA_STATIC, CAMERA_VERSION );
		// position
		f32Temp[0] = m_rPos[0];
		f32Temp[1] = m_rPos[1];
		f32Temp[2] = m_rPos[2];
		ui32Error = pSave->write( f32Temp, sizeof( f32Temp ) );

		// target pos
		f32Temp[0] = m_rTgt[0];
		f32Temp[1] = m_rTgt[1];
		f32Temp[2] = m_rTgt[2];
		ui32Error = pSave->write( f32Temp, sizeof( f32Temp ) );

		// roll
		ui32Error = pSave->write( &m_f32Roll, sizeof( m_f32Roll ) );

		// FOV
		ui32Error = pSave->write( &m_f32FOV, sizeof( m_f32FOV ) );

		// near plane
		ui32Error = pSave->write( &m_f32NearPlane, sizeof( m_f32NearPlane ) );

		// far plane
		ui32Error = pSave->write( &m_f32FarPlane, sizeof( m_f32FarPlane ) );
	pSave->end_chunk();

	// controllers
	if( m_pPosCont ) {
		pSave->begin_chunk( CHUNK_CAMERA_CONT_POS, CAMERA_VERSION );
			m_pPosCont->save( pSave );
		pSave->end_chunk();
	}

	if( m_pTgtCont ) {
		pSave->begin_chunk( CHUNK_CAMERA_CONT_TGT, CAMERA_VERSION );
			m_pTgtCont->save( pSave );
		pSave->end_chunk();
	}

	return ui32Error;
}

uint32
CameraC::load( LoadC* pLoad )
{
	uint32	ui32Error = IO_OK;
	float32	f32Temp[3];

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

		switch( pLoad->get_chunk_id() ) {

		case CHUNK_CAMERA_BASE:
			if( pLoad->get_chunk_version() == CAMERA_VERSION )
				ScenegraphItemI::load( pLoad );
			break;

		case CHUNK_CAMERA_STATIC:
			if( pLoad->get_chunk_version() == CAMERA_VERSION ) {
				// position
				ui32Error = pLoad->read( f32Temp, sizeof( f32Temp ) );
				m_rPos[0] = f32Temp[0];
				m_rPos[1] = f32Temp[1];
				m_rPos[2] = f32Temp[2];

				// target pos
				ui32Error = pLoad->read( f32Temp, sizeof( f32Temp ) );
				m_rTgt[0] = f32Temp[0];
				m_rTgt[1] = f32Temp[1];
				m_rTgt[2] = f32Temp[2];

				// roll
				ui32Error = pLoad->read( &m_f32Roll, sizeof( m_f32Roll ) );

				// FOV
				ui32Error = pLoad->read( &m_f32FOV, sizeof( m_f32FOV ) );

				// near plane
				ui32Error = pLoad->read( &m_f32NearPlane, sizeof( m_f32NearPlane ) );

				// far plane
				ui32Error = pLoad->read( &m_f32FarPlane, sizeof( m_f32FarPlane ) );
			}
			break;

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

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