///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Human_InteractionHandler.cpp
// Author : Ali Jakamy
// Date   : 25-11-2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"

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

// Asura
#include "Interface/Asura_CommandConsole.h"

// AVP
#include "Actor/AVP_Actor_InputHandler.h"
#include "Core/AVP_Game_Core.h"
#include "Entity/PhysicalObject/Actor/AVP_Actor_Messages.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ClientActor_Human.h"
#include "Entity/PhysicalObject/Interact/AVP_ClientEntity_InteractObject.h"
#include "Entity/PhysicalObject/Interact/ToolReceptacle/BatteryReceptacle/AVP_ClientEntity_InteractBatteryReceptacle.h"
#include "Entity/PhysicalObject/Interact/ToolReceptacle/HackingPoint/AVP_ClientEntity_InteractHackingPoint.h"
#include "Inventory/AVP_Inventory_Group.h"
#include "Inventory/AVP_Inventory_HashIDs.h"
#include "Inventory/AVP_Inventory_Item.h"
#include "Inventory/AVP_Inventory_System.h"
#include "Inventory/Items/AVP_InventoryItem_Weapon.h"
#include "Moves/AVP_Move_Interaction.h"
#include "Moves/Vertebrates/Human/AVP_Human_MovesInteraction.h"
#include "Moves/Vertebrates/Human/AVP_Human_MovesTequila.h"

bool AVP_Human_InteractionHandler::s_bRenderPickUpBuddyPrompt = false;

AVP_Human_InteractionHandler::AVP_Human_InteractionHandler(AVP_ClientEntity_Actor& xOwner)
: PARENT(xOwner)
, m_uNearbyBuddyGuid( ASURA_GUID_UNREGISTERED )
{

}
#if defined(ASURA_SUPPORT_COMMAND_CONSOLE)
void AVP_Human_InteractionHandler::CreateConsoleVars()
{
	Asura_CommandConsole::AddVar(L"AVP.Interaction.ShowPickUpBuddyPrompt", &s_bRenderPickUpBuddyPrompt, Asura_CommandConsole::REMOVE_AT_SHUTDOWN);
	Asura_CommandConsole::MakeVarReadOnly(L"AVP.Interaction.ShowPickUpBuddyPrompt");
}
#endif	// defined(ASURA_SUPPORT_COMMAND_CONSOLE)

DEBUGVAR float dbg_fActorPickupRange = 5.0f;

void AVP_Human_InteractionHandler::Update()
{
	// set guid of buddy if nearby
	m_uNearbyBuddyGuid = ASURA_GUID_UNREGISTERED;

	if ( !IsInteracting() && IsInteractionAllowed() )
	{
		bool bOK = true;
		if ( m_xOwner.GetInventorySystem() && m_xOwner.GetInventorySystem()->GetCurrentItem( uAVP_INVENTORY_GROUPHASH_WEAPON ) )
		{
			bOK = !(m_xOwner.GetInventorySystem()->GetCurrentItem( uAVP_INVENTORY_GROUPHASH_WEAPON )->IsEncumberment());
		}
		if ( bOK )
		{
			Asura_Hashed_List_ConstIt< AVP_ClientActor_Human > xListIt( AVP_ClientActor_Human::GetList() );
			for ( ; !xListIt.Done(); xListIt.Next() )
			{
				float fClosestActor = dbg_fActorPickupRange;
				const AVP_ClientActor_Human* pxClient = xListIt.GetCurrent();
				if ( pxClient && pxClient->IsEntityActive() && pxClient->IsPickupAble() && !pxClient->IsDead() )
				{
					float fDist = ( pxClient->GetCurrentPosition() - m_xOwner.GetCurrentPosition() ).Magnitude();
					if ( fDist < fClosestActor )
					{
						fClosestActor = fDist;
						m_uNearbyBuddyGuid = pxClient->GetGuid();
					}
				}
			}
		}
	}

	if ( AVP_Game_Core::IsLocalPlayer( m_xOwner.GetGuid() ) )
	{
		s_bRenderPickUpBuddyPrompt = (m_uNearbyBuddyGuid != ASURA_GUID_UNREGISTERED);
	}

	PARENT::Update();
}

Asura_Guid AVP_Human_InteractionHandler::GetGuidForInteraction( AVP_INTERACTION_TYPES eType ) const
{
	if ( eType == AVP_INTERACTION_TYPE_PICKUP_BUDDY )
	{
		return m_uNearbyBuddyGuid;
	}
	else
	{
		return PARENT::GetGuidForInteraction( eType );
	}
}

bool AVP_Human_InteractionHandler::IsInteractionAllowed() const
{
	return PARENT::IsInteractionAllowed() && !static_cast< AVP_ClientActor_Human& >( m_xOwner ).IsCarryingBudddy();
}

bool AVP_Human_InteractionHandler::HandleInteraction(AVP_INTERACTION_TYPES eType, int iKeyType, float fKeyValue) const
{
	const Asura_Guid uGuidForInteraction = GetGuidForInteraction( eType );

	if ( eType == AVP_INTERACTION_TYPE_PICKUP_BUDDY )
	{
		if ( uGuidForInteraction != ASURA_GUID_UNREGISTERED )
		{
			Asura_Message* pxMessage = Asura_Network::CreateMessage( AVP_MSGID_REQUEST_INTERACTION, sizeof( AVP_Message_Actor_RequestInteraction ) );
			if ( pxMessage )
			{
				AVP_Message_Actor_RequestInteraction* pxData = static_cast< AVP_Message_Actor_RequestInteraction* >( pxMessage->GetData() );

				// Fill-in the message...
				pxData->SetIsOn( true );
				pxData->SetInteractionType( eType );
				pxData->SetActorGuid( uGuidForInteraction );
				pxData->SetMoveHash( AVP_Human_Move_TequilaPickUp_Player::GetStaticHash() );
				pxData->SetInteractionMoveType( AVP_Message_Actor_RequestInteraction::INTERACTION_NONE );
				// Send the request...
				pxMessage->SetToGuid( m_xOwner.GetGuid() );
				pxMessage->SetFromGuid( m_xOwner.GetGuid() );

				Asura_Network::Send( pxMessage );
			}
		}
		else
		{
			// See if human carrying a tequila, if true, send a drop pickup message
			const AVP_ClientActor_Human* pxClientBuddy = AVP_ClientActor_Human::FindEntity( static_cast< AVP_ClientActor_Human& >( m_xOwner ).GetPickedUpBuddyGuid() );
			if ( pxClientBuddy && pxClientBuddy->IsDroppable() )
			{
				// Send a drop pickup message to the owner
				Asura_Message* pxMessage = Asura_Network::CreateMessage(AVP_MSGID_DROP_PICKUP);
				if( pxMessage )
				{
					pxMessage->SetFromGuid( m_xOwner.GetGuid() );
					pxMessage->SetToGuid  ( m_xOwner.GetGuid() );
					Asura_Network::Send(pxMessage);
					return true;
				}
			}
		}
	}
	else if ( uGuidForInteraction != ASURA_GUID_UNREGISTERED )
	{
		AVP_ClientEntity_InteractObject* pxInteractObject = AVP_ClientEntity_InteractObject::FindEntity( uGuidForInteraction );
		if ( pxInteractObject )
		{
			// Is it a battery?
			if (pxInteractObject->GetInteractionObjectType() == AVP_ClientEntity_InteractObject::INTERACTION_TYPE_BATTERYRECEPTACLE)
			{
				AVP_ClientEntity_InteractBatteryReceptacle* pxBatteryInteractionObj = static_cast<AVP_ClientEntity_InteractBatteryReceptacle*> (pxInteractObject);
				if (iKeyType == AVP_Actor_InputHandler::INTERACT  && !IsInteracting())
				{
					if(! pxBatteryInteractionObj->IsToolInside())
					{
						return SendInteractMessage(eType, AVP_Human_Move_Interaction_PlugBattery::GetStaticHash(), pxBatteryInteractionObj, AVP_Message_Actor_RequestInteraction::INTERACTION_INTIATED);
					}
					else
					{
						return SendInteractMessage(eType, AVP_Human_Move_Interaction_UnPlugBattery::GetStaticHash(), pxBatteryInteractionObj, AVP_Message_Actor_RequestInteraction::INTERACTION_INTIATED);
					}
				}
			}
			else if(pxInteractObject->GetInteractionObjectType() == AVP_ClientEntity_InteractObject::INTERACTION_TYPE_HACKINGPOINT)
			{
				AVP_ClientEntity_InteractHackingPoint* pxHackingInteractionObj = static_cast<AVP_ClientEntity_InteractHackingPoint*> (pxInteractObject);
				if (iKeyType == AVP_Actor_InputHandler::INTERACT  && !IsInteracting())
				{
					if(! pxHackingInteractionObj->IsToolInside())
					{
						return SendInteractMessage(eType, AVP_Human_Move_Interaction_PlugHackingTool::GetStaticHash(), pxHackingInteractionObj, AVP_Message_Actor_RequestInteraction::INTERACTION_INTIATED);
					}
					else
					{
						return SendInteractMessage(eType, AVP_Human_Move_Interaction_UnPlugHackingTool::GetStaticHash(), pxHackingInteractionObj, AVP_Message_Actor_RequestInteraction::INTERACTION_INTIATED);
					}
				}
			}
			else
			{
				if(!IsInteracting())
				{
					// Fall back to old interaction handle to not break up things already there
					return PARENT::HandleInteraction(eType, iKeyType, fKeyValue);
				}
			}
		}
	}
	else
	{
		// See if human carrying a batery, if true, send a drop pickup message
		const AVP_InventoryItem_Weapon* pxItem = m_xOwner.GetCurrentWeapon();
		if(pxItem && pxItem->IsEncumberment() )
		{
			// Send a drop pickup message to the owner
			Asura_Message* pxMessage = Asura_Network::CreateMessage(AVP_MSGID_DROP_PICKUP);
			if( pxMessage )
			{
				pxMessage->SetFromGuid( m_xOwner.GetGuid() );
				pxMessage->SetToGuid  ( m_xOwner.GetGuid() );
				Asura_Network::Send(pxMessage);
				return true;
			}
		}
	}
	return false;
}

bool AVP_Human_InteractionHandler::IsInteracting() const
{
	const Asura_Move* pxMove = m_xOwner.GetMovementSystem() ? m_xOwner.GetMovementSystem()->GetCurrentMove() : NULL; 
	if (pxMove)
	{
		return GetIsHumanInteractionMove(pxMove->GetHash());
	}
	return false;
}

bool AVP_Human_InteractionHandler::GetIsHumanInteractionMove(const Asura_Hash_ID uMoveHash)
{
	if ((uMoveHash == AVP_Move_Interaction_BeginWeaponAway::GetStaticHash())
		|| (uMoveHash == AVP_Human_Move_Interaction_PlugBattery::GetStaticHash())
		|| (uMoveHash == AVP_Human_Move_Interaction_UnPlugBattery::GetStaticHash())
		|| (uMoveHash == AVP_Human_Move_Interaction_LetGoBattery::GetStaticHash())
		|| (uMoveHash == AVP_Human_Move_Interaction_GrabBattery::GetStaticHash())
		|| (uMoveHash == AVP_Human_Move_Interaction_PlugHackingTool::GetStaticHash())
		|| (uMoveHash == AVP_Human_Move_Interaction_UnPlugHackingTool::GetStaticHash())
		|| (uMoveHash == AVP_Human_Move_Interaction_LetGoHackingTool::GetStaticHash())
		|| (uMoveHash == AVP_Human_Move_Interaction_GrabHackingTool::GetStaticHash())
		|| (uMoveHash == AVP_Human_Move_TequilaPickUp_Player::GetStaticHash())
		|| (uMoveHash == AVP_Move_Interaction::GetStaticHash()))
	{
		return true;
	}
	else
	{
		return false;
	}
}
