
//#include <windows.h>
//#include <stdio.h>

#include "KeyC.h"
#include "DataBlockI.h"
#include "EditableI.h"
#include "UndoC.h"
#include "PajaTypes.h"
#include <vector>
#include "FileIO.h"



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

const PajaTypes::uint8		KEY_VERSION_1 = 1;
const PajaTypes::uint8		KEY_VERSION = 2;


KeyC::KeyC() :
	m_i32Time( 0 ),
	m_i32Flags( KEY_NOFLAGS )
{
	// empty
}

KeyC::KeyC( EditableI* pOriginal ) :
	EditableI( pOriginal ),
	m_i32Time( 0 ),
	m_i32Flags( KEY_NOFLAGS )
{
	// empty
}

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

KeyC*
KeyC::create_new()
{
	return new KeyC;
}

DataBlockI*
KeyC::create()
{
	return new KeyC;
}

DataBlockI*
KeyC::create( EditableI* pOriginal )
{
	return new KeyC( pOriginal );
}

void
KeyC::copy( EditableI* pEditable )
{
	KeyC*	pKey = (KeyC*)pEditable;

	m_i32Time = pKey->m_i32Time;
	m_i32Flags = pKey->m_i32Flags;
}

void
KeyC::restore( EditableI* pEditable )
{
	KeyC*	pKey = (KeyC*)pEditable;

	m_i32Time = pKey->m_i32Time;
	m_i32Flags = pKey->m_i32Flags;
}

PluginClass::SuperClassIdC
KeyC::get_base_class_id() const
{
	return BASECLASS_KEY;
}

PajaTypes::int32
KeyC::get_time()
{
	return m_i32Time;
}

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

void
KeyC::set_flags( int32 i32Flags )
{
	m_i32Flags = i32Flags;
}

void
KeyC::add_flags( int32 i32Flags )
{
	m_i32Flags |= i32Flags;
}

void
KeyC::del_flags( int32 i32Flags )
{
	m_i32Flags &= ~i32Flags;
}

void
KeyC::toggle_flags( int32 i32Flags )
{
	m_i32Flags ^= i32Flags;
}

int32
KeyC::get_flags()
{
	return m_i32Flags;
}

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

	uint8	ui8Version = KEY_VERSION;
	uint8	ui8Temp;

	// version
	ui32Error = pSave->write( &ui8Version, sizeof( ui8Version ) );
	// time
	ui32Error = pSave->write( &m_i32Time, sizeof( m_i32Time ) );
	// flags (with out select bit
	ui8Temp = (uint8)(m_i32Flags & ~KEY_SELECTED);
	ui32Error = pSave->write( &ui8Temp, sizeof( ui8Temp ) );

	return ui32Error;
}

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

	uint8	ui8Version;
	uint8	ui8Temp;

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

	if( ui8Version == KEY_VERSION_1 ) {
		uint32	ui32NumChannels = 0;
		// channel count
		ui32Error = pLoad->read( &ui8Temp, sizeof( ui8Temp ) );
		// values
		ui32NumChannels = ui8Temp;
		float32*	pTemp = new float32[ui32NumChannels];
		if( ui32NumChannels )
			ui32Error = pLoad->read( pTemp, ui32NumChannels * sizeof( float32 ) );
		delete [] pTemp;
		// time
		ui32Error = pLoad->read( &m_i32Time, sizeof( m_i32Time ) );
		// flags (with out select bit
		ui32Error = pLoad->read( &ui8Temp, sizeof( ui8Temp ) );
		m_i32Flags = ui8Temp;
	}
	else if( ui8Version == KEY_VERSION ) {
		// time
		ui32Error = pLoad->read( &m_i32Time, sizeof( m_i32Time ) );
		// flags (with out select bit
		ui32Error = pLoad->read( &ui8Temp, sizeof( ui8Temp ) );
		m_i32Flags = ui8Temp;
	}

	return ui32Error;
}


//
//
// Float key
//
//

FloatKeyC::FloatKeyC() :
	m_pValues( 0 ),
	m_i32NumChannels( 0 ),
	m_f32EaseIn( 0 ),
	m_f32EaseOut( 0 ),
	m_f32Tens( 0 ),
	m_f32Cont( 0 ),
	m_f32Bias( 0 )
{
	m_i32Flags = KEY_LINEAR;
}

FloatKeyC::FloatKeyC( int32 i32NumChannels ) :
	m_pValues( 0 ),
	m_i32NumChannels( 0 ),
	m_f32EaseIn( 0 ),
	m_f32EaseOut( 0 ),
	m_f32Tens( 0 ),
	m_f32Cont( 0 ),
	m_f32Bias( 0 )
{
	m_i32Flags = KEY_LINEAR;

	if( i32NumChannels )
		m_pValues = new float32[3 * i32NumChannels];

	m_i32NumChannels = i32NumChannels;

	for( int i = 0; i < m_i32NumChannels * 3; i++ )
		m_pValues[i] = 0;

}

FloatKeyC::FloatKeyC( EditableI* pOriginal ) :
	KeyC( pOriginal ),
	m_pValues( 0 ),
	m_i32NumChannels( 0 ),
	m_f32EaseIn( 0 ),
	m_f32EaseOut( 0 ),
	m_f32Tens( 0 ),
	m_f32Cont( 0 ),
	m_f32Bias( 0 )
{
	// empty
}

FloatKeyC::~FloatKeyC()
{
	delete m_pValues;
}

FloatKeyC*
FloatKeyC::create_new()
{
	return new FloatKeyC;
}

FloatKeyC*
FloatKeyC::create_new( int32 i32NumChannels )
{
	return new FloatKeyC( i32NumChannels );
}


DataBlockI*
FloatKeyC::create()
{
	return new FloatKeyC;
}

DataBlockI*
FloatKeyC::create( EditableI* pOriginal )
{
	return new FloatKeyC( pOriginal );
}

void
FloatKeyC::copy( EditableI* pEditable )
{
	FloatKeyC*	pKey = (FloatKeyC*)pEditable;

	if( m_i32NumChannels )
		delete m_pValues;

	m_i32Time = pKey->m_i32Time;
	m_i32Flags = pKey->m_i32Flags;
	m_i32NumChannels = pKey->m_i32NumChannels;

	m_f32EaseIn = pKey->m_f32EaseIn;
	m_f32EaseOut = pKey->m_f32EaseOut;
	m_f32Tens = pKey->m_f32Tens;
	m_f32Cont = pKey->m_f32Cont;
	m_f32Bias = pKey->m_f32Bias;

	if( m_i32NumChannels ) {
		m_pValues = new float32[3 * m_i32NumChannels];
		for( int i = 0; i < 3 * m_i32NumChannels; i++ )
			m_pValues[i] = pKey->m_pValues[i];
	}
	else
		m_pValues = 0;
}

void
FloatKeyC::restore( EditableI* pEditable )
{
	FloatKeyC*	pKey = (FloatKeyC*)pEditable;

	if( m_i32NumChannels )
		delete m_pValues;

	m_i32Time = pKey->m_i32Time;
	m_i32Flags = pKey->m_i32Flags;
	m_i32NumChannels = pKey->m_i32NumChannels;

	m_f32EaseIn = pKey->m_f32EaseIn;
	m_f32EaseOut = pKey->m_f32EaseOut;
	m_f32Tens = pKey->m_f32Tens;
	m_f32Cont = pKey->m_f32Cont;
	m_f32Bias = pKey->m_f32Bias;

	if( m_i32NumChannels ) {
		m_pValues = new float32[3 * m_i32NumChannels];
		for( int i = 0; i < 3 * m_i32NumChannels; i++ )
			m_pValues[i] = pKey->m_pValues[i];
	}
	else
		m_pValues = 0;
}

float32
FloatKeyC::get_ease_in()
{
	return m_f32EaseIn;
}

float32
FloatKeyC::get_ease_out()
{
	return m_f32EaseOut;
}

float32
FloatKeyC::get_tens()
{
	return m_f32Tens;
}

float32
FloatKeyC::get_cont()
{
	return m_f32Cont;
}

float32
FloatKeyC::get_bias()
{
	return m_f32Bias;
}

void
FloatKeyC::set_ease_in( float32 f32EaseIn )
{
	m_f32EaseIn = f32EaseIn;
}

void
FloatKeyC::set_ease_out( float32 f32EaseOut )
{
	m_f32EaseOut = f32EaseOut;
}

void
FloatKeyC::set_tens( float32 f32Tens )
{
	m_f32Tens = f32Tens;
}

void
FloatKeyC::set_cont( float32 f32Cont )
{
	m_f32Cont = f32Cont;
}

void
FloatKeyC::set_bias( float32 f32Bias )
{
	m_f32Bias = f32Bias;
}

void
FloatKeyC::get_value( float32* pValues )
{
	for( int32 i = 0; i < m_i32NumChannels; i++ )
		pValues[i] = m_pValues[i];
}

void
FloatKeyC::set_value( const float32* pValues )
{
	for( int32 i = 0; i < m_i32NumChannels; i++ )
		m_pValues[i] = pValues[i];
}

void
FloatKeyC::get_in_tan( float32* pValues )
{
	float32*	pSrc = &m_pValues[m_i32NumChannels];
	for( int32 i = 0; i < m_i32NumChannels; i++ )
		pValues[i] = pSrc[i];
}

void
FloatKeyC::set_in_tan( const float32* pValues )
{
	float32*	pDst = &m_pValues[m_i32NumChannels];
	for( int32 i = 0; i < m_i32NumChannels; i++ )
		pDst[i] = pValues[i];
}

void
FloatKeyC::get_out_tan( float32* pValues )
{
	float32*	pSrc = &m_pValues[2 * m_i32NumChannels];
	for( int32 i = 0; i < m_i32NumChannels; i++ )
		pValues[i] = pSrc[i];
}

void
FloatKeyC::set_out_tan( const float32* pValues )
{
	float32*	pDst = &m_pValues[2 * m_i32NumChannels];
	for( int32 i = 0; i < m_i32NumChannels; i++ )
		pDst[i] = pValues[i];
}

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

	uint8	ui8Version = KEY_VERSION;
	uint8	ui8Temp;

	// version
	ui32Error = pSave->write( &ui8Version, sizeof( ui8Version ) );
	// channel count
	ui8Temp = (uint8)m_i32NumChannels;
	ui32Error = pSave->write( &ui8Temp, sizeof( ui8Temp ) );
	// values
	if( m_i32NumChannels )
		ui32Error = pSave->write( m_pValues, m_i32NumChannels * sizeof( float32 ) );
	// time
	ui32Error = pSave->write( &m_i32Time, sizeof( m_i32Time ) );
	// flags (with out select bit
	ui8Temp = (uint8)(m_i32Flags & ~KEY_SELECTED);
	ui32Error = pSave->write( &ui8Temp, sizeof( ui8Temp ) );
	// ease in
	ui32Error = pSave->write( &m_f32EaseIn, sizeof( m_f32EaseIn ) );
	// ease out
	ui32Error = pSave->write( &m_f32EaseOut, sizeof( m_f32EaseOut ) );
	// tens
	ui32Error = pSave->write( &m_f32Tens, sizeof( m_f32Tens ) );
	// cont
	ui32Error = pSave->write( &m_f32Cont, sizeof( m_f32Cont ) );
	// bias
	ui32Error = pSave->write( &m_f32Bias, sizeof( m_f32Bias ) );

	return ui32Error;
}

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

	uint8	ui8Version;
	uint8	ui8Temp;

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

	if( ui8Version <= KEY_VERSION ) {
		// channel count
		ui32Error = pLoad->read( &ui8Temp, sizeof( ui8Temp ) );
		m_i32NumChannels = ui8Temp;
		// values
		if( m_i32NumChannels )
			ui32Error = pLoad->read( m_pValues, m_i32NumChannels * sizeof( float32 ) );
		// time
		ui32Error = pLoad->read( &m_i32Time, sizeof( m_i32Time ) );
		// flags (with out select bit
		ui32Error = pLoad->read( &ui8Temp, sizeof( ui8Temp ) );
		m_i32Flags = ui8Temp;
		// ease in
		ui32Error = pLoad->read( &m_f32EaseIn, sizeof( m_f32EaseIn ) );
		// ease out
		ui32Error = pLoad->read( &m_f32EaseOut, sizeof( m_f32EaseOut ) );
		// tens
		ui32Error = pLoad->read( &m_f32Tens, sizeof( m_f32Tens ) );
		// cont
		ui32Error = pLoad->read( &m_f32Cont, sizeof( m_f32Cont ) );
		// bias
		ui32Error = pLoad->read( &m_f32Bias, sizeof( m_f32Bias ) );
	}

	return ui32Error;
}


//
//
// File key
//
//

FileKeyC::FileKeyC() :
	m_pFileHandle( 0 ),
	m_i32TimeOffset( 0 ),
	m_f32TimeScale( 1 )
{
	m_i32Flags = KEY_FILE;
}


FileKeyC::FileKeyC( EditableI* pOriginal ) :
	KeyC( pOriginal ),
	m_pFileHandle( 0 ),
	m_i32TimeOffset( 0 ),
	m_f32TimeScale( 1 )
{
	m_i32Flags = KEY_FILE;
}

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

FileKeyC*
FileKeyC::create_new()
{
	return new FileKeyC;
}


DataBlockI*
FileKeyC::create()
{
	return new FileKeyC;
}

DataBlockI*
FileKeyC::create( EditableI* pOriginal )
{
	return new FileKeyC( pOriginal );
}

void
FileKeyC::copy( EditableI* pEditable )
{
	FileKeyC*	pKey = (FileKeyC*)pEditable;

	m_i32Time = pKey->m_i32Time;
	m_i32Flags = pKey->m_i32Flags;

	m_pFileHandle = pKey->m_pFileHandle;
	m_i32TimeOffset = pKey->m_i32TimeOffset;
	m_f32TimeScale = pKey->m_f32TimeScale;
}

void
FileKeyC::restore( EditableI* pEditable )
{
	FileKeyC*	pKey = (FileKeyC*)pEditable;

	m_i32Time = pKey->m_i32Time;
	m_i32Flags = pKey->m_i32Flags;

	m_pFileHandle = pKey->m_pFileHandle;
	m_i32TimeOffset = pKey->m_i32TimeOffset;
	m_f32TimeScale = pKey->m_f32TimeScale;
}


void
FileKeyC::set_file_handle( FileHandleC* pHandle )
{
	m_pFileHandle = pHandle;
}

FileHandleC*
FileKeyC::get_file_handle()
{
	return m_pFileHandle;
}
		
void
FileKeyC::set_time_scale( float32 f32Scale )
{
	m_f32TimeScale = f32Scale;
}

float32
FileKeyC::get_time_scale() const
{
	return m_f32TimeScale;
}

void
FileKeyC::set_time_offset( int32 i32Offset )
{
	m_i32TimeOffset = i32Offset;
}

int32
FileKeyC::get_time_offset() const
{
	return m_i32TimeOffset;
}

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

	uint8	ui8Version = KEY_VERSION;
	uint8	ui8Temp;

	// version
	ui32Error = pSave->write( &ui8Version, sizeof( ui8Version ) );
	// time
	ui32Error = pSave->write( &m_i32Time, sizeof( m_i32Time ) );
	// flags (with out select bit
	ui8Temp = (uint8)(m_i32Flags & ~KEY_SELECTED);
	ui32Error = pSave->write( &ui8Temp, sizeof( ui8Temp ) );
	// time offset
	ui32Error = pSave->write( &m_i32TimeOffset, sizeof( m_i32TimeOffset ) );
	// time scale
	ui32Error = pSave->write( &m_f32TimeScale, sizeof( m_f32TimeScale ) );
	// file handle
	uint32	ui32FileId = 0xffffffff;
	if( m_pFileHandle ) {
		ui32FileId = m_pFileHandle->get_id();
	}
	ui32Error = pSave->write( &ui32FileId, sizeof( ui32FileId ) );

	return ui32Error;
}

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

	uint8	ui8Version;
	uint8	ui8Temp;

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

	if( ui8Version == KEY_VERSION ) {
		// time
		ui32Error = pLoad->read( &m_i32Time, sizeof( m_i32Time ) );
		// flags (with out select bit
		ui32Error = pLoad->read( &ui8Temp, sizeof( ui8Temp ) );
		m_i32Flags = ui8Temp;
		// timeoffset
		ui32Error = pLoad->read( &m_i32TimeOffset, sizeof( m_i32TimeOffset ) );
		// time scale
		ui32Error = pLoad->read( &m_f32TimeScale, sizeof( m_f32TimeScale ) );
		// file handle
		uint32	ui32FileHandle;
		ui32Error = pLoad->read( &ui32FileHandle, sizeof( ui32FileHandle ) );

		if( ui32FileHandle != 0xffffffff )
			pLoad->add_file_handle_patch( (void**)&m_pFileHandle, ui32FileHandle );
		else
			m_pFileHandle = 0;
	}

	return ui32Error;
}

