/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/* ***************************************************** */
/********************************************************************/
// UndoManager.h: interface for the CUndoManager class.

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

#include "Undo/IActionManager.h"

struct IAction;

class CUndoManager : public IActionManager{

public:
	/// we use a deque so that we can pop off both ends
	/// (e.g., off the bottom during overflow) and so we
	/// can access all actions, say when building an undo
	/// menu, rather than just the top; also note that we
	/// push onto the back (like you would with a vector)
	typedef std::deque<IAction*> ActionStack;

	CUndoManager();
	CUndoManager(
		IActionTarget* actionTarget,
		int capacity = UM_DEFAULT_STACK_CAPACITY);

	virtual ~CUndoManager();

	virtual IActionTarget* GetTarget() const;

	virtual void RegisterTarget(
		IActionTarget* actionTarget,
		int capacity = UM_DEFAULT_STACK_CAPACITY);

	/// add an action to the action target's undo stack.
	virtual void SetLastAction(IAction *itsLastAction = 0);

	/// undo the last n actions applied to an action target
	virtual void Undo(int nActions = 1);

	/// can we undo the last n actions?
	virtual bool CanUndo(int nActions = 1) const;

	/// redo the last n undone actions
	virtual void Redo(int nActions = 1);

	/// can we redo the last n undone action?
	virtual bool CanRedo(int nActions = 1) const;

	/// call when the action target has been cleaned (saved)
	void TargetCleaned();

	/// get the current size of a stack
	virtual int GetStackSize(StackKind kind) const;

	///@name get/set the maximum size of a stack (both stacks have same max)
	//@{
	virtual int GetStackCapacity() const{ return m_capacity; };
	virtual void SetStackCapacity(int nActions);
	//@}
	
	/// Delete all the actions stacked.
	virtual void DeleteActions();

private:
	CUndoManager(const CUndoManager& other);
	CUndoManager& operator=(const CUndoManager& other);

	void DeleteActions(ActionStack& aStack, int nActions);

	//Push_back the action to redo or undo stack.
	void push_back_to_redo(IAction* action);
	void push_back_to_undo(IAction* action);

	IActionTarget* m_actionTarget; //Target Document.
	ActionStack m_undoStack;
	ActionStack m_redoStack;
	int m_cleanMarker;
	int m_capacity;
};
