//
// Tools_SecondaryEntityFile_System.h
//
// Created by Richard Rice - 21/04/2005
// 
// Copyright (C) 2005 Rebellion, All Rights Reserved.
//


#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef _TOOLS_SECONDARYENTITYFILE_SYSTEM_H_
#define _TOOLS_SECONDARYENTITYFILE_SYSTEM_H_

#include "Core/Asura_String.h"
#include "Network/Asura_Guid.h"
#include "misc/list_tem.hpp"

#include "EntityTemplate/Tools_EntityTemplate_System.h"

class Tools_SecondaryEntityFile;
class Asura_TreeDialog_Tree;
class Asura_TreeDialog_Item;

struct EntityListElement 
{
	Asura_String xName;
	int			 iToolsID;
};

class Tools_SecondaryEntityFile_System
{
public :
	static void Initialise();
	static void Shutdown();
	static void Reset(){Shutdown();Initialise();}


	//displayes message first time this is called ,if multiple entity files are in use
	static void SelectInitialEntityFile();

	//returns true if using any secondary files.
	static bool AnySecondaryFiles(){return s_xFileList.size()>1;}

	//Per frame update
	static void Update();

	static void ProcessHistoryList();
	static void RemoveFromHistoryList(class Tools_Object* pxObject);

	//creates the tree
	static void CreateTree();

	//Forces the tree to be regenerated during the next update.
	static void InvalidateTree() {s_bTreeValid = false;}
	static bool IsTreeValid() {return s_bTreeValid;}


	static bool IsEditingSecondaryFile(){return s_pxCurrentFile!=0;}

	//Adds the entity associated with the object to the current entity file.
	static void AddToCurrentFile(class Tools_Object* pxObject);
	//And similarly for a specific file;
	static void AddToFile(class Tools_Object* pxObject, const char* szEntityFile, const char* szFolder);

	//Adds file entry from chunk	
	static void AddFileFromLoad(const char* pszName,int iFileVersion,int iNextID, int iChunkFlags);

	//Generates the filename for the entity file from its name
	static void GenerateFilename(const char* pszName,bool bMissionDir,Asura_String& xOutputFilename);
	static void GenerateFilename(const Tools_SecondaryEntityFile* pxFile,Asura_String& xOutputFilename);

	//attempt to save all the secondary entity files
	static void SaveFiles();

	static void MakeBackups();


	//Checks to see if secondary enttiy file can be saved. If name is blank/null it checks the main entity file
	static bool CanSaveFile(const Tools_SecondaryEntityFile* pxFile);
	static bool CanSaveFile(const char* szFile);
	static bool CanSaveFileCached(const Tools_SecondaryEntityFile* pxFile);

	//shows a warning if the current entity file is read only
	static void WarnIfCurrentFileIsReadOnly();

	//add version info chunks for secondary files to entity file
	static void AddChunksToFile(class Asura_SaveBlock* pxSaveBlock);

	//Updates entities from the secondary entity files , provided this hasn't been done yet.
	static void UpdateFromSecondaryFiles();

	//The modified flag here is just used for warning about readonly files , since
	//all the entity files get saved at the same time regardless.
	static void SetFileModified(const char* pszName);

	//Determines whether the targeted object is safe for messages for the given entity file
	//based on what is writeable.
	static bool IsAllowableTarget(const char* pszEntityFile,bool bSourceIsCutsceneFile,Tools_Object* pxTargetObject,bool bShowMessage = true);
	static bool IsAllowableTarget(Tools_Object* pxSourceObject,Tools_Object* pxTargetObject,bool bShowMessage = true);

	//Tells Tools_LoadedFileList which files should be tracked for external modification.
	static void SetFilesToCheckForExternalModification();

	//Returns true if the selected entity file is allowed to be saved.
	static bool CanSaveCurrentFile();

	//called either side of creating an object to assign it to the correct entity file
	static void PreCreateObject();
	static void PostCreateObject();

	//gets the decription to use for the main entity file
	static const char* GetMainFileLabel();

	//access to the names of the secondary files
	static int GetNumSecondaryFiles();
	static const char* GetSecondaryFileName(int iIndex);

	//(re)inserts the entity in the tree , allowing it to be updated for name/folder changes
	static void UpdateEntityInTree(Tools_BaseEntity_Object* pxEntityObject, bool bSelect);
	//Deletes the tree item corresponding to the entity
	static void RemoveEntityFromTree(Asura_Guid uGuid);


	//for the overlay
	static void ToggleOverlay();
	static void CreateOverlay();
	static void CloseOverlay();
	static bool OverlayIsOn();

	static void OnOverlayClosed(bool bClosedByUser);

	static u_int GetItemColour(Asura_TreeDialog_Item* pxItem);

	#ifndef TOOLS_USE_OLD_ENTITY_MANAGER
	static void FilterTextChangedCallback ();
	#endif


	// Store/restore the expanded state of the tree and scrollbar offsets, etc.
	static void StoreTreeState();
	static void RestoreTreeState();

private :

	static void StoreTreeStateRecurse(FILE* pFile, Asura_TreeDialog_Item* pxFirstSibling, u_int& uCounter);

	//callback for getting the icon index for each tree item
	static int GetItemIconIndex(Asura_TreeDialog_Item* pxItem);

	#ifndef TOOLS_USE_OLD_ENTITY_MANAGER
	static int GetAdditionalItemIconIndex(Asura_TreeDialog_Item* pxItem, u_int uIconIndex);
	#endif

	static Asura_TreeDialog_Item* AddEntityToTree(Tools_BaseEntity_Object* pxEntityObject);

	#ifndef TOOLS_USE_OLD_ENTITY_MANAGER
	static Asura_String GetExpandedName (Tools_BaseEntity_Object* pxEntityObject, int& iStartIndex, int& iEndIndex);
	static Asura_String GetNameSubString (Asura_TreeDialog_Item* pxTreeItem, const char* pszFullString);
	#endif

	//Comparison function for sorting items as they are added to the tree
	static int CompareTreeItem( const Asura_TreeDialog_Item& xOne, const Asura_TreeDialog_Item& xTwo);

	// Generates a hash id from a tree item
	static Asura_Hash_ID GetItemHash(Asura_TreeDialog_Item* pxItem);

	//gets the entity file that a given tree item is associated with
	static Tools_SecondaryEntityFile* GetFileFromTreeItem(const Asura_TreeDialog_Item* pxItem);

	//Get the name of the root file item in the tree
	static const char* GetFileDisplayNameFromTreeItem(const Asura_TreeDialog_Item* pxItem);

	//Gets the entity browser path associated with the tree item
	static void GetFolderPathFromTreeItem(const Asura_TreeDialog_Item* pxItem, Asura_String& xOutput);

	static Asura_Guid GetGuidFromTreeItem(const Asura_TreeDialog_Item* pxItem);

	//Gets the tools entity object for the entity associated with the tree item 
	static Tools_Entity_Object* GetToolsEntityObjectFromTreeItem(const Asura_TreeDialog_Item* pxItem);

	static bool IsFileTreeItem(const Asura_TreeDialog_Item* pxItem);
	static bool IsFolderTreeItem(const Asura_TreeDialog_Item* pxItem);
	static bool IsEntityTreeItem(const Asura_TreeDialog_Item* pxItem);

	//Finds/creates the specified file/folder item in the tree	
	static Asura_TreeDialog_Item* Tools_SecondaryEntityFile_System::GetFileOrFolderFromTree(Tools_SecondaryEntityFile* pxFile, const char* szChildPath, bool bCreateIfNeeded);
	static Asura_TreeDialog_Item* Tools_SecondaryEntityFile_System::GetFileOrFolderFromTree(const char* szEntityFile, const char* szChildPath, bool bCreateIfNeeded);

	
	//creates a new secondary entity file
	static void CreateEntityFile();
	//Creates a common entity file , which is more restrictions about how it can be used
	static void CreateCommonEntityFile();

	//Add an existing secondary entity file
	static void AddEntityFile();


	//deletes the current file , mergeing all its entities into the main ent file
	static void MergeEntityFile();

	//deletes the current file , and all the entities that belong to it
	static void DeleteEntityFile();

	//Removes a file and deletes all the entities belonging to it , but doesn't delete the file
	static void RemoveEntityFile();

	//Renames a secondary entity file , and fixes up any entities so that they know about the new name
	static void RenameEntityFile();
	static void RenameEntityFile(Tools_SecondaryEntityFile* pxFile, const char* szNewName, bool bShowInitialMessages);

	//Replace a secondary entity file entry with another existing file
	static void ReplaceEntityFile();

	//Transfers the selected objects to the current entity file.
	static void TransferSelectedObjects();

	//Create a new folder for containing entities
	static void CreateFolder();

	static void CollapseAllTreeBranches();
	static void CollapseAllTreeBranchesRecursive(Asura_TreeDialog_Item* pxItem);

	//callback used by drag/drop on tree view
	static void DragAndDrop(Asura_TreeDialog_Item* pxDropTarget);

	//callback used when clicking on the eye icons
	static void IconClicked(Asura_TreeDialog_Item*, bool bDrag);

	#ifndef TOOLS_USE_OLD_ENTITY_MANAGER
	static void AdditionalIconClicked(Asura_TreeDialog_Item*, bool bDrag);
	static bool RecursiveCheckShouldHide(Asura_TreeDialog_Item* pxItem, bool bCurrentFlag);
	#endif

	//right click menus
	static void AddContextMenuItems(class Tools_ContextMenu& xMenu, const class Tools_ContextMenu_Context& xContext);

	static void ContextMenu_SelectAll(void* pClickedItem);
	static void ContextMenu_SelectNone();
	static void ContextMenu_InvertSelection();
	static void ContextMenu_SelectType(void* pClickedItem);
	static void ContextMenu_DeselectType(void* pClickedItem);
	static void ContextMenu_SelectVisible();
	static void ContextMenu_DeselectVisible();

	static void ContextMenu_Copy(void* pClickedItem);
	static void ContextMenu_Paste(void* pClickedItem);

	static void ContextMenu_Rename(void* pClickedItem);

	static void ContextMenu_Hide();
	static void ContextMenu_Unhide();
	static void HideRecursive(Asura_TreeDialog_Item* pxItem, bool bHide);

	static void ContextMenu_Create();
	static void ContextMenu_Goto(void* pClickedItem);

	static void ContextMenu_Delete();
	static void RemoveChildrenFromList(List<Asura_TreeDialog_Item*>& xSelectionList);
	static void AddToDeletionLists(Asura_TreeDialog_Item* pxItem, List<Tools_SecondaryEntityFile*>& xFileList, List<Asura_TreeDialog_Item*>& xFolderItemList, List<Tools_Object*>& xEntityItemList);


	static void SelectAllEntityRecursive(Asura_TreeDialog_Item* pxItem);
	static void InvertEntitySelectionRecursive(Asura_TreeDialog_Item* pxItem);

	//update the selection in the object system based on the selection in the tree control
	static void UpdateObjectSelectionFromTree();
	static void UpdateTreeFromObjectSelection();

	//Deals with moving items during drag/drop
	static bool TransferEntity(Asura_TreeDialog_Item* pxEntityItem, Tools_SecondaryEntityFile* pxDestFile, const char* szFolder);
	static Asura_TreeDialog_Item* TransferFolder(Asura_TreeDialog_Item* pxEntityItem, Tools_SecondaryEntityFile* pxDestFile, const char* szFolder);

	static Tools_SecondaryEntityFile* GetFile(const char* szName);
	static Tools_SecondaryEntityFile* GetMainFile() {return s_xFileList.first_entry();}

	static void CreateEntityFile(bool bCommon);
	static void RemoveEntityFile(Tools_SecondaryEntityFile* pxFile, bool bDelete);

	static void UpdateOverlay();

	static void UpdateTree();

	static void SetSelectedFile(Tools_SecondaryEntityFile* pxFile);

	static void WarnAboutUnwriteableEntity(Tools_Object* pxObject, const char* szFileDisplayName);


	//checks to see if a group is selected
	static bool IsGroupSelected();

	//Determines which tree items should be hidden
	static void UpdateTreeVisibility();
	static void UpdateTreeVisibility(Asura_TreeDialog_Item* pxItem, const char* szWildcardSearchString, bool bUseVisibility);

	static bool FilterList_IsSelected(int iIndex);
	static void FilterList_SetSelected(int iIndex, bool bSet);
	static bool FilterList_AnySelected();

	static bool IsFilterPanelMinimised(int iJunk) {return s_bFiltersMinimised;}
	static bool IsNotOnMainTab(int iJunk) {return s_uSelectedTab!=0;}

	//For dealing with the various filter options
	enum
	{
		FILTER_OBJECTTYPE,      //filter by object type
		FILTER_SHAPE,           //filter by shape/skin
		FILTER_BLUEPRINTTYPE,   //filter by blueprint type
		FILTER_BLUEPRINT,       //filter by blueprint

		FILTER_NUMTYPES,
	};

	static void DeleteFilterList();
	static void UpdateFilterList();
	static void AddToFilterList(const char* szName,int iData,bool bMatchByName);

	//callback for doubleclicking
	static void GotoSelected();

	//Callback for renaming items on the tree
	static void RenameItem(Asura_TreeDialog_Item* pxItem, const char* szName);
	static void RenameFolder(Asura_TreeDialog_Item* pxFolderItem, const char* szNewName);

	static void UpdateColourRecursive(Asura_TreeDialog_Item* pxItem);

	#ifndef TOOLS_USE_OLD_ENTITY_MANAGER
	static void OnShowHiddenEntitiesTickboxTicked ();
	#endif

	/////////

	static List<Tools_SecondaryEntityFile*> s_xFileList;
	 
	static Tools_SecondaryEntityFile* s_pxCurrentFile;
	static Asura_String s_xCurrentFolder;
	static bool s_bDoneUpdate;

	static bool s_bHideObjectsInOtherFiles;
	#ifndef TOOLS_USE_OLD_ENTITY_MANAGER
	static bool s_bShowHiddenEntities;
	#endif
	static bool s_bHideObjectsInThisFile;

	static class Asura_Tree_Dialog* s_pxTreeDialog;
	static bool s_bTreeValid;
	static u_int s_uTreeItemColourValidity;

	static bool s_bSelectionChanged;
	static u_int s_uObjectSystemSelectionChangedStamp;

	static bool s_bFilterChanged;

	static bool s_bFiltersMinimised;
	static bool s_bHistoryMinimised;

	//text search filter
	static int s_iSearchOption;
	static Asura_String s_xSearchText;

	//and for filter by type etc
	static List<ListSelectionItem*> s_xFilterList;
	static char** s_pszFilterStrings;

	static int s_iFilterType;
	static bool s_bFilterTypeChanged;

	static int s_iFilterIndex;
	static bool s_bFilterIndexChanged;

	static class Asura_List_Dialog* s_pxFilterDialog;

	static List<int> s_xFilterList_Type;
	static List<Asura_String> s_xFilterList_Shape;
	static List<Asura_String> s_xFilterList_BlueprintType;
	static List<Asura_String> s_xFilterList_Blueprint;

 	static u_int s_uSelectedTab;

	#ifndef TOOLS_USE_OLD_ENTITY_MANAGER
	static class Asura_String_Dialog* s_pxFilterSearchStringDialog;
	#endif

public :
	static const u_int s_uNumHistorySlots = 5;
	static u_int s_uNumUsedHistorySlots;

	static bool s_bOverlayIsOn;
	static Asura_Vector_2 s_xOverlayPosition;
	static Asura_Vector_2 s_xTreeDialogSize;
	static Asura_Vector_2 s_xFilterListDialogSize;

	static Asura_TreeDialog_Tree s_xTree;
	static class Asura_Panel_Dialog* s_pxPanelDialog;
	static class Asura_Panel_Dialog* s_pxHistoryPanelDialog;
	static class Asura_List_Dialog* s_pxHistoryListDialog;
	static Asura_Overlay* s_pxOverlay;
	static Tools_Object* s_axHistory[s_uNumHistorySlots];
	static const char* s_axHistoryStrings[s_uNumHistorySlots];
	static bool s_bNeedToUpdateHistoryStrings;
};

class Tools_SecondaryEntityFile
{
public :
	Tools_SecondaryEntityFile(const char* pszName);

	bool CanSaveFile(bool bShowMessages) const;
	void WarnIfReadOnly() const;
	//Version of CanSaveFile that just checks for the last remembered state
	//For less-critical UI code that might need to query this frequently
	bool CanSaveFileCached() const;


	void GenerateFilename(Asura_String& xOutputFilename) const;
	const char* GetDisplayName() const;
	bool IsMainFile() const {return m_bMainFile;}

	Asura_String m_xName;//filename without path/extension
	int	m_iNextID;
	int m_iFileVersion;
	int m_iFileVersionToSave;
	bool m_bModified;
	bool m_bCommonFile;//secondary entity file that may be shared by several main entity files
	bool m_bMissionDir;//secondary entity file that should be save to the mission directory
	bool m_bMainFile;//Represents the primary entity file. If true , then most of the other values don't apply

	int m_iFileID;//temporary id to match this with its entry in the tree

private :
	mutable bool m_bCachedWriteableFlag;
	mutable u_int m_uCachedWriteableFlagValidity;

	static int s_iNextFileID;

};

//workspace for doing the updates
class Tools_SecondaryEntityFileUpdater : public Tools_EntityTemplateInstance
{
public :
	Tools_SecondaryEntityFileUpdater(Tools_SecondaryEntityFile* pxFile);
	~Tools_SecondaryEntityFileUpdater();

	void Update(bool bIgnoreVersion = false);

	//template instance overrides

	virtual const Asura_Vector_3& GetRelativePosition() const {return Asura_Maths::ZeroVector3;}
	virtual const Asura_Matrix_3x3& GetRelativeMatrix() const {return Asura_Maths::IdentityMatrix3x3;}
	virtual bool ShouldUseRelativeMatrix() const {return false;}

	

	//converts message block from value stored in template to valid value for level
	virtual u_short ConvertMessageBlock(u_short usBlockID) const;

	//convert guid in template file to guid of equivalent entity in this instance
	virtual Asura_Guid ConvertGuid(Asura_Guid uGuid) const;
	//and the same for sound guids
	virtual Asura_Guid ConvertSoundGuid(Asura_Guid uGuid) const {return ASURA_GUID_UNREGISTERED;}

	//convert sound IDs from entity sound IDs in template file to entity sound IDs in the level
	virtual int ConvertSoundID(int iSoundID) const;

	static bool IsUpdatingFromSecondaryFile()				{ return s_bUpdatingFromSecondaryFile; }
	static void SetUpdatingFromSecondaryFile(bool bSet)		{ s_bUpdatingFromSecondaryFile = bSet; }

private :
	Tools_SecondaryEntityFile* m_pxFile;

	List<struct Tools_EntityChunkPair*> m_xEntityList;

	List<struct Tools_IDAndGuids*> m_xIDGuidList;

	const class Asura_Chunk_StaticMessages* m_pxMessageChunk;
	const class Asura_Chunk_TextureNames* m_pxEntityTextureChunk;

	List<const Asura_Chunk_SoundNames*> m_xSoundChunkList;

	static bool s_bUpdatingFromSecondaryFile;
};

struct Tools_IDAndGuids
{
	int m_iID;
	Asura_Guid m_uOldGuid;//guid in secondary file
	Asura_Guid m_uNewGuid;//guid in main file
	bool m_bUsableInSecondaryFile;
	Tools_Entity_Object* m_pxOldEntity;
};



#endif //_TOOLS_SECONDARYENTITYFILE_SYSTEM_H_
