//
// Tools_Mode_GUIMenu.h
//
// Created by Richard Rice - 29/11/2006
// 
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//


#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif


#ifndef _TOOLS_MODE_GUIMENU_H_
#define _TOOLS_MODE_GUIMENU_H_
#ifdef ASURA_USE_GUI_MENU_SYSTEM

#include "Core/Asura_NameTree.h"

#include "Tools_Mode.h"
#include "Tools_Undo.h"
#include "Misc/list_tem.hpp"
#include "Misc/Tools_Platform.h"

class Asura_GUIMenu_Root;
class Asura_GUIMenu_Menu_Page;
class Asura_GUIMenu_Widget_Base;
class Tools_GUIMenu_Root;
class Tools_GUIMenu_Menu_Page;
class Tools_GUIMenu_PickItem;
class Asura_List_Dialog;
class Asura_Function_Dialog;
class Asura_TreeDialog_Tree;

#define TOOLS_MENUS_DRAG_MINX 0x00000001
#define TOOLS_MENUS_DRAG_MAXX 0x00000002
#define TOOLS_MENUS_DRAG_MINY 0x00000004
#define TOOLS_MENUS_DRAG_MAXY 0x00000008
#define TOOLS_MENUS_DRAG_MOVE 0x00000010
#define TOOLS_MENUS_DRAG_RESTRICTX 0x00000020 //used when axis restrict has been locked in
#define TOOLS_MENUS_DRAG_RESTRICTY 0x00000040 //used when axis restrict has been locked in
#define TOOLS_MENUS_DRAG_MENUOFFSET_PENDING 0x00000080 //indicates that user may be trying to alter the menu offset by dragging
#define TOOLS_MENUS_DRAG_MENUOFFSET_CONFIRMED 0x00000100 //indicates that the user is trying to alter the menu offset by dragging
#define TOOLS_MENUS_DRAG_PENDING 0x00000200 //Used to indcate that dragging/selection mode hasn't been locked in for left click yet.
#define TOOLS_MENUS_DRAG_CONFIRMED 0x00000400 //Left click has been confirmed as being for dragging.

#define TOOLS_MENUS_DRAG_MENUOFFSET (TOOLS_MENUS_DRAG_MENUOFFSET_PENDING|TOOLS_MENUS_DRAG_MENUOFFSET_CONFIRMED)

//flags for copying function
#define TOOLS_MENUS_COPY_ATCURSOR			0x00000001
#define TOOLS_MENUS_COPY_STYLE				0x00000002 //copy is part of applying a style
#define TOOLS_MENUS_COPY_STYLEINSTANCE		0x00000004 //copy is doing root item of a style
#define TOOLS_MENUS_COPY_CLAMPTOPARENT		0x00000008 //Should clamp to parent after copying
#define TOOLS_MENUS_COPY_COPYSTYLEHASH		0x00000010


//special menu item type used by StartMenuItemPlacement
#define TOOLS_GUIMENU_PASTE				-1
#define TOOLS_GUIMENU_STYLE				-2
#define TOOLS_GUIMENU_IMPORTTEXT		-3
#define TOOLS_GUIMENU_IMPORTALLTEXT		-4

class Tools_Mode_GUIMenu : public Tools_Mode
{
	friend class Tools_MessageLogAction_GUIMenu;

public :
	Tools_Mode_GUIMenu();
	~Tools_Mode_GUIMenu();

	static Tools_Mode_GUIMenu* GetInstance() {return s_pxThis;}

	virtual void InitialiseMode(void);
	virtual void ShutdownMode(void);
	
	virtual void Update(void);
	virtual void Render2D(void);
	virtual void RenderUI(void);
	virtual bool ShouldRenderDuringModalOverlay() {return true;}

	void QuickSave(void);
	virtual bool IsModified();

	//deals with style updates from outside of menu mode.
	static void DoStyleUpdateIfRequired();



	//Converts from screen coordinates to 'menu' coordinates.
	//(basically applies the zoom and offset values)
	static Asura_Vector_2 ConvertToMenuCoords(const Asura_Vector_2& xPos);
	//and the reverse
	static Asura_Vector_2 ConvertFromMenuCoords(const Asura_Vector_2& xPos);

	static Asura_Bounding_Rectangle ConvertFromMenuCoords(const Asura_Bounding_Rectangle& xRect);

	Asura_Vector_2 GetCursorPos(bool bInMenuCoords);
	static Asura_Vector_2 GetCursorPosInMenuCoords();

	static int GetOffsetX() {return s_iMenuOffsetX;}
	static int GetOffsetY() {return s_iMenuOffsetY;}
	static float GetZoom() {return s_fZoom;}

	//snaps menu coord values to grid (if snap is on)
	static const float SnapX( const float fX, bool bForceSnap  = false);
	static const float SnapY( const float fY, bool bForceSnap  = false);

	//used by Tools_GUIMenu_Root constructor/destructor to update the tree view
	void AddToTree(Tools_GUIMenu_Root* pxItem);
	void RemoveFromTree(Tools_GUIMenu_Root* pxItem);
	void UpdateParentInTree(Tools_GUIMenu_Root* pxItem);
	void UpdateNameOnTree(Tools_GUIMenu_Root* pxItem);
	void UpdateChildOrderOnTree(Tools_GUIMenu_Root* pxItem);

	void HandleItemDeletion(Tools_GUIMenu_Root* pxItem);


	//place a new element/widget
	void StartMenuItemPlacement(Tools_GUIMenu_Root* pxToolsParent,int iType,Tools_GUIMenu_Root* pxSourceItem=0);
	void CancelMenuItemPlacement();

	//prompted selection of a menu item
	void StartPromptedSelection(Tools_GUIMenu_PickItem* pxPickItem);
	void CancelPromptedSelection();

	//Creates a menu item at the specified world pos (which may be clamped to the parent's extents)
	Tools_GUIMenu_Root* CreateItem(Tools_GUIMenu_Root* pxToolsParent,int iType, const Asura_Vector_2& xPos);

	//allocates the tools class for the asura class
	static Tools_GUIMenu_Root* AllocateToolsMenuItem(Asura_GUIMenu_Root* pxAsuraItem,Tools_GUIMenu_Root* pxToolsParent);

	//get types of widgets
	int GetNumberOfWidgetTypes();
	int GetWidgetType(int iIndex);
	const char* GetWidgetTypeName(int iIndex);

	static bool ShouldResizeChildrenWithParent() {return s_bResizeChildrenWithParent;}
	static bool ShouldRepositionChildrenWithinParent() {return s_bRepositionChildrenWithinParent;}

	static float GetRespositionChildrenCornerWeighting() {return s_fRepositionChildren_CornerWeighting;}
	static float GetRespositionChildrenCentreWeighting() {return s_fRepositionChildren_CentreWeighting;}
	static float GetRespositionChildrenStickTogetherWeighting() {return s_fRepositionChildren_StickTogetherWeighting;}

	//returns true if currently previewing a menu in tools
	static bool IsPreview(){return s_bMenuPreview;}

	//returns true if the menu renderers should make use of the offset and zoom values
	//(which will be wanted if in menu mode and not previewing menus)
	static bool ShouldUseOffsetAndZoom();

	//Handles menu messages while previewing in tools
	static void MenuPreview_ProcessMessage(const struct Asura_Message_GUIMenu_Notify* pxData);

	//Find the tools item with the specified ID
	Tools_GUIMenu_Root* FindItemByID(Asura_Hash_ID uID);

	static Tools_GUIMenu_Root* GetSelectedItem(){return s_pxThis->m_pxSelectedItem;}
	static Tools_GUIMenu_Root* GetRootItem(){return s_pxThis->m_pxRoot;}

	static bool GetHideSiblings() {return s_bHideSiblings;}
	static bool ShouldRenderOutlineForHiddenItems() {return s_bRenderOutlineForHiddenItems;}
	static bool ShouldAllowMouseSelectionOfHiddenItems() {return s_bAllowMouseSelectionOfHiddenItems;}

	static void UpdateStyleList(){s_pxThis->UpdateStyleNameList();}

	static Tools_GUIMenu_Root* CreateCopy( Tools_GUIMenu_Root* pxDestParent,const Tools_GUIMenu_Root* pxSource,u_int uCopyFlags,const char* const szDestName = NULL );

	//Used when a style changes , to force any instances of it to be checked during the next update.
	static void FlagStyleForUpdate(Asura_Hash_ID uStyleID);

	//get the name of the widget/element type , used for generating default names
	const char* GetMenuItemTypeName(int iType);

	//Gets an abbreviated type name for showing on the tree view
	const char* GetShortMenuItemTypeName(int iType);

	//Removes any references to a menu item that is being deleted
	static void RemoveReferencesToMenuItem(Asura_Hash_ID uID);
	static void RemoveReferencesToStyle(Asura_Hash_ID uID);

	//Checks for various errors , adding the results to the message log
	bool Verify();

	static bool VerifyBeforeExport();

	//Sets the current selected item
	void SetSelection(Tools_GUIMenu_Root* pxItem);
	void SetSelectionByID(Asura_Hash_ID uItemHash);

	void SaveSelectionToHotkey(int iIndex,Asura_Hash_ID uID){Asura_Assert(iIndex>=0 && iIndex<12,""); m_auHotkeyedSelection[iIndex] = uID;}

	//Create a tools menu item for the supplied asura item
	static Tools_GUIMenu_Root* CreateToolsItemsForAsuraItem(Asura_GUIMenu_Root* pxAsuraItem,Tools_GUIMenu_Root* pxToolsParent) { return s_pxThis->CreateToolsMenuItems( pxAsuraItem, pxToolsParent ); }

	//for getting a name that is unique amongst all children of a menu item
	static const Asura_String GenerateUniqueName( const Tools_GUIMenu_Root* pxParent,const char* const szBaseName );
	static const bool IsNameInUse( const Tools_GUIMenu_Root* pxParent,const char* const szName );
	
	//Adds message to message log for verification process.
	static void AddVerifyMessage(const Tools_GUIMenu_Root* pxItem, const char* szFormat,...);

	//Updates menu items in response to changes to the animators
	static void HandleRenameAnimator(const char* szOldName,const char* szNewName);
	static void HandleDeleteAnimator(const char* szOldName);

	static bool ChooseText(const Asura_Hash_ID uTextPage, Asura_Hash_ID& uTextID);
	static bool ChooseTextPage(Asura_Hash_ID& uTextPage);
	static Asura_Hash_ID BrowseForTextPage();
	static void TextUpdated();

	static bool IsCopyingMenu() {return s_bCopyingMenu;}

	//undo logging
	static void LogUndo_Rectangle(const Tools_GUIMenu_Root* pxItem,const Asura_Bounding_Rectangle& xOldRect);

	// destroy menu page and any associated Tools wrapper class
	static void DestroyMenuPage( Asura_GUIMenu_Menu_Page* pxGuiMenuPage );

	//reset platform to PC when outside of GUIMenu mode for now
	static int GetPreviewPlatform(){return s_pxThis ? s_iPreviewPlatform : TOOLS_PLATFORM_PC;}

	static void AddPlatformDropDown(class Asura_Overlay* pxOverlay, Asura_Vector_2& xOffset);

	static Asura_Vector_2& GetScreenSize() {return s_xScreenSize;}
	static Asura_Vector_2& GetVirtualSize();

private :
	#define OVERLAY_VOID_CALLBACK(__FnName)\
	static void __FnName(int iThis){((Tools_Mode_GUIMenu*)iThis)->__FnName();}\
	void __FnName();

	#define OVERLAY_BOOL_CALLBACK(__FnName)\
	static bool __FnName(int iThis){return ((Tools_Mode_GUIMenu*)iThis)->__FnName();}\
	bool __FnName();

	OVERLAY_VOID_CALLBACK(CreateFile)

	OVERLAY_BOOL_CALLBACK(CanCreateMenu)
	OVERLAY_VOID_CALLBACK(CreateMenu)

	OVERLAY_BOOL_CALLBACK(CanCopy)
	OVERLAY_VOID_CALLBACK(Copy)

	OVERLAY_BOOL_CALLBACK(CanPaste)
	OVERLAY_VOID_CALLBACK(Paste)

	OVERLAY_BOOL_CALLBACK(CanPasteOver)
	OVERLAY_VOID_CALLBACK(PasteOver)

	OVERLAY_BOOL_CALLBACK(CanPreviewMenu)
	OVERLAY_VOID_CALLBACK(MenuPreview)

	OVERLAY_BOOL_CALLBACK(CanCreateStyleInstance)
	OVERLAY_VOID_CALLBACK(CreateStyleInstance)

	OVERLAY_BOOL_CALLBACK(CanApplyStyle)
	OVERLAY_VOID_CALLBACK(ApplyStyle)
	OVERLAY_BOOL_CALLBACK(CanGotoStyle)
	OVERLAY_VOID_CALLBACK(GotoStyle)

	OVERLAY_VOID_CALLBACK(FindItemByIDSelectedByUser)
	OVERLAY_VOID_CALLBACK(FindMenuByName)
	OVERLAY_VOID_CALLBACK(FindByTexture)

	OVERLAY_VOID_CALLBACK(ManualVerify)

	enum
	{
		eLIST_ALL_TEXT_MODIFIERS,
		eLIST_TEXT_MODIFIERS_CURRENTLY_SELECTED_MENU,
		eLIST_TEXT_MODIFIERS_CURRENTLY_SELECTED_FILE,
	};
	static void ListTextModifiers( int iValue );
	static bool IsEnabledForCurrentlySelectedMenu( void );
	static bool IsEnabledForCurrentlySelectedFile( void );
	static Asura_Function_Dialog* s_pxListTextModifiersCurrentlySelectedMenu;
	static Asura_Function_Dialog* s_pxListTextModifiersCurrentlySelectedFile;

	OVERLAY_VOID_CALLBACK(EditTextureFlags)


	#undef OVERLAY_BOOL_CALLBACK
	#undef OVERLAY_VOID_CALLBACK

	static void ReloadText();
	static void ReloadText(int iLanguage);

	void TransferModeData(int iMode);

	void CreateOverlay();

	void CreateStyleOverlay();
	void CloseStyleOverlay();
	static void ToggleStyleOverlay();
	static bool StyleOverlayIsOn();

	void RenderBackdrop();
	void RenderGrid();
	void RenderSafeArea();
	void RenderScreenBorder();



	//gets the menu/element/widget beneath the cursor
	Tools_GUIMenu_Root* GetItemUnderCursor();

	void HandleMouse();
	void HandleKeyboard();
	void MenuPreview_HandleKeyboard();

	void SetSelectionFromTree();
	
	static void ImportText(int iType);
	static void CreateWidget(int iType);
	static bool CanCreateWidget();
	void CreateItemAtCursor(Tools_GUIMenu_Root* pxToolsParent,int iType);

	//create a widget/element of a given type
	//Asura_GUIMenu_Root* AllocateAsuraMenuItem(int iType);

	void DeleteMenuItem(Tools_GUIMenu_Root* pxItem);

	//creates the tools data when entering this mode
	void CreateToolsMenuItems();
	Tools_GUIMenu_Root* CreateToolsMenuItems(Asura_GUIMenu_Root* pxAsuraItem,Tools_GUIMenu_Root* pxToolsParent);

	//Checks if a key is pressed , and not currently being used by a selected item for other purposes
	bool DebouncedKeyPressed(int iKey);
	bool KeyPressed(int iKey);

	Tools_GUIMenu_Root* DetermineParentForPaste();
	void PasteAtCursor();
	static Tools_GUIMenu_Root* CreateCopy(Tools_GUIMenu_Root* pxDestParent,const Tools_GUIMenu_Root* pxSource,u_int uCopyFlags,List<struct Tools_GUIMenu_HashPair>* pxOutputHashMapping,const char* const szDestName = NULL );

	//Update refereneces after a copy so a duplicated menu will work correctly
	static void UpdateAfterCopy(Tools_GUIMenu_Root* pxToolsItem,List<struct Tools_GUIMenu_HashPair>* pxOutputHashMapping);

	//Get a menu item corresponding to a file
	Tools_GUIMenu_Root* GetFileMenuItem(const char* szFilename,bool bCreate);

	void MenuPreview_Start();
	void MenuPreview_End();
	void MenuPreview_Update();
	void MenuPreview_Render();

	void MenuPreview_InitialiseListBox(Asura_Hash_ID uID);

	void BuildStyleTypeList();
	void DeleteStyleTypeList();
	void UpdateStyleNameList();
	void DeleteStyleNameList();

	static int SortStyleCallback(const void* pItem1,const void*pItem2);
	Tools_GUIMenu_Root* GetParentForStyle(Tools_GUIMenu_Root* pxStyle);

	void HandleStyleUpdates();

	void BuildLanguageList();
	void DeleteLanguageList();	

	//Prompts for name for a new menu , and ensures that it is unique.
	static const bool AskForMenuName(Asura_String& xName);

	//For use by the prompted selection when selecting from a list
	void PromptedSelection_SelectFromList();
	void PromptedSelection_AddToListOverlay(Tools_GUIMenu_Root* pxItem,class ListSelection_Overlay* pxOverlay);

	//Gets offset to apply when rendering the screen border/safe area when outsie of menu preview.
	//This is just intended for taking into account the offset that would be applied from
	//menus that have the recentre flag
	Asura_Vector_2 GetScreenBorderOffsetForCurrentMenu();

	//enable/disable clipping to the area defined by s_iScreenWidth and s_iScreenHeight
	static void EnableClipping();
	static void DisableClipping();

	static void UpdateScreenSettingsFromPreset();

	void PrevLanguage();
	void NextLanguage();
	void PrevScreenPreset();
	void NextScreenPreset();

	void Undo();
	void Redo();



	static u_int s_uBackgroundColour;
		
	static u_int s_uGridColour;
	static bool s_bShowGrid;
	static int s_iGridSize;
	static float s_fZoom;
	static int s_iMenuOffsetX;
	static int s_iMenuOffsetY;
	static int s_iGridOriginX;
	static int s_iGridOriginY;
	static bool s_bSnapToGrid;
	static bool s_bResizeChildrenWithParent;
	static bool s_bRepositionChildrenWithinParent;
	static float s_fRepositionChildren_CornerWeighting;
	static float s_fRepositionChildren_CentreWeighting;
	static float s_fRepositionChildren_StickTogetherWeighting;

	static bool s_bHideSiblings;
	static bool s_bRenderOutlineForHiddenItems;
	static bool s_bAllowMouseSelectionOfHiddenItems;
	static bool s_bDisableBilinearFiltering;

	static bool s_bMenuPreview;

	static bool s_bInitialUseCursor;

	static Asura_Vector_2 s_xScreenSize;
	static Asura_Vector_2 s_xVirtualSize;
	static Asura_Bounding_Rectangle s_xSafeArea;
	static bool s_bShowScreenBorder;
	static bool s_bShowSafeArea;
	static u_int s_uScreenBorderColour;
	static u_int s_uSafeAreaColour;
	static bool s_bClipToScreen;
	static int s_iScreenSettingPreset;
	static int s_iPreviewPlatform;//platform to use when previewing menus
	static const char** s_pszPlatformNames;

	static bool s_bCopyingMenu;


	Asura_Handle m_iMenuHandle;
	
	Asura_Vector_2 m_xOverlayPosition;
	u_int m_uOverlayMinimised;
	Asura_Vector_2 m_xStyleOverlayPosition;
	u_int m_uStyleOverlayMinimised;
	bool m_bStyleOverlayOpen;

	//drag state
	bool m_bDrag;
	u_int m_uDragFlags;
	Asura_Vector_2 m_xDragStart;//in menu coords
	int m_iPreDragMenuOffsetX;
	int m_iPreDragMenuOffsetY;

	//tree of menu elements/widgits for selecting by name
	Asura_TreeDialog_Tree* m_pxTree;
	bool m_bTreeSelectionChanged;

	//used while placing a new widget/element
	bool m_bItemPlacement;
	int m_iPlacementType;
	Tools_GUIMenu_Root* m_pxPlacementSource;//item being copied or style being placed
	Tools_GUIMenu_Root* m_pxPlacementParent;

	Tools_GUIMenu_PickItem* m_pxPickItem;

	//the menu being edited
	Tools_GUIMenu_Menu_Page* m_pxToolsMenu;
	
	//Fake item that is used as the root for all the menus
	Tools_GUIMenu_Root* m_pxRoot;

	Tools_GUIMenu_Root* m_pxSelectedItem;

	//item for copy/paste.
	Tools_GUIMenu_Root* m_pxClipboardItem;

	//Store of dummy strings to use when previewing list boxes
	List<Asura_String> m_xListBoxText;

	//for the drop down list of style menu item types
	int m_iNumStyleTypes;
	const char** m_pszStyleTypeNames;
	int* m_piStyleTypes;
	int m_iStyleTypeIndex;
	bool m_bStyleTypeChanged;

	//for list of available languages
	int m_iLanguageListSize;
	const char** m_pszLanguageNames;
	int* m_piLanguageIDs;
	int m_iLanguageIndex;

	//for the list of styles
	int m_iNumStyles;
	Tools_GUIMenu_Root** m_ppxStyleItems;
	char** m_pszStyleNames;
	int m_iStyleIndex;
	Asura_List_Dialog* m_pxStyleListDialog;

	List<Asura_Hash_ID> m_xStyleUpdateList;

	//for hotkeying selected menu items
	Asura_Hash_ID m_auHotkeyedSelection[12];

	bool m_bTemporaryModeInstance;//inidicates that mode is only being created for dealing with style updates or verify
	static bool s_bDoneOneOffStyleUpdate;

	//For detecting resolution changes ,so the main overlay can be resized
	int m_iPreviousScreenHeight;

	//the instance of the undo system for this mode
	VariableSizeUndo m_xUndo;
	bool m_bDisableUndoLogging;

	// display isolation flag.
	bool m_bIsolateDisplay;

	
	//the most recent file (changed to static as part of makeing all CreateCopy methods static - NDB 180208)
	static Tools_GUIMenu_Root* s_pxToolsMenuFile;

	static Tools_Mode_GUIMenu* s_pxThis;
};


class Tools_GUIMenu_PickItem
{
public :
	virtual ~Tools_GUIMenu_PickItem(){}

	virtual const char* GetPrompt(){return "";}
	virtual bool IsValidSelection(Tools_GUIMenu_Root* pxItem) {return false;}
	virtual void OnFinish(Tools_GUIMenu_Root* pxSelection){}
};


struct Tools_GUIMenu_HashPair
{
	Asura_Hash_ID m_uOldID;
	Asura_Hash_ID m_uNewID;
};

enum Tools_GUIMenu_ScreenSettings
{
	TOOLS_GUIMENU_SCREENSETTINGS_CURRENTRES,
	TOOLS_GUIMENU_SCREENSETTINGS_PSP,
	TOOLS_GUIMENU_SCREENSETTINGS_PS2_PAL,
	TOOLS_GUIMENU_SCREENSETTINGS_PS2_NTSC,
	TOOLS_GUIMENU_SCREENSETTINGS_PS2_NTSC_WIDE,
	TOOLS_GUIMENU_SCREENSETTINGS_WII_PAL_4_3,
	TOOLS_GUIMENU_SCREENSETTINGS_WII_PAL_16_9,
	TOOLS_GUIMENU_SCREENSETTINGS_WII_NTSC_4_3,
	TOOLS_GUIMENU_SCREENSETTINGS_WII_NTSC_16_9,

	TOOLS_GUIMENU_SCREENSETTINGS_PS3_4_3,
	TOOLS_GUIMENU_SCREENSETTINGS_PS3_16_9,

	TOOLS_GUIMENU_SCREENSETTINGS_XBOX360_4_3_REQUIRED,
	TOOLS_GUIMENU_SCREENSETTINGS_XBOX360_4_3_RECOMMENDED,

	TOOLS_GUIMENU_SCREENSETTINGS_XBOX360_16_9_REQUIRED,
	TOOLS_GUIMENU_SCREENSETTINGS_XBOX360_16_9_RECOMMENDED,


	TOOLS_GUIMENU_NUM_SCREENSETTINGS,
};



#endif //ASURA_USE_GUI_MENU_SYSTEM
#endif //_TOOLS_MODE_GUIMENU_H_
