//
// action.C
//
// written by Michael Riedel <Michael.Riedel@gmx.de>
//

#include <qclipbrd.h>
#include "KColorMLE.h"
#include "Action.h"



UndoList::UndoList(unsigned int maxEntries)
{
	MaxEntries  = maxEntries;
 	UndoPointer = 0;
	CompleteUndoImpossible = false;
    
	List.setAutoDelete(true);
}



void UndoList::Clear()
{
 	UndoPointer = 0;
	CompleteUndoImpossible = false;
    List.clear();
}



bool UndoList::AddAction(Action* a, bool execute)
{
		// clear entries that are currently undone before adding
		// a new action:
	if(UndoPointer)
		while(UndoPointer != List.last())
			List.removeLast();
	else
		List.clear(); // delete all entries, if UndoPointer was null, 
					  // works on empty list as well

		// remove first Element in list:
	if(List.count() >= MaxEntries)
	{
			// clear flag only if a *dirty* action is removed!
		if(true)
			CompleteUndoImpossible = true;
		List.removeFirst();
	}
	
	if(UndoPointer)
	{
		bool allClean = UndoPointer->allPreviousActionsClean() && !a->Dirty();
		a->setAllPreviousActionsClean(allClean);
	}
	else
		a->setAllPreviousActionsClean(true);

	List.append(a);
	UndoPointer = a;

	if(execute)
		a->Redo();

	return true;
}



bool UndoList::IsDirty()
{
	if(CompleteUndoImpossible)
		return true;

	if(UndoPointer)
		return !UndoPointer->allPreviousActionsClean();
	else
		return false;
}


bool UndoList::Undo()
{
	if(UndoPointer)
	{
		UndoPointer->Undo();
		List.findRef(UndoPointer);
		UndoPointer = List.prev();	// sets UP to 0 when UP == List.first()!
		
		if(!UndoPointer)			// this undo was the last possible!
			return false;
		else
			return true;
	}
	else
	{
		warning("no action to be undone.");
		return false;
	}
}



bool UndoList::Redo()
{
	if(UndoPointer == List.last())
	{
		warning("no action to be redone.");
		return false;
	}
	
	if(UndoPointer)
	{
		List.findRef(UndoPointer);
		UndoPointer = List.next();
	}
	else
	{
		UndoPointer = List.first();
	}

	UndoPointer->Redo();
	return true;
}



void UndoList::debugOut()
{
	int i = 0;
	warning("***********************");
	Action* a = List.first();
	while(a)
	{
		warning("%4d:", i++);
		a->debugOut();
		a = List.next();
	}
	
	int index = List.findRef(UndoPointer);
	warning("***********************");
	warning("index of UndoPointer:%d", index);
	warning("***********************");
}



///////////////////////////////////////////////////

bool CharInputAction::Undo()
{
	Edit->backspace();
	return true;
}



bool CharInputAction::Redo()
{
	Edit->insertChar(C);
	return true;
}



///////////////////////////////////////////////////

bool NewlineAction::Undo()
{
	Edit->backspace();
	return true;
}



bool NewlineAction::Redo()
{
	Edit->newLine();
	return true;
}



///////////////////////////////////////////////////

bool CursorMovementAction::Undo()
{
	Edit->setCursorPosition(OldPos.y(), OldPos.x());
/*	switch(Direct)
	{
		case DirLeft:  Edit->cursorRight(Mark); break;
		case DirRight: Edit->cursorLeft(Mark);  break;
		case DirUp:    Edit->cursorDown(Mark);  break;
		case DirDown:  Edit->cursorUp(Mark);    break;
	}
*/	emit Edit->cursorPosChanged();
	return true;
}



bool CursorMovementAction::Redo()
{
		// save old cursor position:
	int cy, cx;
	Edit->getCursorPosition(&cy, &cx);
	OldPos.setY(cy);
	OldPos.setX(cx);
	
	switch(Direct)
	{
		case DirLeft:  Edit->cursorLeft(Mark);  break;
		case DirRight: Edit->cursorRight(Mark); break;
		case DirUp:    Edit->cursorUp(Mark);    break;
		case DirDown:  Edit->cursorDown(Mark);  break;
	}
	emit Edit->cursorPosChanged();
	return true;
}



///////////////////////////////////////////////////

bool CursorPlacementAction::Undo()
{
	Edit->setCursorPosition(OldPos.y(), OldPos.x(), Mark);
	emit Edit->cursorPosChanged();
	return true;
}



bool CursorPlacementAction::Redo() 
{
	Edit->setCursorPosition(NewPos.y(), NewPos.x(), Mark);
	emit Edit->cursorPosChanged();
	return true;
}



///////////////////////////////////////////////////

bool DeleteAction::Undo()
{
	if(C == '\n')
		Edit->newLine();
	else
		Edit->insertChar(C);
		
	Edit->cursorLeft();
	return true;
}



bool DeleteAction::Redo()
{
//	warning("do delete with char:<%c>\n", C);
	Edit->del();
	emit Edit->textChanged();
//	emit cursorPosChanged();
	return true;
}



///////////////////////////////////////////////////

bool BackspaceAction::Undo()
{
	if(C == '\n')
		Edit->newLine();
	else
		Edit->insertChar(C);
	return true;
}



bool BackspaceAction::Redo() 
{
//	warning("do backspace with char:<%c>\n", C);
	Edit->backspace();
	emit Edit->textChanged();
	return true;
}


///////////////////////////////////////////////////

ClipboardAction::ClipboardAction(KSyntaxMultiLineEdit* edit, ClpActionType type) 
	: StringInputAction(edit, "")
{ 
	Type = type; 

		// S takes the content of the clipboard before 
		// cutting or copying (it is not used for pasting):
	S = QApplication::clipboard()->text();
}



bool ClipboardAction::Undo()
{
	switch(Type)
	{
		case CUT:
			int y1, x1, y2, x2;
			Edit->getCursorPosition(&y1, &x1);
			Edit->paste();
			Edit->getCursorPosition(&y2, &x2);
			Edit->setMark(x1, y1, x2, y2);
			QApplication::clipboard()->setText(S);
			break;

		case COPY:
			QApplication::clipboard()->setText(S);
			break;

		case PASTE:
			Edit->cut();
			break;
	}
	return true;
}



bool ClipboardAction::Redo() 
{
	switch(Type)
	{
		case CUT:
			Edit->cut();
			break;
		case COPY:
			Edit->copyText();
			break;
		case PASTE:
			Edit->paste();
			break;
	}
	return true;
}



void ClipboardAction::debugOut()
{ 
	warning("ClipboardAction(");
	switch(Type)
	{
		case CUT:
			warning("CUT, ");
			break;
		case COPY:
			warning("COPY, ");
			break;
		case PASTE:
			warning("PASTE, ");
 			break;
	}
	warning("%s)", (const char*)S); 
}
	

