// UndoManager.h: interface for the UndoManager class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_UNDOMANAGER_H__8D4EFECB_204F_4BE0_8952_13AB4341E301__INCLUDED_)
#define AFX_UNDOMANAGER_H__8D4EFECB_204F_4BE0_8952_13AB4341E301__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000



#define OFFMAPTAG "***TOMSRULES***"
#include"GUIObjectList.h"
#define COMMAND_MAX 256

class UndoCommand
{
protected:
	EdGUIObject *Object;
	UndoCommand *Next;
public:
	UndoCommand *GetLastLink() {if(Next==NULL) return this; else return Next->GetLastLink();}
	virtual void ExecuteUndo(UndoCommand **revcom);
	virtual void Discard() { }
	void Attach(UndoCommand *cmd);
	UndoCommand(EdGUIObject *obj) {Verify(obj); Object=obj; Next=NULL; Object->AddRefernce(); }
	virtual ~UndoCommand() {if(Object)Object->RemoveRefernce();}
};

class RenameCommand:public UndoCommand
{
protected:
	CString OldName;
public:
	void ExecuteUndo(UndoCommand **revcom);
	RenameCommand(EdGUIObject *obj):UndoCommand(obj) 
		{OldName=obj->GetName(); } 
	virtual ~RenameCommand() {}
};

class MoveCommand:public UndoCommand
{
protected:
	Point3D OldPos;
public:
	void ExecuteUndo(UndoCommand **revcom);
	MoveCommand(EdGUIObject *obj):UndoCommand(obj) 
		{  OldPos=obj->GetPos();} 
	virtual ~MoveCommand() {}
};

class RotateCommand:public UndoCommand
{
protected:
	UnitQuaternion OldRot;
public:
	void ExecuteUndo(UndoCommand **revcom);
	RotateCommand(EdGUIObject *obj):UndoCommand(obj)  
		{ OldRot=obj->GetRot();} 

	virtual ~RotateCommand() {}
};


class AddCommand:public UndoCommand
{
protected:
	GUIObjectList *Parent;
public:
	void ExecuteUndo(UndoCommand **revcom);
	AddCommand(EdGUIObject *obj):UndoCommand(obj) 
		{ Parent=obj->GetParent(); Verify(Parent);} 
	virtual ~AddCommand() {  }
};


class DeleteCommand:public UndoCommand
{
protected:
	int Location;
	GUIObjectList *Parent;
public:
	void ExecuteUndo(UndoCommand **revcom);
	void Discard() {Object->RemoveRefernce(); delete Object; Object=NULL;}
	DeleteCommand(EdGUIObject *obj):UndoCommand(obj) 
		{Parent=obj->GetParent(); Verify(Parent); Location=Parent->FindObjectIdx(obj);  
		Verify(Location>=0); obj->SetName(obj->GetName()+OFFMAPTAG);} 
	virtual ~DeleteCommand() {  }
};

class GroupCommand:public UndoCommand
{
protected:
	GUIObjectList *Parent;
public:
	void ExecuteUndo(UndoCommand **revcom);
	GroupCommand(EdGUIObject *obj):UndoCommand(obj) 
		{Parent=obj->GetParent(); Verify(Parent);} 
	virtual ~GroupCommand() {  }
};

class CommandStack
{
protected:
UndoCommand *Commands[COMMAND_MAX];
int CommandMax;
int CommandCount;
	
	void RemoveBottomCommand();
public:
	int Depth() {return CommandCount;}
	void PushCommand(UndoCommand *cmd);
	UndoCommand *Pop();
	UndoCommand *PopAndExecute();
	void Clear(); 
	CommandStack();
	virtual ~CommandStack() { Clear();}

};

class UndoManager  
{
protected:
CommandStack UndoStack,RedoStack;
public:
	void AddCommand(UndoCommand *cmd);
	bool CanUndo() {return (UndoStack.Depth()>0);}
	bool CanRedo() {return (RedoStack.Depth()>0);}
	void Undo();
	void Redo();	
	UndoManager() {}
	virtual ~UndoManager();
	
};

#endif // !defined(AFX_UNDOMANAGER_H__8D4EFECB_204F_4BE0_8952_13AB4341E301__INCLUDED_)
