//
// action.h
//
// written by Michael Riedel <Michael.Riedel@gmx.de>
// 
// Action Classes Header
//

#ifndef	KBUILDER_action_h
#define	KBUILDER_action_h

#include <kprocess.h>
#include <String.h>

class KSyntaxMultiLineEdit;
class UndoList;



///////////////////////////////////////////////////////////////////
class Action
{
friend UndoList;

public:   
	Action(KSyntaxMultiLineEdit* edit)
	{ Edit = edit; }

	virtual void debugOut() = 0;
	

protected:
		/** Undoes the action. */
	virtual bool Undo() = 0;
	
		/** Redoes the action. */
	virtual bool Redo() = 0;
	
		/** 
			Returns information about wethoer an actions changes
			the Edit's text or not.
			@returns returns true, if this type of action changes
					 the Edit's text; returns false, if it does not.
		*/
	virtual bool Dirty() const = 0;

	bool allPreviousActionsClean() 	{ return AllPrevAreClean; }
	void setAllPreviousActionsClean(bool a) 
									{ AllPrevAreClean = a; }

	bool AllPrevAreClean;
	KSyntaxMultiLineEdit* Edit;
};
///////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////
class UndoList 
{
public:   
	UndoList(unsigned int maxEntries = 100);
	~UndoList() {}

		/**
			Adds an action a to the current undo 
			list; if the number of entries in the list 
			exceeds MaxEntries, the first entry is deleted 
			before the entry a is added; a is added directly after
			the current UndoPointer; this means, that actions that
			were previously undone are deleted and replaced by a.
			@param a Action to be added to the end of the undo list
			@param execute if true, the action a will be executed after
				   it is added to the list.
			@return returns true, if the action is successfully added.
		*/
	bool AddAction(Action* a, bool execute = true);
	
		/**
			Undoes one action in the list, if the current UndoPointer
			is not null (which means that all actions are already undone)
			and moves the UndoPointer one action towards the beginning
			of the list.
			@returns returns true, if an action could be undone and it was
					 not the first action in the list (there are more actions
					 to be undone!); returns false, if the first action in the
					 list was undone or there were no more actions to be undone
					 (UndoPointer was already null on function entry!).
		*/
	bool Undo();
	bool Redo();
	void Clear();

		/**
			Indicates wether the undo list currenty contains any done actions
			that are dirty. In this case true ist returned. When all of the 
			done actions are clean (not dirty) this function returns true.
			If a dirty action has been dropped from the list (due to an overflow
			in the number of list elements (see also MaxEntries), this function
			always returns true!
			@returns see above.
		*/
	bool IsDirty();

	void debugOut();


protected:
	QList<Action> List;
	
		/**
			Points to the action that is currently to be 
			undone (via a call to Undo()). It is null, 
			if there were no elements in the list or all
			actions are currenty undone.
		*/
	Action*       UndoPointer;	
		
		/**
			Maximum number of elements in the undo list.
		*/
	unsigned int  MaxEntries;
		
		/**
			Indicates wether there were more than MaxEntries
			added to the UndoList or not (and therfore some
			elements are dropped). It is neccessary to carry 
			this flag in order to make it possible to clear 
			the documents dirty flag as soon as all actions 
			in the list are undone (this is only possible 
			if there are no dirty elements dropped). 
		*/
	bool CompleteUndoImpossible;
};
///////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////
class CharInputAction : public Action
{
public:
	CharInputAction(KSyntaxMultiLineEdit* edit, char c) : Action(edit)
	{ C = c; }

	virtual void debugOut()
	{ warning("CharInputAction(%c)", C); }


protected:
	virtual bool Undo();
	virtual bool Redo();
	virtual bool Dirty() const { return true; }

	char C;   // entered character
};
///////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////
class NewlineAction : public Action
{
public:
	NewlineAction(KSyntaxMultiLineEdit* edit) : Action(edit)
	{ }

	virtual void debugOut()
	{ warning("NewlineAction()"); }


protected:
	virtual bool Undo();
	virtual bool Redo();
	virtual bool Dirty() const { return true; }
};
///////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////
class StringInputAction : public Action
{
public:
	StringInputAction(KSyntaxMultiLineEdit* edit, const QString& s) : Action(edit)
	{ S = s; }

	virtual void debugOut()
	{ warning("StringInputAction(%s)", (const char*)S); }


protected:
	QString S;   // entered string
};
///////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////
class ClipboardAction : public StringInputAction
{
public:
	typedef enum {CUT, COPY, PASTE} ClpActionType;
	ClipboardAction(KSyntaxMultiLineEdit* edit, ClpActionType type);

	virtual void debugOut();


protected:
	virtual bool Undo();
	virtual bool Redo();
	virtual bool Dirty() const { return Type != COPY; }

	ClpActionType Type;
};
///////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////
class DelBackAction : public Action
{
public:
	DelBackAction(KSyntaxMultiLineEdit* edit, char c) : Action(edit)
	{ C = c; wasMarkedText = false; }
	DelBackAction(KSyntaxMultiLineEdit* edit, const char* s) : Action(edit)
	{ markedText = s; wasMarkedText = true;}
	

protected:
	virtual bool Dirty() const { return true; }

	void _debugOut(const char* name)
	{
		if(wasMarkedText)
			warning("%s(%s), marked", name, markedText.data());
		else
			warning("%s(%c)", name, C); 
	}
	

	bool wasMarkedText;
	QString markedText;
	char C;   // deleted character
};
///////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////
class DeleteAction : public DelBackAction
{
public:
	DeleteAction(KSyntaxMultiLineEdit* edit, char c) 
		: DelBackAction(edit, c) { }
	DeleteAction(KSyntaxMultiLineEdit* edit, const char* s) 
		: DelBackAction(edit, s) { }
	virtual void debugOut()
	{ _debugOut("DeleteAction"); }
	

protected:
	virtual bool Undo();
	virtual bool Redo();
};
///////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////
class BackspaceAction : public DelBackAction
{
public:
	BackspaceAction(KSyntaxMultiLineEdit* edit, char c) 
		: DelBackAction(edit, c) { }		
	BackspaceAction(KSyntaxMultiLineEdit* edit, const QString& s) 
		: DelBackAction(edit, s) { }

	virtual void debugOut()
	{ _debugOut("BackspaceAction"); }


protected:
	virtual bool Undo();
	virtual bool Redo();
};
///////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////
class MarkingAction : public Action
{
public:
	MarkingAction(KSyntaxMultiLineEdit* edit, bool mark, bool init) : Action(edit)
	{ Mark = mark; Init = init; }

	virtual void debugOut() = 0;


protected:
	virtual bool Dirty() const { return false; }

	bool Mark;      		// true, when marking text
	bool Init;				// don't know, wether it's neccessary in CursorMovementAction!
	QPoint OldPos;			// Position before action 
};
///////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////
class CursorMovementAction : public MarkingAction
{
public:
	typedef enum 
	{ DirLeft, DirRight, DirUp, DirDown } CMDIRECTION;

	CursorMovementAction(KSyntaxMultiLineEdit* edit, CMDIRECTION dir, bool mark) 
		: MarkingAction(edit, mark, false)
	{ Direct = dir; }

	virtual void debugOut()
	{ warning("CursorMovementAction(%d, %d)", Direct, Mark); }


protected:
	virtual bool Undo();
	virtual bool Redo();

	CMDIRECTION Direct;   // Direction, in which cursor was moved
};
///////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////
class CursorPlacementAction : public MarkingAction
{
public:
	CursorPlacementAction(KSyntaxMultiLineEdit* edit, QPoint& actualPos, QPoint& newPos, 
						  bool mark, bool init = false) 
		: MarkingAction(edit, mark, init)
	{ 
		OldPos = actualPos;
		NewPos = newPos;
	}

	virtual void debugOut()
	{ warning("CursorMovementAction((%d/%d), (%d/%d), %d)", 
			  NewPos.x(), NewPos.y(), OldPos.x(), OldPos.y(), Mark); }


protected:
	virtual bool Undo();
	virtual bool Redo();

	QPoint NewPos;	// Position after action is done
};
///////////////////////////////////////////////////////////////////



#endif
