//////////////////////////////////////////////////////////////////////////////
//
// Asura_Project_LoadAndSave.cpp
//
// Copyright (c) 2003 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"

#include "LoadAndSave/AVP_WeaponData_System.h"

#include "Blueprint/AVP_Blueprint_HashIDs.h"

bool AVP_WeaponData_System::s_bLoaded = false;
u_int AVP_WeaponData_System::s_auNumWeapons[AVP_Game_Core::NUM_CHARACTERTYPES];
char AVP_WeaponData_System::s_aaszWeaponNames[AVP_Game_Core::NUM_CHARACTERTYPES][ uAVP_MAX_WEAPONS_PER_CHARACTERTYPE ][ uAVP_MAX_WEAPON_FILENAME_LENGTH ];
bool AVP_WeaponData_System::s_aabWeaponShouldBeLoaded[AVP_Game_Core::NUM_CHARACTERTYPES][ uAVP_MAX_WEAPONS_PER_CHARACTERTYPE ];

const char* AVP_WeaponData_System::GetWeaponNameFromHash( const Asura_Hash_ID uWeaponHash, const AVP_Game_Core::CharacterType eCharType )
{
	Asura_Assert( s_bLoaded, "WeaponData not initialised, has common file been exported?" );
	if ( !s_bLoaded )
	{
		return "";
	}
	Asura_Assert( eCharType < AVP_Game_Core::NUM_CHARACTERTYPES, "Invalid character type" );
	if ( eCharType >= AVP_Game_Core::NUM_CHARACTERTYPES )
	{
		return "";
	}

	for ( u_int uItr = 0; uItr < s_auNumWeapons[ eCharType ]; ++uItr )
	{
		const char* szWeaponName = s_aaszWeaponNames[ eCharType ][ uItr ];
		const Asura_Hash_ID uCurrentWeaponHash = Asura_GetHashID( szWeaponName );
		if ( uCurrentWeaponHash == uWeaponHash )
		{
			return szWeaponName;
		}
	}
	Asura_Assertf( false, ( "Weapon with hash ID 0x%08x not found in weapon data. Has common file been exported?", uWeaponHash ) );
	return "";
}

const char* AVP_WeaponData_System::GetWeaponNameFromIndex( const u_int uWeaponIdx, const AVP_Game_Core::CharacterType eCharType )
{
	Asura_Assert( s_bLoaded, "WeaponData not initialised, has common file been exported?" );
	if ( !s_bLoaded )
	{
		return "";
	}
	Asura_Assert( eCharType < AVP_Game_Core::NUM_CHARACTERTYPES, "Invalid character type" );
	if ( eCharType >= AVP_Game_Core::NUM_CHARACTERTYPES )
	{
		return "";
	}
	Asura_Assert( uWeaponIdx < s_auNumWeapons[ eCharType ], "Invalid weapon index" );
	if ( uWeaponIdx >= s_auNumWeapons[ eCharType ] )
	{
		return "";
	}

	return s_aaszWeaponNames[ eCharType ][ uWeaponIdx ];
}

u_int AVP_WeaponData_System::GetWeaponIndexFromHash( const Asura_Hash_ID uWeaponHash, const AVP_Game_Core::CharacterType eCharType )
{
	Asura_Assert( s_bLoaded, "WeaponData not initialised, has common file been exported?" );
	if ( !s_bLoaded )
	{
		return 0;
	}
	Asura_Assert( eCharType < AVP_Game_Core::NUM_CHARACTERTYPES, "Invalid character type" );
	if ( eCharType >= AVP_Game_Core::NUM_CHARACTERTYPES )
	{
		return 0;
	}

	for ( u_int uItr = 0; uItr < s_auNumWeapons[ eCharType ]; ++uItr )
	{
		const char* szWeaponName = s_aaszWeaponNames[ eCharType ][ uItr ];
		const Asura_Hash_ID uCurrentWeaponHash = Asura_GetHashID( szWeaponName );
		if ( uCurrentWeaponHash == uWeaponHash )
		{
			return uItr;
		}
	}
	Asura_Assertf( false, ( "Weapon with hash ID 0x%08x not found in weapon data. Has common file been exported?", uWeaponHash ) );
	return 0;
}

u_int AVP_WeaponData_System::GetNumWeaponsForCharacterType( const AVP_Game_Core::CharacterType eCharType )
{
	Asura_Assert( s_bLoaded, "WeaponData not initialised, has common file been exported?" );
	if ( !s_bLoaded )
	{
		return 0;
	}
	Asura_Assert( eCharType < AVP_Game_Core::NUM_CHARACTERTYPES, "Invalid character type" );
	if ( eCharType >= AVP_Game_Core::NUM_CHARACTERTYPES )
	{
		return 0;
	}
	return s_auNumWeapons[ eCharType ];
}


void AVP_WeaponData_System::SetShouldLoadWeapon( const u_int uWeaponIdx, const AVP_Game_Core::CharacterType eCharType, const bool bSet /*= true*/ )
{
	Asura_Assert( s_bLoaded, "WeaponData not initialised, has common file been exported?" );
	if ( !s_bLoaded )
	{
		return;
	}
	Asura_Assert( eCharType < AVP_Game_Core::NUM_CHARACTERTYPES, "Invalid character type" );
	if ( eCharType >= AVP_Game_Core::NUM_CHARACTERTYPES )
	{
		return;
	}
	Asura_Assert( uWeaponIdx < s_auNumWeapons[ eCharType ], "Invalid weapon index" );
	if ( uWeaponIdx >= s_auNumWeapons[ eCharType ] )
	{
		return;
	}

	s_aabWeaponShouldBeLoaded[ eCharType ][ uWeaponIdx ] = bSet;
}

bool AVP_WeaponData_System::GetShouldLoadWeapon( const u_int uWeaponIdx, const AVP_Game_Core::CharacterType eCharType )
{
	Asura_Assert( s_bLoaded, "WeaponData not initialised, has common file been exported?" );
	if ( !s_bLoaded )
	{
		return false;
	}
	Asura_Assert( eCharType < AVP_Game_Core::NUM_CHARACTERTYPES, "Invalid character type" );
	if ( eCharType >= AVP_Game_Core::NUM_CHARACTERTYPES )
	{
		return false;
	}
	Asura_Assert( uWeaponIdx < s_auNumWeapons[ eCharType ], "Invalid weapon index" );
	if ( uWeaponIdx >= s_auNumWeapons[ eCharType ] )
	{
		return false;
	}

	return s_aabWeaponShouldBeLoaded[ eCharType ][ uWeaponIdx ];
}

void AVP_WeaponData_System::ResetShouldBeLoadedData( const bool bSet /*= false*/ )
{
	for ( u_int uCharTypeItr = 0; uCharTypeItr < AVP_Game_Core::NUM_CHARACTERTYPES; ++uCharTypeItr )
	{
		for ( u_int uWeaponItr = 0; uWeaponItr < uAVP_MAX_WEAPONS_PER_CHARACTERTYPE; ++uWeaponItr )
		{
			s_aabWeaponShouldBeLoaded[ uCharTypeItr ][ uWeaponItr ] = bSet;
		}
	}
}

#ifdef ASURA_TOOLS

void AVP_WeaponData_System::InitialiseFromBlueprints()
{
	s_bLoaded = true;

	for ( u_int uCharTypeItr = 0; uCharTypeItr < AVP_Game_Core::NUM_CHARACTERTYPES; ++uCharTypeItr )
	{
		s_auNumWeapons[ uCharTypeItr ] = 0;
	}

	Asura_Blueprint_ConstIterator xLevelBPItr( uAVP_BLUEPRINT_TYPE_LEVELS );
	while ( !xLevelBPItr.Done() && xLevelBPItr.GetCurrent() )
	{
		Asura_Hash_ID auWeaponHashesInLevel[ uAVP_MAX_WEAPONS_IN_LEVEL ];
		AVP_Blueprint_ParameterEnumerator_LevelWeapons xWeaponEnumerator( auWeaponHashesInLevel );
		u_int uNumWeapons = xLevelBPItr.GetCurrent()->EnumerateParameters( "Weapon", 2, xWeaponEnumerator );

		if ( uNumWeapons < uAVP_MAX_WEAPONS_IN_LEVEL )
		{
			Asura_Value xVal;
			if ( xLevelBPItr.GetCurrent()->GetParameterValueByHashID( uAVP_BLUEPRINT_PARAM_HACKINGTOOL, xVal ) && xVal.GetHashIDValue() != ASURA_HASH_ID_UNSET )
			{
				auWeaponHashesInLevel[ uNumWeapons ] = xVal.GetHashIDValue();
				++uNumWeapons;
			}
		}

		Asura_Value xValue;
		AVP_Settings::Species eSpecies = AVP_Settings::AVP_SPECIES_UNKNOWN;
		if ( xLevelBPItr.GetCurrent()->GetParameterValueByHashID( 0x11d155d1, xValue ) && static_cast< u_int >( xValue.GetIntValue() ) < AVP_Settings::AVP_NUM_SPECIES ) // "Character Type"
		{
			eSpecies = static_cast< AVP_Settings::Species >( xValue.GetIntValue() );
		}
		else
		{
			Asura_Assertf( false, ( "Paremeter \"Character Type\" not found in level blueprint %s", xLevelBPItr.GetCurrent()->GetName() ) );
		}
		bool bMultiplayer = false;
		if ( xLevelBPItr.GetCurrent()->GetParameterValueByHashID( 0x2184e15a, xValue ) ) // "Multiplayer"
		{
			bMultiplayer = xValue.GetBoolValue();
		}
		else
		{
			Asura_Assertf( false, ( "Paremeter \"Multiplayer\" not found in level blueprint %s", xLevelBPItr.GetCurrent()->GetName() ) );
		}

		AVP_Game_Core::CharacterType eCharType = AVP_Game_Core::CHARACTERTYPE_UNKNOWN;
		switch ( eSpecies )
		{
			case AVP_Settings::AVP_SPECIES_ALIEN:
			{
				eCharType = bMultiplayer ? AVP_Game_Core::MULTIPLAYER_ALIEN : AVP_Game_Core::SINGLE_PLAYER_ALIEN;
			}
			break;

			case AVP_Settings::AVP_SPECIES_HUMAN:
			{
				eCharType = bMultiplayer ? AVP_Game_Core::MULTIPLAYER_MARINE : AVP_Game_Core::SINGLE_PLAYER_MARINE;
			}
			break;

			case AVP_Settings::AVP_SPECIES_PREDATOR:
			{
				eCharType = bMultiplayer ? AVP_Game_Core::MULTIPLAYER_PREDATOR : AVP_Game_Core::SINGLE_PLAYER_PREDATOR;
			}
			break;

			default:
			{
				Asura_Assertf( false, ( "Invalid charater type in level blueprint %s", xLevelBPItr.GetCurrent()->GetName() ) );
			}
			break;
		}

		if ( eCharType != AVP_Game_Core::CHARACTERTYPE_UNKNOWN )
		{
			for ( u_int uWeaponItr = 0; uWeaponItr < uNumWeapons; ++uWeaponItr )
			{
				if ( auWeaponHashesInLevel[ uWeaponItr ] != ASURA_HASH_ID_UNSET )
				{
					// search for this weapon in the list
					bool bFound = false;
					for ( u_int uCurrentWeaponItr = 0; uCurrentWeaponItr < s_auNumWeapons[ eCharType ] && !bFound; ++uCurrentWeaponItr )
					{
						Asura_Hash_ID uCurrentWeaponHash = Asura_GetHashID( s_aaszWeaponNames[ eCharType ][ uCurrentWeaponItr ] );
						if ( auWeaponHashesInLevel[ uWeaponItr ] == uCurrentWeaponHash )
						{
							bFound = true;
						}
					}

					// if not there then add it
					if ( !bFound )
					{
						const Asura_Blueprint* pxWeaponBlueprint = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_INVENTORY_ITEMS, auWeaponHashesInLevel[ uWeaponItr ] );
						if ( pxWeaponBlueprint == NULL )
						{
							// if not found in inv items, try pickups (might be a hacking tool)
							pxWeaponBlueprint = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_PICKUPS, auWeaponHashesInLevel[ uWeaponItr ] );
						}
						Asura_Assertf( pxWeaponBlueprint, ( "Unable to get weapon blueprint 0x%08x in Inventory Items blueprint, has it been deleted? does it need removing from the level blueprint (%s)?", auWeaponHashesInLevel[ uWeaponItr ], xLevelBPItr.GetCurrent()->GetName().GetString() ) );
						if ( pxWeaponBlueprint )
						{
							Asura_PrintfToBfr( s_aaszWeaponNames[ eCharType ][ s_auNumWeapons[ eCharType ] ], "%s", uAVP_MAX_WEAPON_FILENAME_LENGTH, true, pxWeaponBlueprint->GetName().GetString() );
							s_auNumWeapons[ eCharType ]++;
						}
					}
				}
			}
		}
		xLevelBPItr.Next();
	}

	Asura_Blueprint_ConstIterator xPickupBPItr( uAVP_BLUEPRINT_TYPE_PICKUPS );
	while ( !xPickupBPItr.Done() && xPickupBPItr.GetCurrent() )
	{
		Asura_Value xValue;
		AVP_Settings::Species eSpecies = AVP_Settings::AVP_SPECIES_UNKNOWN;
		if ( xPickupBPItr.GetCurrent()->GetParameterValueByHashID( 0x843f8d15, xValue ) && static_cast< u_int >( xValue.GetIntValue() ) < AVP_Settings::AVP_NUM_SPECIES ) // "Allegiance"
		{
			eSpecies = static_cast< AVP_Settings::Species >( xValue.GetIntValue() );
		}
		else
		{
			Asura_Assertf( false, ( "Paremeter \"Character Type\" not found in pickup blueprint %s", xPickupBPItr.GetCurrent()->GetName() ) );
		}

		for ( u_int uMPItr = 0; uMPItr < 2; ++uMPItr )
		{
			const bool bMultiplayer = ( uMPItr == 1 );
			AVP_Game_Core::CharacterType eCharType = AVP_Game_Core::CHARACTERTYPE_UNKNOWN;
			switch ( eSpecies )
			{
				case AVP_Settings::AVP_SPECIES_ALIEN:
				{
					eCharType = bMultiplayer ? AVP_Game_Core::MULTIPLAYER_ALIEN : AVP_Game_Core::SINGLE_PLAYER_ALIEN;
				}
				break;

				case AVP_Settings::AVP_SPECIES_HUMAN:
				{
					eCharType = bMultiplayer ? AVP_Game_Core::MULTIPLAYER_MARINE : AVP_Game_Core::SINGLE_PLAYER_MARINE;
				}
				break;

				case AVP_Settings::AVP_SPECIES_PREDATOR:
				{
					eCharType = bMultiplayer ? AVP_Game_Core::MULTIPLAYER_PREDATOR : AVP_Game_Core::SINGLE_PLAYER_PREDATOR;
				}
				break;

				default:
				{
					Asura_Assertf( false, ( "Invalid charater type in pickup blueprint %s", xPickupBPItr.GetCurrent()->GetName() ) );
				}
				break;
			}

			if ( eCharType != AVP_Game_Core::CHARACTERTYPE_UNKNOWN )
			{
				// search for this weapon in the list
				bool bFound = false;
				Asura_Hash_ID uWeaponInvItemParameterHash = bMultiplayer ? uAVP_BLUEPRINT_PARAM_PICKUP_MULTIPLAYERINVENTORYITEMBLUEPRINT : uAVP_BLUEPRINT_PARAM_PICKUP_SINGLEPLAYERINVENTORYITEMBLUEPRINT;
				Asura_Hash_ID uWeaponItemHash = xPickupBPItr.GetCurrent()->GetParameterAsHash( uWeaponInvItemParameterHash, ASURA_HASH_ID_UNSET );
				if ( uWeaponItemHash != ASURA_HASH_ID_UNSET )
				{
					for ( u_int uCurrentWeaponItr = 0; uCurrentWeaponItr < s_auNumWeapons[ eCharType ] && !bFound; ++uCurrentWeaponItr )
					{
						Asura_Hash_ID uCurrentWeaponHash = Asura_GetHashID( s_aaszWeaponNames[ eCharType ][ uCurrentWeaponItr ] );
						if ( uWeaponItemHash == uCurrentWeaponHash )
						{
							bFound = true;
						}
					}

					// if not there then add it
					if ( !bFound )
					{
						const Asura_Blueprint* pxWeaponBlueprint = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_INVENTORY_ITEMS, uWeaponItemHash );
						Asura_Assertf( pxWeaponBlueprint, ( "Unable to get weapon blueprint 0x%08x in Inventory Items blueprint, has it been deleted? does it need removing from the pickup blueprint (%s)?", uWeaponItemHash, xPickupBPItr.GetCurrent()->GetName().GetString() ) );
						if ( pxWeaponBlueprint )
						{
							Asura_PrintfToBfr( s_aaszWeaponNames[ eCharType ][ s_auNumWeapons[ eCharType ] ], "%s", uAVP_MAX_WEAPON_FILENAME_LENGTH, true, pxWeaponBlueprint->GetName().GetString() );
							++s_auNumWeapons[ eCharType ];
							if ( s_auNumWeapons[ eCharType ] > uAVP_MAX_WEAPONS_PER_CHARACTERTYPE )
							{
								Asura_Assertf( false, ( "Too many weapons for character type %d", eCharType ) );
								--s_auNumWeapons[ eCharType ];
							}
						}
					}
				}
			}
		} // MP loop
		xPickupBPItr.Next();
	} // pickup BP loop
}

bool* AVP_WeaponData_System::GetShouldLoadWeaponBoolPtr( const u_int uWeaponIdx, const AVP_Game_Core::CharacterType eCharType )
{
	Asura_Assert( s_bLoaded, "WeaponData not initialised, has common file been exported?" );
	if ( !s_bLoaded )
	{
		return NULL;
	}
	Asura_Assert( eCharType < AVP_Game_Core::NUM_CHARACTERTYPES, "Invalid character type" );
	if ( eCharType >= AVP_Game_Core::NUM_CHARACTERTYPES )
	{
		return NULL;
	}
	Asura_Assert( uWeaponIdx < s_auNumWeapons[ eCharType ], "Invalid weapon index" );
	if ( uWeaponIdx >= s_auNumWeapons[ eCharType ] )
	{
		return NULL;
	}

	return &s_aabWeaponShouldBeLoaded[ eCharType ][ uWeaponIdx ];
}

#endif

bool AVP_Blueprint_ParameterEnumerator_LevelWeapons::Enumerate( const u_int uIndex, char const* const szName, const Asura_Value& xValue )
{
	bool bOK = uIndex < uAVP_MAX_WEAPONS_IN_LEVEL;
	Asura_Assert( uIndex < uAVP_MAX_WEAPONS_IN_LEVEL, "Too many weapons in level blueprint" );
	if ( bOK )
	{
		m_auWeaponHashes[ uIndex ] = xValue.GetHashIDValue();
	}

	return bOK;
}
