//
// Tools_ReceivedMessages.cpp
//
// Created by Richard Rice - 25/05/2006
// 
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"
#include "Entity/Tools_ReceivedMessages.h"

// Asura includes
#include "Entity/Triggers/Asura_ServerEntity_ProxyTrigger.h"
#include "Interface/Asura_Dialog.h"
#include "Interface/Asura_Overlay.h"
#include "Interface/Asura_Overlay_System.h"

// Tools includes
#include "Tools_Overlays.h"
#include "Entity/Tools_Message_Editing.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Objects/Tools_Object.h"
#include "Objects/Tools_Object_System.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////

class Tools_Overlay_ReceivedMessages : public Asura_Overlay
{
public :
	Tools_Overlay_ReceivedMessages(const char *szName, bool bAlwaysOnTop, Asura_Vector_2* pxPosition)
	:Asura_Overlay(szName, bAlwaysOnTop, pxPosition)
	{}

	~Tools_Overlay_ReceivedMessages()
	{
		if(IsClosingByCloseGadget())
		{
			Tools_ReceivedMessages::s_bOverlayShouldBeOpen = false;	
		}
	}
};

/////////////////////////////////////////////////////////////////////////////////////////////////////

Asura_Vector_2 Tools_ReceivedMessages::s_xOverlayPosition(25.0f,10.0f);
bool Tools_ReceivedMessages::s_bOverlayShouldBeOpen = false;

Asura_Guid Tools_ReceivedMessages::s_uCurrentGuid;
int Tools_ReceivedMessages::s_iSelectedIndex;
bool Tools_ReceivedMessages::s_bSelectedIndexChanged;

bool Tools_ReceivedMessages::s_bLockTarget = false;

List<Tools_ReceivedMessageData*> Tools_ReceivedMessages::s_xMessageList;
const char** Tools_ReceivedMessages::s_pszListStrings;

bool Tools_ReceivedMessages::s_bListInvalidated = false;

bool Tools_ReceivedMessages::s_bMessageEditing = false;
Tools_StaticMessageID Tools_ReceivedMessages::s_xEditedMessage;

void Tools_ReceivedMessages::Initialise()
{
	s_uCurrentGuid = ASURA_GUID_UNREGISTERED;
	s_iSelectedIndex = 0;
	s_bMessageEditing = false;
}

void Tools_ReceivedMessages::Shutdown()
{
	CloseOverlay();
	s_bMessageEditing = false;
}

void Tools_ReceivedMessages::Update()
{
	if(!OverlayIsOn()) return;

	bool bRecreateOverlay = false;

	if(s_bMessageEditing)
	{
		if(!Tools_Object_System::IsMessageEditing())
		{
			//flag the owner of the edited message as modified.
			s_xEditedMessage.SetModified();
			s_bMessageEditing = false;
		}
	}

	//Has the selected object changed?
	if(!s_bLockTarget)
	{
		Tools_Object* pxSelectedObject = Tools_Object_System::SelectedObject;
		Asura_Guid uSelectedGuid = pxSelectedObject ? pxSelectedObject->GetGuid() : ASURA_GUID_UNREGISTERED;

		if(uSelectedGuid != ASURA_GUID_UNREGISTERED && uSelectedGuid != s_uCurrentGuid)
		{
			//change selection
			s_uCurrentGuid = uSelectedGuid;
			bRecreateOverlay = true;
		}	
	}
	
	if(!bRecreateOverlay && s_uCurrentGuid != ASURA_GUID_UNREGISTERED)
	{
		//make sure the message list is still correct , and the
		bRecreateOverlay = !ValidateOverlayData();
	}

	if(bRecreateOverlay)
	{
		CreateOverlay();
	}
	else 
	{
		UpdateOverlay();
	}
}

void Tools_ReceivedMessages::ToggleOverlay()
{
	if(OverlayIsOn())
	{
		s_bOverlayShouldBeOpen = false;
		CloseOverlay();
	}
	else
	{
		s_bOverlayShouldBeOpen = true;
		CreateOverlay();
	}
}

bool Tools_ReceivedMessages::OverlayIsOn()
{
	return Asura_Overlay_System::DoesOverlayExist(TOOLS_OVERLAY_RECEIVEDMESSAGES);
}

void Tools_ReceivedMessages::CreateOverlay()
{
	CloseOverlay();
	if(!s_bOverlayShouldBeOpen) return;
	
	Asura_Overlay* pxOverlay = new Tools_Overlay_ReceivedMessages("Received Messages",false,&s_xOverlayPosition);
	Asura_Vector_2 xOffset = Asura_Vector_2(1.0f, 3.0f);
	Asura_Dialog* pxDialog;

	BuildMessageList();

	char szText[200];

	//give name of selected target.
	if(s_uCurrentGuid == ASURA_GUID_UNREGISTERED)
	{
		strcpy(szText,"Target : None");
	}
	else
	{
		Tools_Object* pxTarget = Tools_Object_System::GetObjectFromGuid(s_uCurrentGuid);
		if(pxTarget)
			Asura_PrintfToBfr(szText,"Target : %s",sizeof(szText),true,pxTarget->GetName());
		else
			Asura_PrintfToBfr(szText,"Target : Guid %d",sizeof(szText),true,s_uCurrentGuid);

	}

	
	pxDialog = new Asura_Function_Dialog(szText,xOffset,ChooseTarget);
	pxDialog->SetHelpText("The target entity whose messages are being listed.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	

	pxDialog = new Asura_Tickbox_Dialog("Lock Target",xOffset,&s_bLockTarget);
	pxDialog->SetHelpText("Prevents the current target being changed whenever the selected object is changed");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::LargeSpacing();

	//add list of messages (if any)
	if(s_pszListStrings)
	{
		s_iSelectedIndex = Asura_Maths::ClampToRange(s_iSelectedIndex,0,s_xMessageList.size()-1);
		s_bSelectedIndexChanged = true;

		int iNumLines = Asura_Maths::Min(8,s_xMessageList.size());

		// list dialog - only select when clicked
		pxDialog = new Asura_List_Dialog( xOffset, s_pszListStrings, &s_iSelectedIndex, iNumLines, s_xMessageList.size(), NULL, &s_bSelectedIndexChanged, true );
		pxDialog->SetHelpText("List of all messages sent to the current target");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y = pxDialog->m_xMaxCoord.y + 1.0f;

		//details about current selection
		pxDialog = new Asura_Dialog("Sender",xOffset);
		pxDialog->SetHelpText("The entity sending the selected message");
		pxDialog->m_iControlID = Asura_GetHashID("Sender");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Dialog("Event",xOffset);
		pxDialog->SetHelpText("The event that will cause the message to be sent");
		pxDialog->m_iControlID = Asura_GetHashID("Event");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Dialog("Disabled",xOffset);
		pxDialog->SetHelpText("Indicates whether the message has been disabled");
		pxDialog->m_iControlID = Asura_GetHashID("Disabled");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();

		pxDialog = new Asura_Function_Dialog("Select Sender",xOffset,SelectSender);
		pxDialog->SetHelpText("Selects the sender of the current message");
		pxDialog->SetIsEnabledFunction(CanSelectSender);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("Goto Sender",xOffset,GotoSender);
		pxDialog->SetHelpText("Jumps to and selects the sender of the current message");
		pxDialog->SetIsEnabledFunction(CanSelectSender);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		#ifndef ASURA_TOOLS_USE_NEW_MESSAGE_EDITOR
		pxDialog = new Asura_Function_Dialog("Edit Message",xOffset,EditMessage);
		pxDialog->SetHelpText("Edit the message block containing the current message.\nNote that it isn't possible to completely destroy a message block by this method.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();
		#endif
	}
	else
	{
		pxDialog = new Asura_Dialog("(No Messages)",xOffset);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();
	}
		

	pxOverlay->m_uID = TOOLS_OVERLAY_RECEIVEDMESSAGES;
	Asura_Overlay_System::SubmitNewOverlay(pxOverlay, true);

	UpdateOverlay();
}

void Tools_ReceivedMessages::UpdateOverlay()
{
	Asura_Overlay* pxOverlay = Asura_Overlay_System::GetOverlay(TOOLS_OVERLAY_RECEIVEDMESSAGES);

	char szText[200];

	if(s_xMessageList.size() && s_bSelectedIndexChanged)
	{
		//update details about current selection
		Asura_Assert(s_iSelectedIndex<s_xMessageList.size(),"");
		const Tools_ReceivedMessageData* pxData = s_xMessageList[s_iSelectedIndex];

		Asura_Dialog* pxDialog = pxOverlay->GetDialog(Asura_GetHashID("Sender"));	
		if(pxDialog)
		{
			Asura_PrintfToBfr(szText,"Sender : %s",sizeof(szText),true,pxData->m_xSenderName.GetString());
			pxDialog->UpdateLabel(szText);

		}

		pxDialog = pxOverlay->GetDialog(Asura_GetHashID("Event"));	
		if(pxDialog)
		{
			Asura_PrintfToBfr(szText,"Event : %s",sizeof(szText),true,pxData->m_xMessageEvent.GetString());
			pxDialog->UpdateLabel(szText);
		}

		pxDialog = pxOverlay->GetDialog(Asura_GetHashID("Disabled"));	
		if(pxDialog)
		{
			Asura_PrintfToBfr(szText,"Disabled : %s",sizeof(szText),true,pxData->m_bDisabled ? "Yes" : "No");
			pxDialog->UpdateLabel(szText);
		}

	
	}
	s_bSelectedIndexChanged = false;

}

void Tools_ReceivedMessages::CloseOverlay()
{
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_RECEIVEDMESSAGES);
	DeleteMessageList();
}

void Tools_ReceivedMessages::InvalidateList()
{
	s_bListInvalidated = true;
}


void Tools_ReceivedMessages::BuildMessageList()
{
	DeleteMessageList();
	s_bListInvalidated = false;
	if(s_uCurrentGuid == ASURA_GUID_UNREGISTERED)
	{
		//nothing selected , so no need to create list
		return;
	}

	//search for all messages targeting the selected object
	for(Tools_StaticMessageIterator xIterator(true);!xIterator.Done();xIterator.Next())
	{
		const Asura_StaticMessage* pxMessage = xIterator.GetCurrent();
		if(pxMessage->m_uSendTo != s_uCurrentGuid) 
		{
			// (MH - 09.01.2008) is it sent to the entity via a proxy?
			const Asura_ServerEntity_ProxyTrigger* pxProxy = Asura_ServerEntity_ProxyTrigger::FindEntity(pxMessage->m_uSendTo);
			if (!pxProxy || !pxProxy->IsEntityTargeted(s_uCurrentGuid))
			{
				continue;
			}
		}

		//fill in details for this message
		Tools_ReceivedMessageData* pxData = new Tools_ReceivedMessageData;

		xIterator.GetCurrentMessageID(pxData->m_xStaticMessageID);
		pxData->m_bDisabled = pxMessage->IsDisabled();

		pxData->m_iMessageID = pxMessage->m_usMsgID;

		//find the sender of the message
		pxData->m_xStaticMessageID.GetSenderInfo(&pxData->m_uSender, &pxData->m_xSenderName, &pxData->m_xMessageEvent);
		if(pxData->m_xSenderName.IsBlank()) pxData->m_xSenderName = "Unknown";
		if(pxData->m_xMessageEvent.IsBlank()) pxData->m_xMessageEvent = "Unknown";

		Tools_Message_Editing::GetMessageDescription(pxData->m_iMessageID,pxMessage,pxData->m_xMessageDesc);

		if(pxData->m_bDisabled)
		{
			//Alter the description to indicate that the message is disabled
			char szTemp[200];
			Asura_PrintfToBfr(szTemp,"(D) %s",sizeof(szTemp),true,pxData->m_xMessageDesc.GetString());
			pxData->m_xMessageDesc = szTemp;
		}

		s_xMessageList.add_entry(pxData);	
	}

	if(!s_xMessageList.size()) return;

	//build list of strings for the message overlay
	s_pszListStrings = new const char*[s_xMessageList.size()];
	for(int i=0;i<s_xMessageList.size();i++)
	{
		s_pszListStrings[i] = s_xMessageList[i]->m_xMessageDesc.GetString();
	}

}

void Tools_ReceivedMessages::DeleteMessageList()
{
	delete [] s_pszListStrings;
	s_pszListStrings = 0;

	while(s_xMessageList.size())
	{
		delete s_xMessageList.first_entry();
		s_xMessageList.delete_first_entry();
	}
}


bool Tools_ReceivedMessages::ValidateOverlayData()
{
	if(s_bListInvalidated) return false;

	//make sure all the messages still exist
	for(LIF<Tools_ReceivedMessageData*> xMessageLIF(&s_xMessageList);!xMessageLIF.done();xMessageLIF.next())
	{
		Tools_ReceivedMessageData* pxData = xMessageLIF();

		const Asura_StaticMessage* pxMessage = pxData->m_xStaticMessageID.GetMessagePointer();
		if(!pxMessage) return false;

		if(pxMessage->m_uSendTo != s_uCurrentGuid) 
		{
			// (MH - 09.01.2008) is it sent to the entity via a proxy?
			const Asura_ServerEntity_ProxyTrigger* pxProxy = Asura_ServerEntity_ProxyTrigger::FindEntity(pxMessage->m_uSendTo);
			if (!pxProxy || !pxProxy->IsEntityTargeted(s_uCurrentGuid))
			{
				return false;
			}
		}
		if(pxMessage->m_usMsgID != pxData->m_iMessageID) return false;
	}

	return true;
}

bool Tools_ReceivedMessages::CanSelectSender()
{
	if(s_iSelectedIndex >= s_xMessageList.size()) return false;
	const Tools_ReceivedMessageData* pxData = s_xMessageList[s_iSelectedIndex];

	return pxData->m_uSender != ASURA_GUID_UNREGISTERED;
}

void Tools_ReceivedMessages::SelectSender()
{
	if(s_iSelectedIndex >= s_xMessageList.size()) return;

	const Tools_ReceivedMessageData* pxData = s_xMessageList[s_iSelectedIndex];

	Tools_Object* pxSender = Tools_Object_System::GetObjectFromGuid(pxData->m_uSender,true);
	if(pxSender)
	{
		Tools_Object_System::SelectObject(pxSender);
	}
	else
	{
		Tools_Timed_Message_System::AddMessage(0xffffff,"Failed to find message sender");
	}

}

void Tools_ReceivedMessages::GotoSender()
{
	if(s_iSelectedIndex >= s_xMessageList.size()) return;

	const Tools_ReceivedMessageData* pxData = s_xMessageList[s_iSelectedIndex];

	Tools_Object* pxSender = Tools_Object_System::GetObjectFromGuid(pxData->m_uSender,true);
	if(pxSender)
	{
		Tools_Object_System::GotoAndSelect(pxSender);
	}
	else
	{
		Tools_Timed_Message_System::AddMessage(0xffffff,"Failed to find message sender");
	}
}

void Tools_ReceivedMessages::EditMessage()
{
	//make sure the selection is valid
	if(!ValidateOverlayData()) return;
	if(s_iSelectedIndex >= s_xMessageList.size()) return;


	//find the sender
	const Tools_ReceivedMessageData* pxData = s_xMessageList[s_iSelectedIndex];
	Tools_Object* pxSender = Tools_Object_System::GetObjectFromGuid(pxData->m_uSender,true);

	//and start editing the message
	char szText[100];
	Asura_PrintfToBfr(szText,"Sender  : %s , Event : %s",sizeof(szText),true,pxData->m_xSenderName.GetString(),pxData->m_xMessageEvent.GetString());

	u_short usMessageBlockID = pxData->m_xStaticMessageID.GetStaticMessageBlockID();
	Asura_StaticMessageBlock* pxMessageBlock = pxData->m_xStaticMessageID.GetStaticMessageBlockPointer();
	
	int iMessageIndex = pxData->m_xStaticMessageID.GetMessageIndex();

	if(pxMessageBlock)
	{
		Tools_Object_System::EditMessageBlock(szText,pxMessageBlock,pxSender,NULL);
	}
	else if(usMessageBlockID != ASURA_STATICMESSAGE_EMPTYBLOCK)
	{
		Tools_Object_System::EditMessageBlock(szText,usMessageBlockID,iMessageIndex,pxSender);
	}

	s_bMessageEditing = true;
	s_xEditedMessage = pxData->m_xStaticMessageID;
}

void Tools_ReceivedMessages::ChooseTarget()
{
	//ask for object to select
	Tools_Object* pxObject = Tools_Object_System::ChooseObjectFromList("Show messages targeting which object?");
	if(!pxObject) return;

	Asura_Guid uGuid = pxObject->GetGuid();
	if(uGuid == ASURA_GUID_UNREGISTERED) return;
	
	if(uGuid != s_uCurrentGuid)
	{
		//Need to lock target when choosing guids in this way , since otherwise it will be lost immediately
		s_bLockTarget = true;
		s_uCurrentGuid = uGuid;

		CreateOverlay();
	}
}