#include "PajaTypes.h"
#include "Vector3C.h"
#include "ControllerC.h"
#include "ContFloatC.h"
#include "ContVector3C.h"
#include "LightC.h"

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


LightC::LightC() :
	m_rColor( 1, 1, 1 ),
	m_f32Multiplier( 1 ),
	m_f32DecayStart( 0 ),
	m_bDoDecay( false ),
	m_pPosCont( 0 ),
	m_pColorCont( 0 ),
	m_pMultCont( 0 ),
	m_pDecayStartCont( 0 )
{
	// empty
}

LightC::~LightC()
{
	delete m_pPosCont;
	delete m_pColorCont;
	delete m_pMultCont;
	delete m_pDecayStartCont;
}

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

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

void
LightC::set_color( const ColorC& rVal )
{
	m_rColor = rVal;
}

const
ColorC&
LightC::get_color()
{
	return m_rColor;
}

void
LightC::set_multiplier( float32 f32Val )
{
	m_f32Multiplier = f32Val;
}

float32
LightC::get_multiplier()
{
	return m_f32Multiplier;
}


void
LightC::set_decay_start( float32 f32Val )
{
	m_f32DecayStart = f32Val;
}

float32
LightC::get_decay_start()
{
	return m_f32DecayStart;
}

void
LightC::set_do_decay( bool bState )
{
	m_bDoDecay = bState;
}

bool
LightC::get_do_decay()
{
	return m_bDoDecay;
}


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

	if( m_pColorCont ) {
		Vector3C	rVec = m_pColorCont->get_value( i32Time );
		m_rColor = ColorC( rVec[0], rVec[1], rVec[2] );
	}

	if( m_pMultCont )
		m_f32Multiplier = m_pMultCont->get_value( i32Time ); 

	if( m_pDecayStartCont )
		m_f32DecayStart = m_pDecayStartCont->get_value( i32Time ); 
}

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

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

void
LightC::set_color_controller( ContVector3C* pCont )
{
	m_pColorCont = pCont;
}

ContVector3C*
LightC::get_color_controller()
{
	return m_pColorCont;
}

void
LightC::set_multiplier_controller( ContFloatC* pCont )
{
	m_pMultCont = pCont;
}

ContFloatC*
LightC::get_multiplier_controller()
{
	return m_pMultCont;
}

void
LightC::set_decay_start_controller( ContFloatC* pCont )
{
	m_pDecayStartCont = pCont;
}

ContFloatC*
LightC::get_decay_start_controller()
{
	return m_pDecayStartCont;
}


enum LightChunksE {
	CHUNK_LIGHT_BASE			= 0x1001,
	CHUNK_LIGHT_CONT_POS		= 0x2000,
	CHUNK_LIGHT_CONT_COLOR		= 0x2001,
	CHUNK_LIGHT_CONT_MULT		= 0x2002,
	CHUNK_LIGHT_CONT_DECAYSTART	= 0x2003,
	CHUNK_LIGHT_DO_DECAY		= 0x3000,
};

const uint32	LIGHT_VERSION_1 = 1;
const uint32	LIGHT_VERSION = 2;


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

	std::string	sStr;
	float32	f32Temp[3];

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

		// color
		f32Temp[0] = m_rColor[0];
		f32Temp[1] = m_rColor[1];
		f32Temp[2] = m_rColor[2];
		ui32Error = pSave->write( f32Temp, sizeof( f32Temp ) );

		// mulltiplier
		ui32Error = pSave->write( &m_f32Multiplier, sizeof( m_f32Multiplier ) );

		// attn start
		ui32Error = pSave->write( &m_f32DecayStart, sizeof( m_f32DecayStart ) );

	pSave->end_chunk();

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

	if( m_pColorCont ) {
		pSave->begin_chunk( CHUNK_LIGHT_CONT_COLOR, LIGHT_VERSION );
			m_pColorCont->save( pSave );
		pSave->end_chunk();
	}

	if( m_pMultCont ) {
		pSave->begin_chunk( CHUNK_LIGHT_CONT_MULT, LIGHT_VERSION );
			m_pMultCont->save( pSave );
		pSave->end_chunk();
	}

	if( m_pDecayStartCont ) {
		pSave->begin_chunk( CHUNK_LIGHT_CONT_DECAYSTART, LIGHT_VERSION );
			m_pDecayStartCont->save( pSave );
		pSave->end_chunk();
	}

	if( m_bDoDecay ) {
		pSave->begin_chunk( CHUNK_LIGHT_DO_DECAY, LIGHT_VERSION );
		pSave->end_chunk();
	}

	return ui32Error;
}

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

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

		switch( pLoad->get_chunk_id() ) {
		case CHUNK_LIGHT_BASE:
			{
				if( pLoad->get_chunk_version() == LIGHT_VERSION_1 ||
					pLoad->get_chunk_version() == LIGHT_VERSION ) {
					// position
					ui32Error = pLoad->read( f32Temp, sizeof( f32Temp ) );
					m_rPos[0] = f32Temp[0];
					m_rPos[1] = f32Temp[1];
					m_rPos[2] = f32Temp[2];

					// color
					ui32Error = pLoad->read( f32Temp, sizeof( f32Temp ) );
					m_rColor[0] = f32Temp[0];
					m_rColor[1] = f32Temp[1];
					m_rColor[2] = f32Temp[2];

					// mult
					ui32Error = pLoad->read( &m_f32Multiplier, sizeof( m_f32Multiplier ) );

					// attn start
					ui32Error = pLoad->read( &m_f32DecayStart, sizeof( m_f32DecayStart ) );
				}
			}
			break;

		case CHUNK_LIGHT_CONT_POS:
			{
				if( pLoad->get_chunk_version() == LIGHT_VERSION ) {
					ContVector3C*	pCont = new ContVector3C;
					ui32Error = pCont->load( pLoad );
					m_pPosCont = pCont;
				}
				else if( pLoad->get_chunk_version() == LIGHT_VERSION_1 ) {
					ControllerC*	pCont = ControllerC::create_new( CONT_TYPE_VECTOR3 );
					ui32Error = pCont->load( pLoad );

					if( ui32Error == IO_OK ) {
						uint32	ui32Type = KEY_SMOOTH;
						if( pCont->get_key_count() )
							ui32Type = pCont->get_key( 0 )->get_flags() & (KEY_LINEAR | KEY_SMOOTH);
						if( (ui32Type != KEY_SMOOTH) && (ui32Type != KEY_LINEAR) )
							ui32Type = KEY_SMOOTH;

						ContVector3C*	pVecCont = new ContVector3C( ui32Type );

						pVecCont->set_start_ort( pCont->get_start_ort() );
						pVecCont->set_end_ort( pCont->get_end_ort() );

						for( uint32 i = 0; i < pCont->get_key_count(); i++ ) {

							KeyC*	pKey = pCont->get_key( i );
							float32	f32Values[KEY_MAXCHANNELS];
							pKey->get_value( f32Values );

							KeyVector3C*	pVecKey = pVecCont->add_key();

							pVecKey->set_time( pKey->get_time() );
							pVecKey->set_value( Vector3C( f32Values[0], f32Values[1], f32Values[2] ) );
							pVecKey->set_tens( pKey->get_tens() );
							pVecKey->set_cont( pKey->get_cont() );
							pVecKey->set_bias( pKey->get_bias() );
							pVecKey->set_ease_in( pKey->get_ease_in() );
							pVecKey->set_ease_out( pKey->get_ease_out() );
						}

						pVecCont->sort_keys();
						pVecCont->prepare();

						m_pPosCont = pVecCont;
					}

					pCont->release();
				}
			}
			break;

		case CHUNK_LIGHT_CONT_COLOR:
			{
				if( pLoad->get_chunk_version() == LIGHT_VERSION ) {
					ContVector3C*	pCont = new ContVector3C;
					ui32Error = pCont->load( pLoad );
					m_pColorCont = pCont;
				}
				else if( pLoad->get_chunk_version() == LIGHT_VERSION_1 ) {
					ControllerC*	pCont = ControllerC::create_new( CONT_TYPE_VECTOR3 );
					ui32Error = pCont->load( pLoad );

					if( ui32Error == IO_OK ) {
						uint32	ui32Type = KEY_SMOOTH;
						if( pCont->get_key_count() )
							ui32Type = pCont->get_key( 0 )->get_flags() & (KEY_LINEAR | KEY_SMOOTH);
						if( (ui32Type != KEY_SMOOTH) && (ui32Type != KEY_LINEAR) )
							ui32Type = KEY_SMOOTH;

						ContVector3C*	pVecCont = new ContVector3C( ui32Type );

						pVecCont->set_start_ort( pCont->get_start_ort() );
						pVecCont->set_end_ort( pCont->get_end_ort() );

						for( uint32 i = 0; i < pCont->get_key_count(); i++ ) {

							KeyC*	pKey = pCont->get_key( i );
							float32	f32Values[KEY_MAXCHANNELS];
							pKey->get_value( f32Values );

							KeyVector3C*	pVecKey = pVecCont->add_key();

							pVecKey->set_time( pKey->get_time() );
							pVecKey->set_value( Vector3C( f32Values[0], f32Values[1], f32Values[2] ) );
							pVecKey->set_tens( pKey->get_tens() );
							pVecKey->set_cont( pKey->get_cont() );
							pVecKey->set_bias( pKey->get_bias() );
							pVecKey->set_ease_in( pKey->get_ease_in() );
							pVecKey->set_ease_out( pKey->get_ease_out() );
						}

						pVecCont->sort_keys();
						pVecCont->prepare();

						m_pColorCont = pVecCont;
					}

					pCont->release();
				}
			}
			break;

		case CHUNK_LIGHT_CONT_MULT:
			{
				if( pLoad->get_chunk_version() == LIGHT_VERSION ) {
					ContFloatC*	pCont = new ContFloatC;
					ui32Error = pCont->load( pLoad );
					m_pMultCont = pCont;
				}
				else if( pLoad->get_chunk_version() == LIGHT_VERSION_1 ) {
					ControllerC*	pCont = ControllerC::create_new( CONT_TYPE_VECTOR3 );
					ui32Error = pCont->load( pLoad );

					if( ui32Error == IO_OK ) {
						uint32	ui32Type = KEY_SMOOTH;
						if( pCont->get_key_count() )
							ui32Type = pCont->get_key( 0 )->get_flags() & (KEY_LINEAR | KEY_SMOOTH);
						if( (ui32Type != KEY_SMOOTH) && (ui32Type != KEY_LINEAR) )
							ui32Type = KEY_SMOOTH;

						ContFloatC*	pFloatCont = new ContFloatC( ui32Type );

						pFloatCont->set_start_ort( pCont->get_start_ort() );
						pFloatCont->set_end_ort( pCont->get_end_ort() );

						for( uint32 i = 0; i < pCont->get_key_count(); i++ ) {

							KeyC*	pKey = pCont->get_key( i );
							float32	f32Values[KEY_MAXCHANNELS];
							pKey->get_value( f32Values );

							KeyFloatC*	pFloatKey = pFloatCont->add_key();

							pFloatKey->set_time( pKey->get_time() );
							pFloatKey->set_value( f32Values[0] );
							pFloatKey->set_tens( pKey->get_tens() );
							pFloatKey->set_cont( pKey->get_cont() );
							pFloatKey->set_bias( pKey->get_bias() );
							pFloatKey->set_ease_in( pKey->get_ease_in() );
							pFloatKey->set_ease_out( pKey->get_ease_out() );
						}

						pFloatCont->sort_keys();
						pFloatCont->prepare();

						m_pMultCont = pFloatCont;
					}

					pCont->release();
				}
			}
			break;

		case CHUNK_LIGHT_CONT_DECAYSTART:
			{
				if( pLoad->get_chunk_version() == LIGHT_VERSION ) {
					ContFloatC*	pCont = new ContFloatC;
					ui32Error = pCont->load( pLoad );
					m_pDecayStartCont = pCont;
				}
				else if( pLoad->get_chunk_version() == LIGHT_VERSION_1 ) {
					ControllerC*	pCont = ControllerC::create_new( CONT_TYPE_VECTOR3 );
					ui32Error = pCont->load( pLoad );

					if( ui32Error == IO_OK ) {
						uint32	ui32Type = KEY_SMOOTH;
						if( pCont->get_key_count() )
							ui32Type = pCont->get_key( 0 )->get_flags() & (KEY_LINEAR | KEY_SMOOTH);
						if( (ui32Type != KEY_SMOOTH) && (ui32Type != KEY_LINEAR) )
							ui32Type = KEY_SMOOTH;

						ContFloatC*	pFloatCont = new ContFloatC( ui32Type );

						pFloatCont->set_start_ort( pCont->get_start_ort() );
						pFloatCont->set_end_ort( pCont->get_end_ort() );

						for( uint32 i = 0; i < pCont->get_key_count(); i++ ) {

							KeyC*	pKey = pCont->get_key( i );
							float32	f32Values[KEY_MAXCHANNELS];
							pKey->get_value( f32Values );

							KeyFloatC*	pFloatKey = pFloatCont->add_key();

							pFloatKey->set_time( pKey->get_time() );
							pFloatKey->set_value( f32Values[0] );
							pFloatKey->set_tens( pKey->get_tens() );
							pFloatKey->set_cont( pKey->get_cont() );
							pFloatKey->set_bias( pKey->get_bias() );
							pFloatKey->set_ease_in( pKey->get_ease_in() );
							pFloatKey->set_ease_out( pKey->get_ease_out() );
						}

						pFloatCont->sort_keys();
						pFloatCont->prepare();

						m_pDecayStartCont = pFloatCont;
					}

					pCont->release();
				}
			}
			break;

		case CHUNK_LIGHT_DO_DECAY:
			{
				if( pLoad->get_chunk_version() == LIGHT_VERSION ) {
					m_bDoDecay = true;
				}
			}
			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;
}
