
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Human_AIAnimStateData.cpp
// Author : Will Plano
// Date   : 27/09/2007
//
// Copyright (C) 2007 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"

// This file's header...
#include "Actor/Vertebrates/Human/AVP_Human_AIAnimStateData.h"

// Asura
#include "Blueprint/Asura_Blueprint_System.h"
#include "Core/Asura_Hash.h"
#include "Dynamics/Asura_Collision_Object.h"

// AVP
#include "Actor/AVP_Actor_AnimStateData.h"
#include "Blueprint/AVP_Blueprint_HashIDs.h"
#include "Physics/AVP_Collision_Descriptor.h"

#ifdef ASURA_TOOLS
#include "Blueprint/ToolsAVP_Blueprint_AnimSpreadsheetExporter.h"
#endif

Asura_TemplateHashTree< AVP_Human_AIAnimStateData::AVP_Human_AIAnimWeaponStateData > AVP_Human_AIAnimStateData::s_xHashTree;

AVP_Human_AIAnimStateData::AVP_Human_AIAnimWeaponStateData::AVP_Human_AIAnimWeaponStateData()
{
	for ( u_int uAimingItr = 0; uAimingItr < AVP_Human_AIAnimStateMachine::AIMINGSTATE_END; ++uAimingItr )
	{
		for ( u_int uStateItr = 0; uStateItr < AVP_Human_AIAnimStateMachine::HUMAN_STATE_END; ++uStateItr )
		{
			m_aappxAnimStateData[ uAimingItr ][ uStateItr ] = NULL;
		}
	}
}

AVP_Human_AIAnimStateData::AVP_Human_AIAnimWeaponStateData::~AVP_Human_AIAnimWeaponStateData()
{
	for ( u_int uAimingItr = 0; uAimingItr < AVP_Human_AIAnimStateMachine::AIMINGSTATE_END; ++uAimingItr )
	{
		if ( m_aappxAnimStateData[ uAimingItr ] )
		{
			for ( u_int uStateItr = 0; uStateItr < AVP_Human_AIAnimStateMachine::HUMAN_STATE_END; ++uStateItr )
			{
				if ( m_aappxAnimStateData[ uAimingItr ][ uStateItr ] )
				{
					u_int uNumCoverTypes = AVP_Human_AIAnimStateMachine::HasCoverTypes( uStateItr ) ? AVP_Human_AIAnimStateMachine::COVER_TYPE_END : 1;
					for ( u_int uCoverItr = 0; uCoverItr < uNumCoverTypes; ++uCoverItr )
					{
						delete m_aappxAnimStateData[ uAimingItr ][ uStateItr ][ uCoverItr ];
					}
					delete[] m_aappxAnimStateData[ uAimingItr ][ uStateItr ];
				}
			}
		}
	}
}

void AVP_Human_AIAnimStateData::AVP_Human_AIAnimWeaponStateData::InitialiseFromBlueprint( const Asura_Hash_ID uAnimStateBlueprintType, const Asura_Hash_ID uWeaponBlueprintHash )
{
	const Asura_Blueprint* pxWeaponBlueprint = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_INVENTORY_ITEMS, uWeaponBlueprintHash );
	Asura_Assertf( pxWeaponBlueprint, ( "Unable to get weapon blueprint 0x%08x", uWeaponBlueprintHash ) );
	if ( pxWeaponBlueprint )
	{
		for ( u_int uAimingItr = 0; uAimingItr < AVP_Human_AIAnimStateMachine::AIMINGSTATE_END; ++uAimingItr )
		{
			for ( u_int uStateItr = 0; uStateItr < AVP_Human_AIAnimStateMachine::HUMAN_STATE_END; ++uStateItr )
			{
				bool bHasCover = AVP_Human_AIAnimStateMachine::HasCoverTypes( uStateItr );
				u_int uNumCoverTypes = bHasCover ? AVP_Human_AIAnimStateMachine::COVER_TYPE_END : 1;
				m_aappxAnimStateData[ uAimingItr ][ uStateItr ] = new AVP_Actor_AnimStateData*[ uNumCoverTypes ];
				for ( u_int uCoverItr = 0; uCoverItr < uNumCoverTypes; ++uCoverItr )
				{
					if ( !bHasCover || AVP_Human_AIAnimStateMachine::IsCoverTypeValid( uCoverItr, uStateItr ) )
					{
						Asura_Value xValue;
						Asura_Hash_ID uStateBPParam;
						if ( bHasCover )
						{
							uStateBPParam = ( ( uCoverItr == AVP_Human_AIAnimStateMachine::COVER_TYPE_LOW ) ? uAVP_BLUEPRINT_PARAM_ANIMSTATE_BLUEPRINT_TP_LOWCOVER :
											( ( uCoverItr == AVP_Human_AIAnimStateMachine::COVER_TYPE_MID ) ? uAVP_BLUEPRINT_PARAM_ANIMSTATE_BLUEPRINT_TP_MIDCOVER :
																											  uAVP_BLUEPRINT_PARAM_ANIMSTATE_BLUEPRINT_TP_HIGHCOVER ) );
						}
						else
						{
							uStateBPParam = uAimingItr == 0 ? uAVP_BLUEPRINT_PARAM_ANIMSTATE_BLUEPRINT_TP_AIMING : uAVP_BLUEPRINT_PARAM_ANIMSTATE_BLUEPRINT_TP_NEUTRAL;
						}
						
						if ( pxWeaponBlueprint->GetParameterValueByHashID( uStateBPParam, xValue ) )
						{
							Asura_Hash_ID uAIAnimStateBPHash = xValue.GetHashIDValue();
							const Asura_Blueprint* pxStateBlueprint = Asura_Blueprint_System::GetBlueprintByHashID( uAnimStateBlueprintType, uAIAnimStateBPHash );
							Asura_Assertf( pxStateBlueprint, ( "Unable to get state blueprint 0x%08x", uAIAnimStateBPHash ) );
							if ( pxStateBlueprint )
							{
#ifdef ASURA_TOOLS
								if ( ToolsAVP_Blueprint_AnimSpreadsheetExporter::IsActive() )
								{
									ToolsAVP_Blueprint_AnimSpreadsheetExporter::CreateFile( ( Asura_String( "Human_" ) + pxStateBlueprint->GetName() + ".csv" ).GetString() );
								}
#endif
								Asura_String xStateName = AVP_Human_AIAnimStateMachine::GetStateDescriptionStatic( uStateItr );

								if ( AVP_Human_AIAnimStateMachine::IsDirectionalState( uStateItr ) )
								{
									m_aappxAnimStateData[ uAimingItr ][ uStateItr ][ uCoverItr ] = uStateItr < AVP_Human_AIAnimStateMachine::ACTOR_STATE_IDLE ? NULL : new AVP_Actor_AnimStateData_Directional();
									if ( m_aappxAnimStateData[ uAimingItr ][ uStateItr ][ uCoverItr ] )
									{
										m_aappxAnimStateData[ uAimingItr ][ uStateItr ][ uCoverItr ]->InitialiseFromBlueprint( uAnimStateBlueprintType, *pxStateBlueprint, xStateName.GetString(), AVP_Vertebrate_AIAnimStateMachine::IsStateRequired(uStateItr) );
									}
								}
								else
								{
									m_aappxAnimStateData[ uAimingItr ][ uStateItr ][ uCoverItr ] = uStateItr < AVP_Human_AIAnimStateMachine::ACTOR_STATE_IDLE ? NULL : new AVP_Actor_AnimStateData_NonDirectional();
									if ( m_aappxAnimStateData[ uAimingItr ][ uStateItr ][ uCoverItr ] )
									{
										m_aappxAnimStateData[ uAimingItr ][ uStateItr ][ uCoverItr ]->InitialiseFromBlueprint( uAnimStateBlueprintType, *pxStateBlueprint, xStateName.GetString(), AVP_Vertebrate_AIAnimStateMachine::IsStateRequired(uStateItr) );
									}
								}
#ifdef ASURA_TOOLS
								if ( ToolsAVP_Blueprint_AnimSpreadsheetExporter::IsActive() && uStateItr >= AVP_Human_AIAnimStateMachine::ACTOR_STATE_IDLE )
								{
									ToolsAVP_Blueprint_AnimSpreadsheetExporter::WriteState( xStateName.GetString(), m_aappxAnimStateData[ uAimingItr ][ uStateItr ][ uCoverItr ], pxStateBlueprint, uAnimStateBlueprintType );
								}
#endif						
							} // state blueprint
							else
							{
								m_aappxAnimStateData[ uAimingItr ][ uStateItr ][ uCoverItr ] = NULL;
							}
						} // weapon state blueprint parameter found
#ifdef ASURA_ASSERT
						else
						{
							Asura_Assertf( false, ( "Unable to get actor state blueprint parameter with hash 0x%08x from weapon blueprint 0x%08x", uStateBPParam, uWeaponBlueprintHash ) );
							m_aappxAnimStateData[ uAimingItr ][ uStateItr ][ uCoverItr ] = NULL;
						}
#endif
					} // cover valid
					else
					{
						m_aappxAnimStateData[ uAimingItr ][ uStateItr ][ uCoverItr ] = NULL;
					}
				} // end cover loop
			} // end state loop
		} // end aiming loop
	} // current weapon blueprint valid
}

const AVP_Actor_AnimStateData* AVP_Human_AIAnimStateData::GetAnimStateData( const Asura_Hash_ID uAnimStateBlueprintType, const Asura_Hash_ID uCurrentWeaponHash, u_int uState, const bool bAiming /*= true*/, AVP_Human_AIAnimStateMachine::CoverType eCoverType /*= AVP_Human_AIAnimStateMachine::COVER_TYPE_BEGIN*/ )
{
	Asura_Assert( uState < AVP_Human_AIAnimStateMachine::HUMAN_STATE_END, "Invalid state" );
	if ( uState < AVP_Human_AIAnimStateMachine::HUMAN_STATE_END )
	{
		bool bHasCover = AVP_Human_AIAnimStateMachine::HasCoverTypes( uState );
		if ( !bHasCover )
		{
			eCoverType = AVP_Human_AIAnimStateMachine::COVER_TYPE_BEGIN;
		}
		Asura_Assertf( !bHasCover || ( bHasCover && AVP_Human_AIAnimStateMachine::IsCoverTypeValid( eCoverType, uState ) ), ( "Cover type %s not valid for state %s", AVP_Human_AIAnimStateMachine::GetCoverTypeDescription(eCoverType), AVP_Human_AIAnimStateMachine::GetStateDescriptionStatic(uState) ) );
		if ( !bHasCover || ( bHasCover && AVP_Human_AIAnimStateMachine::IsCoverTypeValid( eCoverType, uState ) ) )
		{
			const AVP_Human_AIAnimStateData::AVP_Human_AIAnimWeaponStateData* pxWeaponData = GetWeaponDataByHash( uAnimStateBlueprintType, uCurrentWeaponHash );
			Asura_Assert( pxWeaponData != NULL, "No weapon state data" );
			if ( pxWeaponData != NULL )
			{
				const u_int uAimingState = bAiming ? AVP_Human_AIAnimStateMachine::AIMING : AVP_Human_AIAnimStateMachine::NEUTRAL;
				if ( pxWeaponData->m_aappxAnimStateData[ uAimingState ] &&
					 pxWeaponData->m_aappxAnimStateData[ uAimingState ][ uState ] )
				{
					return pxWeaponData->m_aappxAnimStateData[ uAimingState ][ uState ][ eCoverType ];
				}
			}
		}
	}
	return NULL;
}

const AVP_Human_AIAnimStateData::AVP_Human_AIAnimWeaponStateData* AVP_Human_AIAnimStateData::GetWeaponDataByHash( const Asura_Hash_ID uAnimStateBlueprintType, const Asura_Hash_ID uHash )
{
	AVP_Human_AIAnimWeaponStateData* pxData = s_xHashTree.GetDataByHash( uHash, false );
	if ( pxData == NULL && uHash != ASURA_HASH_ID_UNSET )
	{
		pxData = s_xHashTree.AddNode( uHash );
		Asura_Assert( pxData != NULL, "Unable to add new anim state data to tree" );
		if ( pxData != NULL )
		{
			pxData->InitialiseFromBlueprint( uAnimStateBlueprintType, uHash );
		}
	}
	return pxData;
}

/// End of file. ///
