

#include "Composition.h"
#include "SceneItemC.h"
#include <assert.h>

using namespace PajaTypes;
using namespace Composition;


/*
static
void
TRACE( const char* szFormat, ...  )
{
	char	szMsg[256];
	va_list	rList;
	va_start( rList, szFormat );
	_vsnprintf( szMsg, 255, szFormat, rList );
	va_end( rList );
	OutputDebugString( szMsg );
}
*/


ControllerSampleDataC::ControllerSampleDataC() :
	m_f32Min( -0.5f ), m_f32Max( 0.5f ),
	m_ui32NumCh( 0 )
{
}

ControllerSampleDataC::~ControllerSampleDataC()
{
}

uint32
ControllerSampleDataC::get_sample_count()
{
	if( m_ui32NumCh )
		return m_rSamples.size() / m_ui32NumCh;
	return 0;
}

float32*
ControllerSampleDataC::get_sample( uint32 ui32Num )
{
	if( (m_ui32NumCh * ui32Num) < m_rSamples.size() )
		return &m_rSamples[m_ui32NumCh * ui32Num];
	return &m_rSamples[0];
}

float32
ControllerSampleDataC::get_min() const
{
	return m_f32Min;
}

float32
ControllerSampleDataC::get_max() const
{
	return m_f32Max;
}

void
ControllerSampleDataC::clear()
{
	m_rSamples.clear();
}

void
ControllerSampleDataC::sample_controller( Composition::ParamI* pParam, PajaTypes::int32 i32NumValues, PajaTypes::int32 i32MinTime, PajaTypes::int32 i32TimeStep, bool bUpdateMinMax )
{
	if( !pParam ) {
		return;
	}
	if( i32NumValues < 2 ) {
		return;
	}

	ControllerC*	pCont = pParam->get_controller();

	if( !pCont ) {
		return;
	}

	// dont sample file controllers
	if( pCont->get_type() == CONT_TYPE_FILE )
		return;

	float32			f32Min, f32Max;
	bool			bHasOldSamples = false;
	float32			f32ClampMin[KEY_MAXCHANNELS], f32ClampMax[KEY_MAXCHANNELS];
	bool			bClampValues = false;

	bClampValues = pParam->get_min_max( f32ClampMin, f32ClampMax );

	if( m_rSamples.size() )
		bHasOldSamples = true;

	// create new samples
	uint32	ui32NewNumCh = pCont->get_num_channels();
	uint32	ui32NewNumSamples = i32NumValues;

	assert( ui32NewNumCh && ui32NewNumCh <= KEY_MAXCHANNELS );

	if( (ui32NewNumCh * ui32NewNumSamples) > m_rSamples.size() ) {
		// delete old
		m_rSamples.resize( ui32NewNumCh * ui32NewNumSamples );
	}


	m_ui32NumCh = ui32NewNumCh;


	// init time
	int32	i32Time = i32MinTime;

	// init min/max
	pCont->get_value( &m_rSamples[0], i32Time );
	f32Min = f32Max = m_rSamples[0];

	for( int32 i = 0; i < i32NumValues; i++ ) {

		float32*	pSample = &m_rSamples[i * m_ui32NumCh];

		pCont->get_value( pSample, i32Time );

		// clamp samples, and find min/max
		for( uint32 j = 0; j < m_ui32NumCh; j++ ) {
			if( bClampValues ) {
				if( pSample[j] < f32ClampMin[j] )
					pSample[j] = f32ClampMin[j];
				if( pSample[j] > f32ClampMax[j] )
					pSample[j] = f32ClampMax[j];
			}
			if( pSample[j] < f32Min )
				f32Min = pSample[j];
			if( pSample[j] > f32Max )
				f32Max = pSample[j];
		}

		i32Time += i32TimeStep;
	}

	// if adjusting keys, dont update min/max
	if( !bHasOldSamples || bUpdateMinMax ) {
		// show at least the min/max area
		if( pParam && bClampValues ) {
			f32Min = f32ClampMin[0];
			f32Max = f32ClampMax[0];
			for( uint32 j = 1; j < m_ui32NumCh; j++ ) {
				if( f32ClampMin[j] < f32Min )
					f32Min = f32ClampMin[j];
				if( f32ClampMax[j] > f32Max )
					f32Max = f32ClampMax[j];
			}
		}

		// The min and max are nearly same, calculate the range, so
		// that editing is reasonable
		if( (f32Max - f32Min) < pParam->get_increment() ) {
			// Use the clamping range if possible.
			if( bClampValues ) {
				uint32	i;
				// min
				f32Min = f32ClampMin[0];
				for( i = 1; i < m_ui32NumCh; i++ )
					f32Min = __min( f32Min, f32ClampMin[i] );
				// max
				f32Max = f32ClampMax[0];
				for( i = 1; i < m_ui32NumCh; i++ )
					f32Max = __max( f32Max, f32ClampMax[i] );
			}
			else {
				// If the parameter doesnt have clipping range, use a couple of
				// increments in both ways to expand the range.
				f32Min -= pParam->get_increment() * 5.0f;
				f32Max += pParam->get_increment() * 5.0f;
			}
		}
		m_f32Min = f32Min;
		m_f32Max = f32Max;
	}
}






SceneItemC::SceneItemC() :
	m_pPtr( 0 ),
	m_ui32Type( SCENEITEM_UNKNOWN ),
	m_i32X( 0 ),
	m_i32Y( 0 ),
	m_i32Flags( 0 )
{
	// empty
}

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

uint32
SceneItemC::get_type() const
{
	return m_ui32Type;
}

void
SceneItemC::init( LayerC* pLayer )
{
	m_pPtr = (void*)pLayer;
	m_ui32Type = SCENEITEM_LAYER;
}

void
SceneItemC::init( EffectI* pEffect )
{
	m_pPtr = (void*)pEffect;
	m_ui32Type = SCENEITEM_EFFECT;
}

void
SceneItemC::init( GizmoI* pGizmo )
{
	m_pPtr = (void*)pGizmo;
	m_ui32Type = SCENEITEM_GIZMO;
}

void
SceneItemC::init( ParamI* pParam )
{
	m_pPtr = (void*)pParam;
	m_ui32Type = SCENEITEM_PARAMETER;
}

void
SceneItemC::set_x( int32 i32X )
{
	m_i32X = i32X;
}

int32
SceneItemC::get_x()
{
	return m_i32X;
}

void
SceneItemC::set_y( int32 i32Y )
{
	m_i32Y = i32Y;
}

int32
SceneItemC::get_y()
{
	return m_i32Y;
}

void
SceneItemC::set_height( int32 i32Height )
{
	m_i32Height = i32Height;
}

int32
SceneItemC::get_height()
{
	return m_i32Height;
}

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

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

ControllerSampleDataC*
SceneItemC::get_controller_sampledata()
{
	return &m_rContData;
}

void
SceneItemC::delete_controller_sampledata()
{
	m_rContData.clear();
}


SceneC*
SceneItemC::get_scene()
{
	SceneC*		pScene = 0;
	LayerC*		pLayer = 0;
	EffectI*	pEffect = 0;
	GizmoI*		pGizmo = 0;
	ParamI*		pParameter = 0;

	if( m_ui32Type == SCENEITEM_LAYER ) {
		pLayer = (LayerC*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_EFFECT ) {
		pEffect = (EffectI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_GIZMO ) {
		pGizmo = (GizmoI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_PARAMETER ) {
		pParameter = (ParamI*)m_pPtr;
	}

	if( pParameter )
		pGizmo = pParameter->get_parent();
	if( pGizmo )
		pEffect = pGizmo->get_parent();
	if( pEffect )
		pLayer = pEffect->get_parent();
	if( pLayer )
		pScene = pLayer->get_parent();

	return pScene;
}

LayerC*
SceneItemC::get_layer()
{
	LayerC*		pLayer = 0;
	EffectI*	pEffect = 0;
	GizmoI*		pGizmo = 0;
	ParamI*		pParameter = 0;

	if( m_ui32Type == SCENEITEM_LAYER ) {
		pLayer = (LayerC*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_EFFECT ) {
		pEffect = (EffectI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_GIZMO ) {
		pGizmo = (GizmoI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_PARAMETER ) {
		pParameter = (ParamI*)m_pPtr;
	}

	if( pParameter )
		pGizmo = pParameter->get_parent();
	if( pGizmo )
		pEffect = pGizmo->get_parent();
	if( pEffect )
		pLayer = pEffect->get_parent();

	return pLayer;
}

EffectI*
SceneItemC::get_effect()
{
	EffectI*	pEffect = 0;
	GizmoI*		pGizmo = 0;
	ParamI*		pParameter = 0;

	if( m_ui32Type == SCENEITEM_EFFECT ) {
		pEffect = (EffectI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_GIZMO ) {
		pGizmo = (GizmoI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_PARAMETER ) {
		pParameter = (ParamI*)m_pPtr;
	}

	if( pParameter )
		pGizmo = pParameter->get_parent();
	if( pGizmo )
		pEffect = pGizmo->get_parent();

	return pEffect;
}

GizmoI*
SceneItemC::get_gizmo()
{
	GizmoI*		pGizmo = 0;
	ParamI*		pParameter = 0;

	if( m_ui32Type == SCENEITEM_GIZMO ) {
		pGizmo = (GizmoI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_PARAMETER ) {
		pParameter = (ParamI*)m_pPtr;
	}

	if( pParameter )
		pGizmo = pParameter->get_parent();

	return pGizmo;
}

ParamI*
SceneItemC::get_parameter()
{
	ParamI*		pParameter = 0;

	if( m_ui32Type == SCENEITEM_PARAMETER ) {
		pParameter = (ParamI*)m_pPtr;
	}

	return pParameter;
}

int32
SceneItemC::get_layer_index()
{
	SceneC*		pScene = 0;
	LayerC*		pLayer = 0;
	EffectI*	pEffect = 0;
	GizmoI*		pGizmo = 0;
	ParamI*		pParameter = 0;

	if( m_ui32Type == SCENEITEM_LAYER ) {
		pLayer = (LayerC*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_EFFECT ) {
		pEffect = (EffectI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_GIZMO ) {
		pGizmo = (GizmoI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_PARAMETER ) {
		pParameter = (ParamI*)m_pPtr;
	}

	if( pParameter )
		pGizmo = pParameter->get_parent();
	if( pGizmo )
		pEffect = pGizmo->get_parent();
	if( pEffect )
		pLayer = pEffect->get_parent();
	if( pLayer )
		pScene = pLayer->get_parent();

	if( pScene && pLayer ) {
		for( uint32 i = 0; i < pScene->get_layer_count(); i++ ) {
			if( pScene->get_layer( i ) == pLayer )
				return i;
		}
	}

	return -1;
}

int32
SceneItemC::get_effect_index()
{
	LayerC*		pLayer = 0;
	EffectI*	pEffect = 0;
	GizmoI*		pGizmo = 0;
	ParamI*		pParameter = 0;

	if( m_ui32Type == SCENEITEM_LAYER ) {
		pLayer = (LayerC*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_EFFECT ) {
		pEffect = (EffectI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_GIZMO ) {
		pGizmo = (GizmoI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_PARAMETER ) {
		pParameter = (ParamI*)m_pPtr;
	}

	if( pParameter )
		pGizmo = pParameter->get_parent();
	if( pGizmo )
		pEffect = pGizmo->get_parent();
	if( pEffect )
		pLayer = pEffect->get_parent();

	if( pLayer && pEffect ) {
		for( uint32 i = 0; i < pLayer->get_effect_count(); i++ ) {
			if( pLayer->get_effect( i ) == pEffect )
				return i;
		}
	}

	return -1;
}

int32
SceneItemC::get_gizmo_index()
{
	EffectI*	pEffect = 0;
	GizmoI*		pGizmo = 0;
	ParamI*		pParameter = 0;

	if( m_ui32Type == SCENEITEM_EFFECT ) {
		pEffect = (EffectI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_GIZMO ) {
		pGizmo = (GizmoI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_PARAMETER ) {
		pParameter = (ParamI*)m_pPtr;
	}

	if( pParameter )
		pGizmo = pParameter->get_parent();
	if( pGizmo )
		pEffect = pGizmo->get_parent();

	if( pEffect && pGizmo ) {
		for( uint32 i = 0; i < pEffect->get_gizmo_count(); i++ ) {
			if( pEffect->get_gizmo( i ) == pGizmo )
				return i;
		}
	}

	return -1;
}

int32
SceneItemC::get_parameter_index()
{
	GizmoI*		pGizmo = 0;
	ParamI*		pParameter = 0;

	if( m_ui32Type == SCENEITEM_GIZMO ) {
		pGizmo = (GizmoI*)m_pPtr;
	}
	else if( m_ui32Type == SCENEITEM_PARAMETER ) {
		pParameter = (ParamI*)m_pPtr;
	}

	if( pParameter )
		pGizmo = pParameter->get_parent();

	if( pGizmo && pParameter ) {
		for( uint32 i = 0; i < pGizmo->get_parameter_count(); i++ ) {
			if( pGizmo->get_parameter( i ) == pParameter )
				return i;
		}
	}

	return -1;
}

bool
SceneItemC::operator==( const SceneItemC& rItem ) const
{
	if( m_ui32Type == rItem.m_ui32Type && m_pPtr == rItem.m_pPtr )
		return true;
	return false;
}

void
SceneItemC::sample_controller( PajaTypes::int32 i32NumValues, PajaTypes::int32 i32MinTime, PajaTypes::int32 i32TimeStep, bool bUpdateMinMax )
{
	ParamI*	pParam = get_parameter();
	if( pParam ) {
		// adjust time
		i32MinTime -= get_layer()->get_timesegment()->get_segment_start();
		i32MinTime -= get_effect()->get_timesegment()->get_segment_start();
		// sample
		m_rContData.sample_controller( pParam, i32NumValues, i32MinTime, i32TimeStep, bUpdateMinMax );
	}
}
