//@@author A0114395E
package seedu.todoapp.model;

import java.text.ParseException;
import java.util.Stack;

import seedu.todoapp.commons.exceptions.IllegalValueException;
import seedu.todoapp.logic.commands.exceptions.CommandException;
import seedu.todoapp.model.person.UniqueTaskList.TaskInvalidTimestampsException;

/**
 * Singleton class to handle Undo/Redo commands
 */
public class StateManager {

    private static StateManager instance = null;
    private Model model = null;
    private Stack<StateCommandPair> undoStack;
    private Stack<StateCommandPair> redoStack;
    private Stack<ReadOnlyToDoApp> previousDataStack;

    /**
     * Exists only to defeat instantiation.
     */
    protected StateManager() {
        undoStack = new Stack<StateCommandPair>();
        redoStack = new Stack<StateCommandPair>();
        previousDataStack = new Stack<ReadOnlyToDoApp>();
    }

    /**
     * @return the singleton instance
     */
    public static StateManager getInstance() {
        if (instance == null) {
            instance = new StateManager();
        }
        return instance;
    }

    /*
     * Updates the Model in StateManager
     */
    public void setModel(Model model) {
        this.model = model;
    }

    /**
     * Check if stack exist for redo
     */
    public boolean redoStackHasCommands() {
        return !redoStack.isEmpty();
    }

    /**
     * Check if stack exist for undo
     */
    public boolean undoStackHasCommands() {
        return !undoStack.isEmpty();
    }

    /**
     * Check if stack exist for models
     */
    public boolean previousDataStackHasCommands() {
        return !previousDataStack.isEmpty();
    }

    /**
     * On each new command, add a new command onto the undo stack to track its
     * history and clear the redo history stack
     */
    public void onNewCommand(StateCommandPair newCommandPair) {
        this.undoStack.push(newCommandPair);
        this.redoStack.clear();
    }

    /**
     * On each clear command, we store the current model,
     * in case the user wants to undo that clear command
     */
    public void onClearCommand(ReadOnlyToDoApp data) {
        ToDoApp currentData = new ToDoApp(data);
        this.previousDataStack.push(currentData);
    }

    /**
     * Undo the most recent command, then store that undo command in a redo
     * stack
     * @throws CommandException
     * @throws IllegalValueException
     * @throws ParseException
     * @throws TaskInvalidTimestampsException
     */
    public void undo()
            throws CommandException, IllegalValueException, ParseException, TaskInvalidTimestampsException {
        if (undoStack.isEmpty()) {
            System.out.println("No undo commands found");
        } else {
            // Moving command from undo to redo
            StateCommandPair currentCommand = undoStack.pop();
            redoStack.push(currentCommand);
            // Executing undo command
            currentCommand.executeInverseCommand();
        }
    }

    /**
     * Redo the most recently 'undo' command, then store that redo command in
     * the undo stack
     * @throws CommandException
     * @throws IllegalValueException
     * @throws ParseException
     * @throws TaskInvalidTimestampsException
     */
    public void redo()
            throws CommandException, IllegalValueException, ParseException, TaskInvalidTimestampsException {
        if (redoStack.isEmpty()) {
            System.out.println("No redo commands found");
        } else {
            // Moving command from redo to undo
            StateCommandPair currentCommand = redoStack.pop();
            undoStack.push(currentCommand);
            // Executing redo command
            currentCommand.executeCommand();
        }
    }

    /**
     * Restores previous data (i.e undo a clear command )
     *
     * @throws CommandException
     * @throws IllegalValueException
     */
    public void restoreData() throws CommandException, IllegalValueException {
        if (previousDataStack.isEmpty()) {
            System.out.println("No previous data found");
        } else {
            ReadOnlyToDoApp previousData = previousDataStack.pop();
            this.model.resetData(previousData);
        }
    }
}

@@ -2648,20 +2648,24 @@
         
-if (
+assert(!
 undoStac
@@ -2680,90 +2680,10 @@
 y())
- %7B%0A            System.out.println(%22No undo commands found%22);%0A        %7D else %7B%0A    
+;%0A
     
@@ -2722,20 +2722,16 @@
 to redo%0A
-    
         
@@ -2785,28 +2785,24 @@
 ();%0A        
- 
-   
 redoStack.pu
@@ -2813,36 +2813,32 @@
 urrentCommand);%0A
-    
         // Execu
@@ -2855,36 +2855,32 @@
 command%0A        
-    
 currentCommand.e
@@ -2899,34 +2899,24 @@
 eCommand();%0A
-        %7D%0A
     %7D%0A%0A    /
@@ -3311,20 +3311,24 @@
         
-if (
+assert(!
 redoStac
@@ -3343,90 +3343,10 @@
 y())
- %7B%0A            System.out.println(%22No redo commands found%22);%0A        %7D else %7B%0A    
+;%0A
     
@@ -3389,28 +3389,24 @@
 ndo%0A        
-  
-  
 StateCommand
@@ -3448,28 +3448,24 @@
 ();%0A        
-    
 undoStack.pu
@@ -3488,28 +3488,24 @@
 d);%0A        
-  
-  
 // Executing
@@ -3514,28 +3514,24 @@
 edo command%0A
-    
         curr
@@ -3555,34 +3555,24 @@
 eCommand();%0A
-        %7D%0A
     %7D%0A%0A    /
@@ -3803,20 +3803,24 @@
         
-if (
+assert(!
 previous
@@ -3839,23 +3839,18 @@
 Empty())
- %7B%0A    
+;%0A
         
@@ -3899,29 +3899,8 @@
 %22);%0A
-        %7D else %7B%0A    
     
@@ -3963,28 +3963,24 @@
 ();%0A        
-    
 this.model.r
@@ -4003,26 +4003,16 @@
 sData);%0A
-        %7D%0A
     %7D%0A%7D%0A

Change system print to asserts