#include "utilities/UndoStack.h"
#include "unittest/TestSuite.h"
#include "unittest/TestUndoStateDelta.h"

static void testBasicOperations(void) {
	UndoStack * undoStack = UndoStack_create((void *) 0x4);
	TestCase_assertBoolFalse(UndoStack_canUndo(undoStack));
	TestCase_assertBoolFalse(UndoStack_canRedo(undoStack));
	TestCase_assertPointerNULL(UndoStack_getStateDeltaForUndo(undoStack));
	TestCase_assertPointerNULL(UndoStack_getStateDeltaForRedo(undoStack));
	TestCase_assertBoolFalse(UndoStack_undo(undoStack));
	TestCase_assertBoolFalse(UndoStack_redo(undoStack));
	
	TestUndoStateDelta * stateDelta = TestUndoStateDelta_create();
	TestCase_assertUIntEqual(UndoStack_getCurrentNodeID(undoStack), 0);
	UndoStack_appendNode(undoStack, stateDelta);
	TestCase_assertUIntEqual(UndoStack_getCurrentNodeID(undoStack), 1);
	TestCase_assertBoolTrue(UndoStack_canUndo(undoStack));
	TestCase_assertBoolFalse(UndoStack_canRedo(undoStack));
	TestCase_assertPointerEqual(UndoStack_getStateDeltaForUndo(undoStack), stateDelta);
	TestCase_assertPointerNULL(UndoStack_getStateDeltaForRedo(undoStack));
	TestCase_assertBoolFalse(UndoStack_redo(undoStack));
	
	TestCase_assertUIntEqual(stateDelta->revertCallCount, 0);
	TestCase_assertBoolTrue(UndoStack_undo(undoStack));
	TestCase_assertUIntEqual(UndoStack_getCurrentNodeID(undoStack), 0);
	TestCase_assertUIntEqual(stateDelta->revertCallCount, 1);
	TestCase_assertPointerEqual(stateDelta->lastTarget, (void *) 0x4);
	
	TestCase_assertBoolFalse(UndoStack_canUndo(undoStack));
	TestCase_assertBoolTrue(UndoStack_canRedo(undoStack));
	TestCase_assertPointerNULL(UndoStack_getStateDeltaForUndo(undoStack));
	TestCase_assertPointerEqual(UndoStack_getStateDeltaForRedo(undoStack), stateDelta);
	TestCase_assertBoolFalse(UndoStack_undo(undoStack));
	
	TestCase_assertUIntEqual(stateDelta->applyCallCount, 0);
	undoStack->target = (void *) 0x5;
	TestCase_assertBoolTrue(UndoStack_redo(undoStack));
	TestCase_assertUIntEqual(UndoStack_getCurrentNodeID(undoStack), 1);
	TestCase_assertUIntEqual(stateDelta->applyCallCount, 1);
	TestCase_assertPointerEqual(stateDelta->lastTarget, (void *) 0x5);
	
	TestCase_assertBoolTrue(UndoStack_undo(undoStack));
	TestCase_assertUIntEqual(stateDelta->revertCallCount, 2);
	TestCase_assertPointerEqual(stateDelta->lastTarget, (void *) 0x5);
	
	undoStack->target = (void *) 0x6;
	TestCase_assertBoolTrue(UndoStack_redo(undoStack));
	TestCase_assertUIntEqual(UndoStack_getCurrentNodeID(undoStack), 1);
	TestCase_assertUIntEqual(stateDelta->applyCallCount, 2);
	TestCase_assertPointerEqual(stateDelta->lastTarget, (void *) 0x6);
	
	TestUndoStateDelta * stateDelta2 = TestUndoStateDelta_create();
	UndoStack_appendNode(undoStack, stateDelta2);
	TestCase_assertUIntEqual(UndoStack_getCurrentNodeID(undoStack), 2);
	TestCase_assertBoolTrue(UndoStack_canUndo(undoStack));
	TestCase_assertBoolFalse(UndoStack_canRedo(undoStack));
	TestCase_assertPointerEqual(UndoStack_getStateDeltaForUndo(undoStack), stateDelta2);
	TestCase_assertPointerNULL(UndoStack_getStateDeltaForRedo(undoStack));
	TestCase_assertBoolFalse(UndoStack_redo(undoStack));
	
	TestCase_assertUIntEqual(stateDelta2->revertCallCount, 0);
	TestCase_assertBoolTrue(UndoStack_undo(undoStack));
	TestCase_assertUIntEqual(UndoStack_getCurrentNodeID(undoStack), 1);
	TestCase_assertUIntEqual(stateDelta2->revertCallCount, 1);
	
	TestCase_assertBoolTrue(UndoStack_canUndo(undoStack));
	TestCase_assertBoolTrue(UndoStack_canRedo(undoStack));
	TestCase_assertPointerEqual(UndoStack_getStateDeltaForUndo(undoStack), stateDelta);
	TestCase_assertPointerEqual(UndoStack_getStateDeltaForRedo(undoStack), stateDelta2);
	
	TestCase_assertUIntEqual(stateDelta->disposeCallCount, 0);
	TestCase_assertUIntEqual(stateDelta2->disposeCallCount, 0);
	UndoStack_dispose(undoStack);
	TestCase_assertUIntEqual(stateDelta->disposeCallCount, 1);
	TestCase_assertUIntEqual(stateDelta2->disposeCallCount, 1);
	free(stateDelta);
}

TEST_SUITE(UndoStackTest,
           testBasicOperations)
