#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 Import;
using namespace FileIO;


LightC::LightC() :
	m_ui32LightType( LIGHT_OMNI ),
	m_ui32DecayType( DECAY_NONE ),
	m_rColor( 1, 1, 1 ),
	m_f32Multiplier( 1.0f ),
	m_f32FallOff( 0 ),
	m_f32Hotspot( 0 ),
	m_bCastShadows( false ),
	m_pProjectionTex( 0 ),
	m_pPosCont( 0 ),
	m_pTgtCont( 0 ),
	m_pColorCont( 0 ),
	m_pMultiplierCont( 0 ),
	m_pFalloffCont( 0 ),
	m_pHotspotCont( 0 ),
	m_pDecayCont( 0 )
{
	// empty
}

LightC::~LightC()
{
	delete m_pPosCont;
	delete m_pTgtCont;
	delete m_pColorCont;
	delete m_pMultiplierCont;
	delete m_pFalloffCont;
	delete m_pHotspotCont;
	delete m_pDecayCont;
}

int32
LightC::get_type()
{
	return CGITEM_LIGHT;
}

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

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

void
LightC::set_target( const Vector3C& rPos )
{
	m_rTgt = rPos;
}

const
Vector3C&
LightC::get_target()
{
	return m_rTgt;
}

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_falloff( float32 f32Val )
{
	m_f32FallOff = f32Val;
}

float32
LightC::get_falloff()
{
	return m_f32FallOff;
}


void
LightC::set_hotspot( float32 f32Val )
{
	m_f32Hotspot = f32Val;
}

float32
LightC::get_hotspot()
{
	return m_f32Hotspot;
}


void
LightC::set_decay( float32 f32Val )
{
	m_f32Decay = f32Val;
}

float32
LightC::get_decay()
{
	return m_f32Decay;
}


void
LightC::set_decay_type( uint32 ui32Type )
{
	m_ui32DecayType = ui32Type;
}

uint32
LightC::get_decay_type()
{
	return m_ui32DecayType;
}

void
LightC::set_light_type( uint32 ui32Type )
{
	m_ui32LightType = ui32Type;
}

uint32
LightC::get_light_type()
{
	return m_ui32LightType;
}

void
LightC::set_cast_shadows( bool bState )
{
	m_bCastShadows = bState;
}

bool
LightC::get_cast_shadows() const
{
	return m_bCastShadows;
}

void
LightC::set_projection_texture( FileHandleC* pHandle )
{
	m_pProjectionTex = pHandle;
}

FileHandleC*
LightC::get_projection_texture() const
{
	return m_pProjectionTex;
}


void
LightC::eval_state( int32 i32Time )
{
	if( m_pPosCont )
		m_rPos = m_pPosCont->get_value( i32Time );
	if( m_pTgtCont )
		m_rTgt = m_pTgtCont->get_value( i32Time );
	if( m_pMultiplierCont )
		m_f32Multiplier = m_pMultiplierCont->get_value( i32Time );
	if( m_pFalloffCont )
		m_f32FallOff = m_pFalloffCont->get_value( i32Time );
	if( m_pHotspotCont )
		m_f32Hotspot = m_pHotspotCont->get_value( i32Time );
	if( m_pDecayCont )
		m_f32Decay = m_pDecayCont->get_value( i32Time );
	if( m_pColorCont ) {
		Vector3C	rCol = m_pColorCont->get_value( i32Time );
		m_rColor[0] = rCol[0];
		m_rColor[1] = rCol[1];
		m_rColor[2] = rCol[2];
	}

	m_rTM.set_trans( m_rPos );
}

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

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

void
LightC::set_target_controller( ContVector3C* pCont )
{
	m_pTgtCont = pCont;
}

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

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

void
LightC::set_falloff_controller( ContFloatC* pCont )
{
	m_pFalloffCont = pCont;
}

void
LightC::set_hotspot_controller( ContFloatC* pCont )
{
	m_pHotspotCont = pCont;
}

void
LightC::set_decay_controller( ContFloatC* pCont )
{
	m_pDecayCont = pCont;
}

void
LightC::update_dependencies( std::vector<ScenegraphItemI*> rScenegraph )
{
}


enum LightChunksE {
	CHUNK_LIGHT_BASE			= 0x1000,
	CHUNK_LIGHT_STATIC			= 0x1001,
	CHUNK_LIGHT_CONT_POS		= 0x2000,
	CHUNK_LIGHT_CONT_TGT		= 0x2001,
	CHUNK_LIGHT_CONT_COLOR		= 0x2002,
	CHUNK_LIGHT_CONT_MULT		= 0x2003,
	CHUNK_LIGHT_CONT_FALLOFF	= 0x2004,
	CHUNK_LIGHT_CONT_HOTSPOT	= 0x2005,
	CHUNK_LIGHT_CONT_DECAY		= 0x2006,
};

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];
	uint8		ui8Tmp;
	uint32		ui32Temp;

	// light base
	pSave->begin_chunk( CHUNK_LIGHT_BASE, LIGHT_VERSION );
		ScenegraphItemI::save( pSave );
	pSave->end_chunk();

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

		// target
		f32Temp[0] = m_rTgt[0];
		f32Temp[1] = m_rTgt[1];
		f32Temp[2] = m_rTgt[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 ) );

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

		// hotspot
		ui32Error = pSave->write( &m_f32Hotspot, sizeof( m_f32Hotspot ) );

		// falloff
		ui32Error = pSave->write( &m_f32FallOff, sizeof( m_f32FallOff ) );

		// decay
		ui32Error = pSave->write( &m_f32Decay, sizeof( m_f32Decay ) );

		// light type
		ui32Error = pSave->write( &m_ui32LightType, sizeof( m_ui32LightType ) );

		// decay type
		ui32Error = pSave->write( &m_ui32DecayType, sizeof( m_ui32DecayType ) );

		// cast shadows
		ui8Tmp = m_bCastShadows ? 1 : 0;
		ui32Error = pSave->write( &ui8Tmp, sizeof( ui8Tmp ) );

		// Tex handle
		if( m_pProjectionTex )
			ui32Temp = m_pProjectionTex->get_id();
		else
			ui32Temp = 0xffffffff;
		ui32Error = pSave->write( &ui32Temp, sizeof( ui32Temp ) );

	pSave->end_chunk();

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

	// tgt controller
	if( m_pTgtCont ) {
		pSave->begin_chunk( CHUNK_LIGHT_CONT_TGT, LIGHT_VERSION );
			m_pTgtCont->save( pSave );
		pSave->end_chunk();
	}

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

	// mult controller
	if( m_pMultiplierCont ) {
		pSave->begin_chunk( CHUNK_LIGHT_CONT_MULT, LIGHT_VERSION );
			m_pMultiplierCont->save( pSave );
		pSave->end_chunk();
	}

	// hotspot controller
	if( m_pHotspotCont ) {
		pSave->begin_chunk( CHUNK_LIGHT_CONT_HOTSPOT, LIGHT_VERSION );
			m_pHotspotCont->save( pSave );
		pSave->end_chunk();
	}

	// falloff controller
	if( m_pFalloffCont ) {
		pSave->begin_chunk( CHUNK_LIGHT_CONT_FALLOFF, LIGHT_VERSION );
			m_pFalloffCont->save( pSave );
		pSave->end_chunk();
	}

	// decay controller
	if( m_pDecayCont ) {
		pSave->begin_chunk( CHUNK_LIGHT_CONT_DECAY, LIGHT_VERSION );
			m_pDecayCont->save( pSave );
		pSave->end_chunk();
	}

	return ui32Error;
}

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

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

		switch( pLoad->get_chunk_id() ) {
		case CHUNK_LIGHT_BASE:
			if( pLoad->get_chunk_version() == LIGHT_VERSION )
				ScenegraphItemI::load( pLoad );
			break;

		case CHUNK_LIGHT_STATIC:
			if( pLoad->get_chunk_version() == LIGHT_VERSION_1 ) {
				// 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 ) );
			}
			else if( 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];

				// target
				ui32Error = pLoad->read( f32Temp, sizeof( f32Temp ) );
				m_rTgt[0] = f32Temp[0];
				m_rTgt[1] = f32Temp[1];
				m_rTgt[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 ) );

				// hotspot
				ui32Error = pLoad->read( &m_f32Hotspot, sizeof( m_f32Hotspot ) );

				// falloff
				ui32Error = pLoad->read( &m_f32FallOff, sizeof( m_f32FallOff ) );

				// decay
				ui32Error = pLoad->read( &m_f32Decay, sizeof( m_f32Decay ) );

				// light type
				ui32Error = pLoad->read( &m_ui32LightType, sizeof( m_ui32LightType ) );

				// decay type
				ui32Error = pLoad->read( &m_ui32DecayType, sizeof( m_ui32DecayType ) );

				// cast shadows
				ui32Error = pLoad->read( &ui8Tmp, sizeof( ui8Tmp ) );
				m_bCastShadows = ui8Tmp ? true : false;

				// texture handle
				ui32Error = pLoad->read( &ui32Temp, sizeof( ui32Temp ) );
				if( ui32Temp != 0xffffffff )
					pLoad->add_file_handle_patch( (void**)&m_pProjectionTex, ui32Temp );
			}
			break;

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

		case CHUNK_LIGHT_CONT_TGT:
			if( pLoad->get_chunk_version() == LIGHT_VERSION ) {
				ContVector3C*	pCont = new ContVector3C;
				ui32Error = pCont->load( pLoad );
				m_pTgtCont = pCont;
			}
			break;

		case CHUNK_LIGHT_CONT_COLOR:
			if( pLoad->get_chunk_version() == LIGHT_VERSION ) {
				ContVector3C*	pCont = new ContVector3C;
				ui32Error = pCont->load( pLoad );
				m_pColorCont = pCont;
			}
			break;

		case CHUNK_LIGHT_CONT_MULT:
			if( pLoad->get_chunk_version() == LIGHT_VERSION ) {
				ContFloatC*	pCont = new ContFloatC;
				ui32Error = pCont->load( pLoad );
				m_pMultiplierCont = pCont;
			}
			break;

		case CHUNK_LIGHT_CONT_HOTSPOT:
			if( pLoad->get_chunk_version() == LIGHT_VERSION ) {
				ContFloatC*	pCont = new ContFloatC;
				ui32Error = pCont->load( pLoad );
				m_pHotspotCont = pCont;
			}
			break;

		case CHUNK_LIGHT_CONT_FALLOFF:
			if( pLoad->get_chunk_version() == LIGHT_VERSION ) {
				ContFloatC*	pCont = new ContFloatC;
				ui32Error = pCont->load( pLoad );
				m_pFalloffCont = pCont;
			}
			break;

		case CHUNK_LIGHT_CONT_DECAY:
			if( pLoad->get_chunk_version() == LIGHT_VERSION ) {
				ContFloatC*	pCont = new ContFloatC;
				ui32Error = pCont->load( pLoad );
				m_pDecayCont = pCont;
			}
			break;

		default:
			assert( 0 );
		}

		pLoad->close_chunk();

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

	return ui32Error;
}
