//////////////////////////////////////////////////////////////////////////////
//
// AVP_ServerEntity_InteractBatteryReceptacle.h
//
// Created by AJK 24/11/2008
//
// Copyright (c) 2008 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"

// This file's header.
#include "Entity/PhysicalObject/Interact/ToolReceptacle/BatteryReceptacle/AVP_ServerEntity_InteractBatteryReceptacle.h"

// Asura
#include "Entity/Asura_StaticMessage_System.h"

//AVP
#include "Entity/PhysicalObject/Interact/ToolReceptacle/BatteryReceptacle/AVP_Messages_InteractBatteryReceptacle.h"
#include "Entity/AVP_Entity_Classification.h"
#include "Entity/AVP_Messages.h"
#include "Entity/PhysicalObject/Actor/AVP_Actor_Messages.h"
#include "Entity/PhysicalObject/Actor/AVP_ServerEntity_Actor.h"
#include "Entity/PhysicalObject/Interact/ToolReceptacle/BatteryReceptacle/AVP_ClientEntity_InteractBatteryReceptacle.h"
#include "Entity/PhysicalObject/Pickup/AVP_ServerEntity_Pickup.h"
#include "Inventory/AVP_Inventory_HashIDs.h"

#ifdef ASURA_TOOLS
#include "EntityTemplate/Tools_EntityTemplate_System.h"
#endif

Asura_Hashed_List<AVP_ServerEntity_InteractBatteryReceptacle> AVP_ServerEntity_InteractBatteryReceptacle::s_xList;

AVP_ServerEntity_InteractBatteryReceptacle::AVP_ServerEntity_InteractBatteryReceptacle( Asura_Guid uGuid ) 
: Asura_Entity_Server( uGuid )
, PARENT( uGuid )
, m_usMarineInsertBatteryMessageBlock( ASURA_STATICMESSAGE_EMPTYBLOCK )
, m_usMarineRemoveBatteryMessageBlock( ASURA_STATICMESSAGE_EMPTYBLOCK )
, m_usPredatorUseBatteryMessageBlock( ASURA_STATICMESSAGE_EMPTYBLOCK )
, m_usAlienDestroyBatteryMessageBlock( ASURA_STATICMESSAGE_EMPTYBLOCK )
{
	Classification = AVP_ENTITYCLASS_INTERACT_BATTERY_RECEPTACLE;

	s_xList.AddToList(this);

	m_uAttachMarker = 0x6822FD4C; // "BatteryAttachMarker"
}

AVP_ServerEntity_InteractBatteryReceptacle::~AVP_ServerEntity_InteractBatteryReceptacle()
{
	s_xList.RemoveFromList(this);
}

void AVP_ServerEntity_InteractBatteryReceptacle::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iCurrentChunkVersion;

	xStream >> iCurrentChunkVersion;

	switch ( iCurrentChunkVersion )
	{
	case CURRENT_CHUNK_VERSION :
		{
			PARENT::ReadFromChunkStream(xStream);
			xStream >> m_usMarineInsertBatteryMessageBlock;
			xStream >> m_usMarineRemoveBatteryMessageBlock;
			xStream >> m_usPredatorUseBatteryMessageBlock;
			xStream >> m_usAlienDestroyBatteryMessageBlock;
			break;
		}
	default :
		{
			Asura_Assertf(false, ("Unknown chunk version (%d) in AVP_ServerEntity_InteractBatteryReceptacle", iCurrentChunkVersion));
			break;
		}
	}
}

void AVP_ServerEntity_InteractBatteryReceptacle::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << CURRENT_CHUNK_VERSION;

	PARENT::WriteToChunkStream( xStream );

	xStream << m_usMarineInsertBatteryMessageBlock;
	xStream << m_usMarineRemoveBatteryMessageBlock;
	xStream << m_usPredatorUseBatteryMessageBlock;
	xStream << m_usAlienDestroyBatteryMessageBlock;

}

void AVP_ServerEntity_InteractBatteryReceptacle::MakeCreateMessage( Asura_Guid uRequestingClient, bool bSendGuaranteed /*= false*/ )
{
	Asura_Message* pxMessage = Asura_Network::CreateMessage(ASURA_MSG_CLIENTCREATE, sizeof( AVP_Message_InteractBatteryReceptacle_ClientCreate ), GetClassification());
	if(pxMessage)
	{
		AVP_Message_InteractBatteryReceptacle_ClientCreate* pxData = static_cast< AVP_Message_InteractBatteryReceptacle_ClientCreate* >( pxMessage->GetData() );
		pxData->FillInteractionObject(this);

		pxMessage->SetToGuid( ASURA_GUID_MY_CLIENT_ENTITIES );
		pxMessage->SetFromGuid( GetGuid() );
		if (bSendGuaranteed)
		{
			pxMessage->UseGuaranteedDelivery();
		}
		Asura_Network::SendToSpecificMachine( pxMessage, uRequestingClient );
	}
}

#ifdef ASURA_TOOLS
void AVP_ServerEntity_InteractBatteryReceptacle::CreateFromTools(Asura_Guid uGuid)
{
	new AVP_ServerEntity_InteractBatteryReceptacle(uGuid);
}

bool AVP_ServerEntity_InteractBatteryReceptacle::CanBeIncludedInTemplate() const
{
	return (GetClassification() == AVP_ENTITYCLASS_INTERACT_BATTERY_RECEPTACLE);
}

void AVP_ServerEntity_InteractBatteryReceptacle::ApplyChangesForTemplateInstance( Tools_EntityTemplateInstance* pxInstance )
{
	PARENT::ApplyChangesForTemplateInstance(pxInstance);

	m_usMarineInsertBatteryMessageBlock = pxInstance->ConvertMessageBlock( m_usMarineInsertBatteryMessageBlock );
	m_usMarineRemoveBatteryMessageBlock = pxInstance->ConvertMessageBlock( m_usMarineRemoveBatteryMessageBlock );
	m_usPredatorUseBatteryMessageBlock  = pxInstance->ConvertMessageBlock( m_usPredatorUseBatteryMessageBlock  );
	m_usAlienDestroyBatteryMessageBlock = pxInstance->ConvertMessageBlock( m_usAlienDestroyBatteryMessageBlock );
}
#endif // #ifdef ASURA_TOOLS

#ifdef ASURA_TOOLS
void AVP_ServerEntity_InteractBatteryReceptacle::GetCustomEventName(int iEventIndex, Asura_String& xEventName)
{
	switch(iEventIndex)
	{
		case MESSAGE_BLOCK_MARINE_INSERT_BATTERY:		xEventName = "On marine insert battery";		return;
		case MESSAGE_BLOCK_MARINE_REMOVE_BATTERY:		xEventName = "On marine remove battery";		return;
		case MESSAGE_BLOCK_PREDATOR_USE_BATTERY:		xEventName = "On predator use battery";			return;
		case MESSAGE_BLOCK_ALIEN_DESTROY_BATTERY:		xEventName = "On alien destroy battery";		return;
	}

	Asura_Assert(FALSE, "Invalid battery receptacle custom event index");

	xEventName = "";
}

unsigned short* AVP_ServerEntity_InteractBatteryReceptacle::GetCustomEvent(int iIndex)
{
	switch(iIndex)
	{
		case MESSAGE_BLOCK_MARINE_INSERT_BATTERY:		return &m_usMarineInsertBatteryMessageBlock;
		case MESSAGE_BLOCK_MARINE_REMOVE_BATTERY:		return &m_usMarineRemoveBatteryMessageBlock;
		case MESSAGE_BLOCK_PREDATOR_USE_BATTERY:		return &m_usPredatorUseBatteryMessageBlock;
		case MESSAGE_BLOCK_ALIEN_DESTROY_BATTERY:		return &m_usAlienDestroyBatteryMessageBlock;
	}

	Asura_Assert(FALSE, "Invalid battery receptacle custom event index");

	return NULL;
}
#endif // ASURA_TOOLS

bool AVP_ServerEntity_InteractBatteryReceptacle::HandleMessage(const Asura_Message* pxMsg)
{
	switch ( pxMsg->GetMsgID() )
	{
	case AVP_MSGID_REQUEST_INTERACTION:
		{
			const AVP_Message_Actor_RequestInteraction*	pxData = static_cast< const AVP_Message_Actor_RequestInteraction* >( pxMsg->GetData() );
			if ( pxData )
			{
				Asura_Assert( pxData->GetInteractionType() == AVP_INTERACTION_TYPE_DEFAULT, "Interaction objects only handle default interactions" );
				if( pxData->GetInteractionMoveType() ==  AVP_Message_Actor_RequestInteraction::INTERACTION_INTIATED)
				{
					// Find the species
					AVP_ServerEntity_Actor* pxActor = AVP_ServerEntity_Actor::FindEntity( pxData->GetActorGuid() );
					{
						if(pxActor)
						{
							//pxActor->SetIteractionObjectGuid(GetGuid());
							switch(pxActor->GetClassification())
							{
							case ( AVP_ENTITYCLASS_MARINE ):
								{
									if( !IsToolInside() )
									{
										// Attach battery to marine righthand
									    AttachBatteryToRightHand(pxData->GetActorGuid() );
										// Insert battery
										SendMarineInsertBatteryMessage();
									}
									else
									{
										// Remove battery
										SendMarineRemoveBatteryMessage();
									}
									break;
								}
							case ( AVP_ENTITYCLASS_PREDATOR ):
								{
									if( IsToolInside() )
									{
										OnTurnOn();
										// Add energy to the predator
										SendPredatorUseBatteryMessage();
									}
									break;
								}
							case ( AVP_ENTITYCLASS_ALIEN ):
								{
									if( IsToolInside() )
									{
										// Destroy the battery here
										SendAlienDestroyBatteryMessage();
									}
									break;
								}
							}
							Asura_Network::Forward( pxMsg, ASURA_GUID_MY_CLIENT_ENTITIES, GetGuid() );
							return true;
						}
					}
				}
			}
			else
			{
				Asura_Assert( false, "No data" );
				return false;
			}
			return false;
		}

	default:
		return PARENT::HandleMessage(pxMsg);
	}
}

void AVP_ServerEntity_InteractBatteryReceptacle::SendMarineInsertBatteryMessage()
{
	if ( m_usMarineInsertBatteryMessageBlock != ASURA_STATICMESSAGE_EMPTYBLOCK )
	{
		Asura_StaticMessage_System::SendMessages( m_usMarineInsertBatteryMessageBlock, GetGuid() );
	}
}

void AVP_ServerEntity_InteractBatteryReceptacle::SendMarineRemoveBatteryMessage()
{
	if ( m_usMarineRemoveBatteryMessageBlock != ASURA_STATICMESSAGE_EMPTYBLOCK )
	{
		Asura_StaticMessage_System::SendMessages( m_usMarineRemoveBatteryMessageBlock, GetGuid() );
	}
}

void AVP_ServerEntity_InteractBatteryReceptacle::SendAlienDestroyBatteryMessage()
{
	if ( m_usAlienDestroyBatteryMessageBlock != ASURA_STATICMESSAGE_EMPTYBLOCK )
	{
		Asura_StaticMessage_System::SendMessages( m_usAlienDestroyBatteryMessageBlock, GetGuid() );
	}
}

void AVP_ServerEntity_InteractBatteryReceptacle::SendPredatorUseBatteryMessage()
{
	if ( m_usPredatorUseBatteryMessageBlock != ASURA_STATICMESSAGE_EMPTYBLOCK )
	{
		Asura_StaticMessage_System::SendMessages( m_usPredatorUseBatteryMessageBlock, GetGuid() );
	}
}

void AVP_ServerEntity_InteractBatteryReceptacle::DestroyBattery()
{
	OnTurnOn();

	// Mesh swap for now
	if (m_uToolGuid == ASURA_GUID_UNREGISTERED) 
	{
		Asura_Assert( false, "How come?" );
		return;
	}

	AVP_ServerEntity_Pickup* pxPickup = AVP_ServerEntity_Pickup::FindEntity(m_uToolGuid);
	if(pxPickup)
	{
		// Get the rest Anim
		const AVP_ClientEntity_InteractBatteryReceptacle* pxClient = AVP_ClientEntity_InteractBatteryReceptacle::FindEntity(GetGuid());
		if(pxClient)
		{
			pxPickup->ChangeSkinToDestroyed(pxClient->GetToolRestAnim());
		}
	}
	else
	{
		Asura_Assert( false, "Where is my battery?" );
	}
	
	//Send message to client entities to disable the destroyed battery
	Asura_Message* pxMessage = Asura_Network::CreateMessage(AVP_MSGID_INTERACTION_OBJECT_DISABLE);
	if( pxMessage )
	{
		pxMessage->SetFromGuid( GetGuid() );
		pxMessage->SetToGuid( GetGuid() );
		Asura_Network::Send(pxMessage);
	}
	
}

void AVP_ServerEntity_InteractBatteryReceptacle::AttachBatteryToRightHand(Asura_Guid uActorGuid)
{
	AVP_ServerEntity_Pickup* pxPickup = NULL;

	if (m_uToolGuid != ASURA_GUID_UNREGISTERED)
	{
		pxPickup = AVP_ServerEntity_Pickup::FindEntity(m_uToolGuid);
	}
	else
	{
		AVP_ServerEntity_Actor* pxActor = AVP_ServerEntity_Actor::FindEntity( uActorGuid );
		if(pxActor)
		{
			pxPickup = AVP_ServerEntity_Pickup::FindEntity(pxActor->GetPickupGuid());
		}
	}

	if(pxPickup)
	{	
		pxPickup->SetHidden(false);

		Asura_Message*	pxMessage	= Asura_Network::CreateMessage(ASURA_MSG_LINK_TO_PARENT, sizeof(Asura_Message_PhysicalObject_LinkToParent));

		if(pxMessage)
		{
			Asura_Message_PhysicalObject_LinkToParent*	pxData	= static_cast<Asura_Message_PhysicalObject_LinkToParent*>( pxMessage->GetData() );

			// Create and send the message...
			pxData->SetParentGuid( uActorGuid);

			pxData->SetMarkerHash( 0xA282148B ); // 0xA282148B, Asura_GetHashID("righthand")

			pxMessage->SetFromGuid( GetGuid() );
			pxMessage->SetToGuid( pxPickup->GetGuid() );

			Asura_Network::Send( pxMessage );
		}
	}
	else
	{
		Asura_Assert(false, "Couldn't find Tool server pickup!");
	}
}
