

#include "PajaTypes.h"
#include "ContBoolC.h"
#include "DataBlockI.h"
#include "EditableI.h"
#include "KeyC.h"
#include <math.h>
#include <assert.h>
#include <stdlib.h>		//qsort
#include "FileIO.h"
#include "QuatC.h"

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



const uint32		CONTROLLER_VERSION = 1;

enum ContBoolChunksE {
	CHUNK_CONTROLLER_BASE = 0x1000,
	CHUNK_CONTROLLER_KEY = 0x2000,
};

const PajaTypes::uint8		KEY_VERSION = 1;

//
//
// Key
//
//

KeyBoolC::KeyBoolC()
{
	// empty
}

KeyBoolC::~KeyBoolC()
{
	// empty
}

int32
KeyBoolC::get_time()
{
	return m_i32Time;
}

void
KeyBoolC::set_time( int32 i32Time )
{
	m_i32Time = i32Time;
}


uint32
KeyBoolC::save( SaveC* pSave )
{
	uint32	ui32Error = IO_OK;
	uint8	ui8Version = KEY_VERSION;

	// version
	ui32Error = pSave->write( &ui8Version, sizeof( ui8Version ) );
	// time
	ui32Error = pSave->write( &m_i32Time, sizeof( m_i32Time ) );

	return ui32Error;
}

uint32
KeyBoolC::load( LoadC* pLoad )
{
	uint32	ui32Error = IO_OK;
	uint8	ui8Version;

	// version
	ui32Error = pLoad->read( &ui8Version, sizeof( ui8Version ) );

	if( ui8Version == KEY_VERSION ) {
		// time
		ui32Error = pLoad->read( &m_i32Time, sizeof( m_i32Time ) );
	}

	return ui32Error;
}


//
//
// Controller
//
//

ContBoolC::ContBoolC() :
	m_bStartVal( false )
{
	// empty
}

ContBoolC::~ContBoolC()
{
	// delete keys
	for( uint32 i = 0; i < m_rKeys.size(); i++ )
		delete m_rKeys[i];
	m_rKeys.clear();
}

int32
ContBoolC::get_key_count()
{
	return m_rKeys.size();
}

KeyBoolC*
ContBoolC::get_key( int32 i32Index )
{
	if( i32Index >= 0 && i32Index < m_rKeys.size() )
		return m_rKeys[i32Index];
	return 0;
}

void
ContBoolC::del_key( int32 i32Index )
{
	assert( i32Index >= 0 && i32Index < m_rKeys.size() );

	KeyBoolC*	pKey = m_rKeys[i32Index];
	delete pKey;
	m_rKeys.erase( m_rKeys.begin() + i32Index );
}

KeyBoolC*
ContBoolC::add_key()
{
	KeyBoolC*	pKey = new KeyBoolC;
	m_rKeys.push_back( pKey );
	return pKey;
}


static
int
compare_func( const void* vpParam1, const void* vpParam2 )
{
	KeyBoolC*	pKey1 = *(KeyBoolC**)vpParam1;
	KeyBoolC*	pKey2 = *(KeyBoolC**)vpParam2;

	if( pKey1->get_time() < pKey2->get_time() )
		return -1;

	return 1;
}

void
ContBoolC::sort_keys()
{
	qsort( (void*)&m_rKeys[0], m_rKeys.size(), sizeof( KeyBoolC* ), compare_func );
}

void
ContBoolC::set_start_val( bool bVal )
{
	m_bStartVal = bVal;
}

bool
ContBoolC::get_start_val() const
{
	return m_bStartVal;
}

bool
ContBoolC::get_value( int32 i32Time ) const
{
	bool	bVal = m_bStartVal;

	if( m_rKeys.size() == 0 )
		return 0;

/*
		for (int i=0; i<keys.Count(); i++) {
			if (keys[i].time>t) break;
			onOff = !onOff;
			}
*/

	for( uint32 i = 0; i < m_rKeys.size(); i++ ) {
		if( m_rKeys[i]->get_time() > i32Time )
			break;
		bVal = !bVal;
	}

	return bVal;
}


int32
ContBoolC::get_min_time() const
{
	if( m_rKeys.size() )
		return m_rKeys[0]->get_time();
	return 0;
}

int32
ContBoolC::get_max_time() const
{
	if( m_rKeys.size() )
		return m_rKeys[m_rKeys.size() - 1]->get_time();
	return 0;
}


uint32
ContBoolC::save( SaveC* pSave )
{
	uint32	ui32Error = IO_OK;
	uint8	ui8Temp;

	pSave->begin_chunk( CHUNK_CONTROLLER_BASE, CONTROLLER_VERSION );
		// start val
		ui8Temp = (uint8)m_bStartVal ? 1 : 0;
		ui32Error = pSave->write( &ui8Temp, sizeof( ui8Temp ) );
	pSave->end_chunk();

	// save keys
	for( uint32 i = 0; i < m_rKeys.size(); i++ ) {
		pSave->begin_chunk( CHUNK_CONTROLLER_KEY, CONTROLLER_VERSION );
		ui32Error = m_rKeys[i]->save( pSave );
		pSave->end_chunk();
	}

	return ui32Error;
}

uint32
ContBoolC::load( LoadC* pLoad )
{
	uint32	ui32Error = IO_OK;

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

		switch( pLoad->get_chunk_id() ) {
		case CHUNK_CONTROLLER_BASE:
			{
				if( pLoad->get_chunk_version() == CONTROLLER_VERSION ) {
					uint8	ui8Temp;
					// start val
					ui32Error = pLoad->read( &ui8Temp, sizeof( ui8Temp ) );
					m_bStartVal = ui8Temp == 1 ? true : false;
				}
			}
			break;
		case CHUNK_CONTROLLER_KEY:
			{
				if( pLoad->get_chunk_version() == CONTROLLER_VERSION ) {
					KeyBoolC*	pKey = new KeyBoolC;
					ui32Error = pKey->load( pLoad );
					m_rKeys.push_back( pKey );
				}
			}
			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;

	sort_keys();

	return IO_OK;
}

