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

#include "Core/Asura.h"
#include "GUIMenu/Tools_GUIMenu_Widget_Button.h"

#ifdef ASURA_USE_GUI_MENU_SYSTEM

#include "Interface/Asura_Dialog.h"
#include "Interface/Asura_Overlay.h"
#include "GUIMenu/Asura_GUIMenu_Menu_Page.h"
#include "GUIMenu/Asura_GUIMenu_System.h"
#include "GUIMenu/Asura_GUIMenu_Widget_Button.h"

#include "Rendering/Asura_Render.h"
#include "Rendering/Asura_Text_Output.h"

#include "GUIMenu/Tools_GUIMenu_CommandConsole.h"
#include "GUIMenu/Tools_GUIMenu_System.h"
#include "GUIMenu/Tools_GUIMenu_Widget_Base.h"
#include "GUIMenu/Tools_GUIMenu_PreviewOverlay.h"
#include "Misc/Tools_MessageLog.h"
#include "Misc/Tools_Timed_Messages.h"

// -- static class vars --
Tools_GUIMenu_Widget_Button* Tools_GUIMenu_Widget_Button::s_pxSelectedButton = 0;

Tools_GUIMenu_Widget_Button::Tools_GUIMenu_Widget_Button(Asura_GUIMenu_Widget_Button* pxAsuraButton,Tools_GUIMenu_Root* pxToolsParent)
:Tools_GUIMenu_Widget_Base(pxAsuraButton,pxToolsParent)
{
	m_pxAsuraButton = pxAsuraButton;

	m_iHotLinkMenuDropDownIndex = 0;
	m_iHotLinkWidgetDropDownIndex = 0;

	m_hashMenuID		= ASURA_HASH_ID_UNSET;
	m_hashWidgetID		= ASURA_HASH_ID_UNSET;

	m_pxWidgetListBox	= NULL;

	m_bMaxActionsChanged = false;
}

// -------------------------------------------------------------------------------------------------

Tools_GUIMenu_Widget_Button::~Tools_GUIMenu_Widget_Button()
{
	m_pxWidgetListBox	= NULL;
}

// -------------------------------------------------------------------------------------------------

void Tools_GUIMenu_Widget_Button::Update()
{
	if(m_bChanged)
	{
		if ((m_pxAsuraButton->GetButtonFlags() & ASURA_GUIMENU_BUTTON_FLAG_GO_BACK) != 0)
		{
			*m_pxAsuraButton->GetButtonFlagsAsPtr() |= ASURA_GUIMENU_BUTTON_FLAG_DONT_SET_BACKLINK;
		}
	}

	PARENT::Update();

	if( m_bMaxActionsChanged)
	{
		Tools_GUIMenu_Root::DeleteOverlay();
		Tools_GUIMenu_Root::CreateOverlay();
		m_bMaxActionsChanged = false;
		m_bChanged = true;
		SetModified();
	}
}

// -------------------------------------------------------------------------------------------------

void Tools_GUIMenu_Widget_Button::OnDeselection()
{
	s_pxSelectedButton = 0;

	PARENT::OnDeselection();
}

// -------------------------------------------------------------------------------------------------

void Tools_GUIMenu_Widget_Button::OnSelection()
{
	PARENT::OnSelection();

	s_pxSelectedButton = this;

}

// -------------------------------------------------------------------------------------------------

void Tools_GUIMenu_Widget_Button::AddOverlayControls(Asura_Overlay* pxOverlay,Asura_Vector_2& xOffset)
{
	const Asura_Char** ppszList;
	int iPageCount, iWidgetCount;
	Asura_Dialog* pxDialog;
	Asura_GUIMenu_Root* pxHotLinkObject = NULL;
	Asura_GUIMenu_Root* pxMenuObject = NULL;
	Asura_GUIMenu_Menu_Page* pxMenuPage;
	Asura_Hash_ID hashMenuID = ASURA_HASH_ID_UNSET;
	Asura_Hash_ID hashWidgetID = ASURA_HASH_ID_UNSET;

	PARENT::AddOverlayControls(pxOverlay,xOffset);
	
	xOffset.y += Asura_Dialog::DefaultSpacing();

	ppszList = (const Asura_Char**)Tools_GUIMenu_System::GetAvailableMenuPageNames( &iPageCount);

	pxDialog = new Asura_StringDisplay_Dialog( ".::Hot Link Options ::.", xOffset);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

    Asura_Hash_ID hashHotLink = m_pxAsuraButton->GetLinkToHash();
	
	if( hashHotLink != ASURA_HASH_ID_UNSET)
	{
		pxHotLinkObject = Asura_GUIMenu_System::FindRootObjectByID( hashHotLink);
	}

	m_iHotLinkMenuDropDownIndex = 0;
	m_iHotLinkWidgetDropDownIndex = 0;

	if( pxHotLinkObject != NULL)
	{
		// -- work out id's for menu and widget list boxes --
		if( pxHotLinkObject->GetType() != Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_MENUPAGE)
		{
			pxMenuObject = Asura_GUIMenu_System::FindParentMenuOfObjectID( hashHotLink);
			
			hashMenuID = pxMenuObject->GetID();
			hashWidgetID = pxHotLinkObject->GetID();
		}
		else
		{
			hashMenuID = pxHotLinkObject->GetID();
		}

		m_hashMenuID = hashMenuID;
		m_hashWidgetID = hashWidgetID;

		// -- calculate index for selected menu
		if( hashMenuID != ASURA_HASH_ID_UNSET)	// this data has an id set, so use it
		{
			for( u_int i=0; i<Asura_GUIMenu_System::GetCurrentMenuListCount(); ++i )
			{
				pxMenuPage = Asura_GUIMenu_System::GetMenuPageByIndex( i);

				if( pxMenuPage->GetID() == hashMenuID)
				{
						// found a match, so set the starting index in the dropdown list to this one.
						m_iHotLinkMenuDropDownIndex = i+1;
						break;
				}
			}
		}
	}	

	Asura_DropDown_List_Dialog* pxDropList = new Asura_DropDown_List_Dialog( xOffset,
													ppszList,
													&m_iHotLinkMenuDropDownIndex,
													12, 
													iPageCount,
													NULL, 0, "Menu Pages");

	// Don't sort the first item in the list of stings as this is "None" and
	// should stay at the top of the list.
	pxDropList->SetSortStrings(true,1);

	pxDropList->SetIsEnabledFunction(CanEditButtonLink);

	pxDropList->SetOnSelectCallback( MenuNameListBoxCallBack);

	pxOverlay->AddDialog( pxDropList);
	xOffset.y += Asura_Dialog::LargeSpacing();
	
	const Asura_Hash_ID* puHashIDs = NULL;
	ppszList = Tools_GUIMenu_System::GetAllMenuWidgetNames( hashMenuID, &iWidgetCount,&puHashIDs);

	if( pxHotLinkObject != NULL)
	{
		// -- calculate index for selected widget --
		// Calculation of the widget is delayed until after the call to Tools_GUIMenu_System::GetAllMenuWidgetNames as we
		// need a list of strings and corresponding hash IDs.
		// Use the hash ID to find the index number for the drop down list.
		if( hashMenuID != ASURA_HASH_ID_UNSET)	// this data has an id set, so use it
		{
			pxMenuPage = Asura_GUIMenu_System::GetMenuPageByIndex( m_iHotLinkMenuDropDownIndex - 1);

			for( int i=0; i < iWidgetCount; i++)
			{
				if ( puHashIDs[i] == hashWidgetID )
				{
					m_iHotLinkWidgetDropDownIndex = i;
				}
			}
		}
	}

	m_pxWidgetListBox = new Asura_DropDown_List_Dialog(xOffset,
												ppszList,
												&m_iHotLinkWidgetDropDownIndex,
												12, 
												iWidgetCount,
												NULL, 0, "Available Widgets");
	m_pxWidgetListBox->SetIsEnabledFunction(CanEditButtonLink);

	m_pxWidgetListBox->SetOnSelectCallback( WidgetNameListBoxCallBack);

	pxOverlay->AddDialog( m_pxWidgetListBox);
	xOffset.y += Asura_Dialog::LargeSpacing();

	pxDialog = new Asura_FlagTickbox_Dialog( "Close Menu On Click", xOffset, m_pxAsuraButton->GetButtonFlagsAsPtr(), ASURA_GUIMENU_BUTTON_FLAG_CLOSE_MENU_ONCLICKED, &m_bChanged );
	pxDialog->SetIsEnabledFunction(CanEditButtonFlags);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_FlagTickbox_Dialog( "Auto Click", xOffset, m_pxAsuraButton->GetButtonFlagsAsPtr(), ASURA_GUIMENU_BUTTON_FLAG_AUTOCLICK, &m_bChanged );
	pxDialog->SetIsEnabledFunction(CanEditButtonFlags);
	pxDialog->SetHelpText("If ticked, this button behaves as if it were clicked on as soon as its display condition is met.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_FlagTickbox_Dialog( "Don't Set 'Back' Link", xOffset, m_pxAsuraButton->GetButtonFlagsAsPtr(), ASURA_GUIMENU_BUTTON_FLAG_DONT_SET_BACKLINK, &m_bChanged );
	pxDialog->SetIsEnabledFunction(CanEditButtonFlags);
	pxDialog->SetHelpText("If ticked, this button won't allow the target menu to return to this one using normal 'back' functionality. Use this for buttons that navigate back through a menu tree.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_FlagTickbox_Dialog( "Trap 'Back' Keypress", xOffset, m_pxAsuraButton->GetButtonFlagsAsPtr(), ASURA_GUIMENU_BUTTON_FLAG_TRAP_BACK_KEYPRESS, &m_bChanged );
	pxDialog->SetIsEnabledFunction(CanEditButtonFlagTrapBackKeypress);
	pxDialog->SetHelpText("If ticked, this button takes care of the back/cancel action for the menu page. Ignored unless \"Don't Set 'Back' Link\" is ticked.");
	pxDialog->SetRadioButtonGroup(Asura_GetHashID("GUIMenuBackOptions"), false);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_FlagTickbox_Dialog( "Go Back On Clicked", xOffset, m_pxAsuraButton->GetButtonFlagsAsPtr(), ASURA_GUIMENU_BUTTON_FLAG_GO_BACK, &m_bChanged );
	pxDialog->SetIsEnabledFunction(CanEditButtonFlags);
	pxDialog->SetHelpText("If ticked, this button Will follow the 'Back' link when clicked.");
	pxDialog->SetRadioButtonGroup(Asura_GetHashID("GUIMenuBackOptions"), false);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_FlagTickbox_Dialog( "Duplicate 'Back' Link", xOffset, m_pxAsuraButton->GetButtonFlagsAsPtr(), ASURA_GUIMENU_BUTTON_FLAG_DUPLICATE_BACKLINK, &m_bChanged );
	pxDialog->SetIsEnabledFunction(CanEditButtonFlags);
	pxDialog->SetHelpText("If ticked, this button will set the target menu to return to the menu before this one. Use this for buttons that swap sideways to another menu.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_FlagTickbox_Dialog( "Check KeyPresses", xOffset, m_pxAsuraButton->GetButtonFlagsAsPtr(), ASURA_GUIMENU_BUTTON_FLAG_POLL_BUTTON_PRESSES, &m_bChanged );
	pxDialog->SetIsEnabledFunction(CanEditButtonFlags);
	pxDialog->SetHelpText("If ticked, this button will check for the action commands even when it's not highlighted.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	// "time before X" variables are lumped in with the button flags for Style purposes
	pxDialog = new Asura_Numerical_Dialog( "Min Time Before Active", xOffset, &m_pxAsuraButton->m_fMinTimeBeforeActive, 0.0f, 999.9f, 0.1f, "%.1f", &m_bChanged );
	pxDialog->SetIsEnabledFunction(CanEditButtonFlags);
	pxDialog->SetHelpText("Time after menu opens before this button appears and is available.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Numerical_Dialog( "Time Before Autoclick", xOffset, &m_pxAsuraButton->m_fTimeBeforeAutoclick, 0.0f, 999.9f, 0.1f, "%.1f", &m_bChanged );
	pxDialog->SetIsEnabledFunction(CanEditTimeBeforeAutoclick);
	pxDialog->SetHelpText("Time before this button autoclicks.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	// add controls for command to execute
	m_pxAsuraButton->m_xCommandManager.AddOverlayControls( pxOverlay, xOffset, true, true, &m_bChanged, &m_bMaxActionsChanged);
}

// -------------------------------------------------------------------------------------------------

void Tools_GUIMenu_Widget_Button::UpdateOverlayControls(Asura_Overlay* pxOverlay)
{
	PARENT::UpdateOverlayControls(pxOverlay);
}

// -------------------------------------------------------------------------------------------------

void Tools_GUIMenu_Widget_Button::UpdateReferences(Asura_Hash_ID uOldID,Asura_Hash_ID uNewID,bool bPostCopy)
{
	PARENT::UpdateReferences( uOldID, uNewID, bPostCopy);

	if( GetHotLink() == uOldID)
	{
		if( uNewID == ASURA_HASH_ID_UNSET)
		{
			Tools_Timed_Message_System::AddUnloggedMessage(0xff0000, "The menu hotlink in Button Widget: %s is no longer valid.", m_pxAsuraButton->GetNameAsChar());
			Tools_Timed_Message_System::AddUnloggedMessage(0xff0000, "This suggests that the hotlink menu has been deleted");
			Tools_Timed_Message_System::AddUnloggedMessage(0xff0000, "or set as code driven from it's menu flags.");	
			Tools_Timed_Message_System::AddUnloggedMessage(0xff0000, "Clearing Hotlink hash to ASURA_HASH_ID_UNSET.");	
			Tools_Mode_GUIMenu::AddVerifyMessage(this,"The menu hotlink in Button Widget: %s is no longer valid.", m_pxAsuraButton->GetNameAsChar());
			Tools_MessageLog::ShowOverlay();
		}

		SetHotLink( uNewID);
		SetModified();
	}
}
// -------------------------------------------------------------------------------------------------
// -- Private functions ----------------------------------------------------------------------------

void Tools_GUIMenu_Widget_Button::SetHotLink( Asura_Hash_ID hashID)
{
	m_pxAsuraButton->SetLinkToHash( hashID);
	SetModified();
}

// -------------------------------------------------------------------------------------------------

Asura_Hash_ID Tools_GUIMenu_Widget_Button::GetHotLink()
{
	return m_pxAsuraButton->GetLinkToHash();
}

// -------------------------------------------------------------------------------------------------

void Tools_GUIMenu_Widget_Button::MenuNameListBoxCallBack()
{
	if (s_pxSelectedButton)
	{
		int iWidgetCount = 0;

		Asura_Hash_ID uMenuID = ASURA_HASH_ID_UNSET;

		s_pxSelectedButton->SetWidgetSelectionIndex( 0);

		Asura_DropDown_List_Dialog* pxWidgetListBox = s_pxSelectedButton->GetWidgetListBoxPtr();

		int iSelectedIndex = s_pxSelectedButton->GetMenuSelectionIndex();

		if( iSelectedIndex != 0)
		{
			Asura_GUIMenu_Root* pxMenuPage = Asura_GUIMenu_System::GetMenuPageByIndex( iSelectedIndex - 1);

			if (pxMenuPage)
			{
				uMenuID = pxMenuPage->GetID();
			}
			
			if (pxWidgetListBox)
			{
				const Asura_Char** ppszList = Tools_GUIMenu_System::GetAllMenuWidgetNames( uMenuID, &iWidgetCount);
				pxWidgetListBox->ReplaceStrings( iWidgetCount, ppszList);
			}
		}
		else
		{
			uMenuID = ASURA_HASH_ID_UNSET;

			if (pxWidgetListBox)
			{
				const Asura_Char** ppszList = Tools_GUIMenu_System::GetAllMenuWidgetNames( 0, &iWidgetCount);
				pxWidgetListBox->ReplaceStrings( iWidgetCount, ppszList);
			}
		}
		
		s_pxSelectedButton->SetSelectedMenuID( uMenuID);
		s_pxSelectedButton->SetHotLink( uMenuID);

		s_pxSelectedButton->SetModified();
		s_pxSelectedButton->m_bChanged = true;
	}
}

// -------------------------------------------------------------------------------------------------

void Tools_GUIMenu_Widget_Button::WidgetNameListBoxCallBack()
{
	if (s_pxSelectedButton)
	{
		// we put the menu id here, so if there is no widget selected it's the menu that's made into the hot link
		Asura_Hash_ID uHotLinkID = s_pxSelectedButton->GetSelectedMenuID();
		Asura_Hash_ID uWidgetID = ASURA_HASH_ID_UNSET;

		int iSelectedIndex = s_pxSelectedButton->GetWidgetSelectionIndex();

		const Asura_Hash_ID* pHashID = Tools_GUIMenu_System::GetCurrentHashIds();

		if( iSelectedIndex != 0)
		{
			Asura_GUIMenu_Root* pxMenuRoot = Asura_GUIMenu_System::GetMenuPageByID( s_pxSelectedButton->GetSelectedMenuID());
			if( pxMenuRoot)
			{
				Asura_GUIMenu_Menu_Page* pxMenuPage = static_cast<Asura_GUIMenu_Menu_Page*>(pxMenuRoot);

				// Find the widget using the hash ID.
				Asura_GUIMenu_Root* pxWidget = pxMenuPage->FindContainerItemByID(pHashID[iSelectedIndex]);

				if( pxWidget)
				{
					uHotLinkID = uWidgetID = pxWidget->GetID();
				}
			}
		}

		s_pxSelectedButton->SetSelectedWidgetID( uWidgetID);
		s_pxSelectedButton->SetHotLink( uHotLinkID);

		s_pxSelectedButton->SetModified();
		s_pxSelectedButton->m_bChanged = true;
	}
}


void Tools_GUIMenu_Widget_Button::Copy(const Tools_GUIMenu_Root* pxSource)
{
	PARENT::Copy(pxSource);

	const Tools_GUIMenu_Widget_Button* pxSourceButton = (const Tools_GUIMenu_Widget_Button*) pxSource;

	//copy tools data
	m_hashMenuID = pxSourceButton->m_hashMenuID;
	m_hashWidgetID = pxSourceButton->m_hashWidgetID;
}

u_int Tools_GUIMenu_Widget_Button::GetFlagsToEdit() const
{
	return PARENT::GetFlagsToEdit() | ASURA_GUIMENU_ACTION_FLAG_NOTIFY_DATA_CHANGE_IMMEDIATE;
}

const char* Tools_GUIMenu_Widget_Button::GetLocalDataFlagName(u_int uFlagValue) const
{
	switch(uFlagValue)
	{
		case Asura_GUIMenu_Widget_Button::ASURA_GUIMENU_WIDGET_BUTTON_LOCAL_FLAG_LINKTO :
			return "Button Link";
			break;

		case Asura_GUIMenu_Widget_Button::ASURA_GUIMENU_WIDGET_BUTTON_LOCAL_FLAG_FLAGS :
			return "Button Flags & Settings";
			break;

		default :
			return PARENT::GetLocalDataFlagName(uFlagValue);

	}
}


bool Tools_GUIMenu_Widget_Button::CanEditButtonLink()
{
	if (!s_pxSelectedButton)
	{
		return false;
	}
	return s_pxSelectedButton->ShouldStyleUseLocalDataFor(Asura_GUIMenu_Widget_Button::ASURA_GUIMENU_WIDGET_BUTTON_LOCAL_FLAG_LINKTO);
}

bool Tools_GUIMenu_Widget_Button::CanEditButtonFlags()
{
	if (!s_pxSelectedButton)
	{
		return false;
	}
	return s_pxSelectedButton->ShouldStyleUseLocalDataFor(Asura_GUIMenu_Widget_Button::ASURA_GUIMENU_WIDGET_BUTTON_LOCAL_FLAG_FLAGS);
}

bool Tools_GUIMenu_Widget_Button::CanEditButtonFlagTrapBackKeypress()
{
	// only does anything if the button navigates like a back keypress.
	if (!s_pxSelectedButton)
	{
		return false;
	}
	return s_pxSelectedButton->ShouldStyleUseLocalDataFor(Asura_GUIMenu_Widget_Button::ASURA_GUIMENU_WIDGET_BUTTON_LOCAL_FLAG_FLAGS);
}

bool Tools_GUIMenu_Widget_Button::CanEditTimeBeforeAutoclick()
{
	if (!s_pxSelectedButton)
	{
		return false;
	}
	if (!s_pxSelectedButton->m_pxAsuraButton->IsButtonFlagSet(ASURA_GUIMENU_BUTTON_FLAG_AUTOCLICK))
	{
		return false;
	}
	return s_pxSelectedButton->ShouldStyleUseLocalDataFor(Asura_GUIMenu_Widget_Button::ASURA_GUIMENU_WIDGET_BUTTON_LOCAL_FLAG_FLAGS);
}

void Tools_GUIMenu_Widget_Button::AddToPreviewOverlay() const
{
	PARENT::AddToPreviewOverlay();

	//register all the console commands used
	Asura_GUIMenu_CommandManager* pxManager = &m_pxAsuraButton->m_xCommandManager;

	for(u_int i=0;i<pxManager->GetActionButtonCount();i++)
	{
		const Asura_GUIMenu_ActionButtonCommand* pxCmd = pxManager->GetActionButtonCommandData(i);
		if(pxCmd->m_xCommand.IsBlank()) continue;

		// (MH - 04.09.2008) no need to register action commands.
		//Tools_GUIMenu_PreviewOverlay::RegisterConsoleCommand(pxCmd->m_xCommand.m_xConsoleCmdName.GetString());
	}
}

bool Tools_GUIMenu_Widget_Button::Verify()
{
	bool bRes;

	bRes = PARENT::Verify();

	//check for broken hotlinks
	Asura_Hash_ID uHotLinkID = m_pxAsuraButton->GetLinkToHash();
	if(uHotLinkID)
	{
		Tools_GUIMenu_Root* pxHotLinkItem = Tools_Mode_GUIMenu::GetInstance()->FindItemByID(uHotLinkID);
		if(!pxHotLinkItem)
		{
			Tools_Mode_GUIMenu::AddVerifyMessage(this,"The hotlink item for button %s in %s can't be found.",GetName(),GetMenuPage()->GetName());
			return false; // An error has occured so return false anyway
		}
	}

	return bRes;
}



#endif //ASURA_USE_GUI_MENU_SYSTEM
