/** @@author A0142130A **/
package seedu.taskell.model;

import java.util.ArrayList;
import java.util.logging.Logger;

import com.google.common.eventbus.Subscribe;

import seedu.taskell.commons.core.LogsCenter;
import seedu.taskell.commons.events.undo.ExecutedIncorrectCommandEvent;
import seedu.taskell.logic.commands.AddCommand;
import seedu.taskell.model.task.Task;

public class HistoryManager implements History {

    private static final Logger logger = LogsCenter.getLogger(HistoryManager.class.getName());
    private static final String EDIT = "edit";
    
    private static ArrayList<CommandHistory> historyList;
    private static Model model;
    private static HistoryManager self;
    
    public HistoryManager() {
        historyList = new ArrayList<>();
    }
    
    public static History getInstance() {
        if (self == null) {
            self = new HistoryManager();
        }    
        return self;
    }
    
    public static void setModel(Model m) {
        model = m;
    }
    
    @Override
    public ArrayList<CommandHistory> getList() {
        return historyList;
    }

    @Override
    public ArrayList<String> getListCommandText() {
        assert historyList != null;
        
        updateList();
        
        ArrayList<String> list = new ArrayList<>();
        for (CommandHistory history: historyList) {
            list.add(history.getCommandText());
        }
        
        return list;
    }
    
    @Override
    public void updateList() {
        if (model == null) {
            logger.severe("Model is null");
            return;
        }
        for (CommandHistory commandHistory: historyList) {
            if (isCommandTypeAddOrEdit(commandHistory) 
                    && !isTaskPresent(commandHistory.getTask())) {
                historyList.remove(commandHistory);
            } else if (isUndoEditCommand(commandHistory) 
                    && !isTaskPresent(commandHistory.getTask())) {
                historyList.remove(commandHistory);
            }
        }
    }
    
    private boolean isCommandTypeAddOrEdit(CommandHistory commandHistory) {
        return (commandHistory.getCommandType().contains(AddCommand.COMMAND_WORD) 
                || commandHistory.getCommandType().contains(EDIT)) 
                && !commandHistory.isRedoTrue();
    }
    
    private boolean isUndoEditCommand(CommandHistory commandHistory) {
        return commandHistory.isRedoTrue() 
                && commandHistory.getCommandType().contains(EDIT);
    }

    @Override
    public void clear() {
        logger.info("Clearing history...");
        historyList.clear();        
    }

    @Override
    public void addCommand(String commandText, String commandType) {
        assert historyList != null;
        historyList.add(new CommandHistory(commandText, commandType));
    }

    @Override
    public void addTask(Task task) {
        logger.info("Adding task to history");
        if (historyList.isEmpty()) {
            logger.warning("No command history to add task to");
            return;
        }
        
        historyList.get(getOffset(historyList.size())).setTask(task);
    }

    @Override
    public void addOldTask(Task task) {
        logger.info("Adding old task to history");
        if (historyList.isEmpty()) {
            logger.warning("No command history to add task to");
            return;
        }
        
        historyList.get(getOffset(historyList.size())).setOldTask(task);
    }

    @Override
    public boolean isTaskPresent(Task task) {
        return model.isTaskPresent(task);
    }
    
    @Override
    public void deleteLatestCommand() {
        logger.info("Command unsuccessfully executed. Deleting command history.");
        if (historyList.isEmpty()) {
            logger.warning("No command history to delete");
            return;
        }
        historyList.remove(getOffset(historyList.size()));
    }

    @Override
    public void deleteCommandHistory(CommandHistory commandHistory) {
        historyList.remove(commandHistory);
    }
    
    private static int getOffset(int index) {
        return index - 1;
    }

    @Subscribe
    private void handleExecuteIncorrectCommandEvent(ExecutedIncorrectCommandEvent event) {
        if (event.isUndoableCommand()) {
            deleteLatestCommand();
        }
    }

    
}

@@ -363,16 +363,98 @@
 .Task;%0A%0A
+/** Implementation of History API, manages command history available for undo%0A */%0A
 public c
@@ -1193,32 +1193,103 @@
 %0A%0A    @Override%0A
+    /** returns list of command history's user input strings%0A     * */%0A
     public Array
@@ -1617,30 +1617,157 @@
 verride%0A    
-public
+/** should be called whenever DeleteCommand is executed%0A     *  deletes history of the task deleted%0A     * */%0A    public synchronized
  void update
@@ -1860,32 +1860,32 @@
         return;%0A
-
         %7D%0A      
@@ -1870,32 +1870,41 @@
 turn;%0A        %7D%0A
+        %0A
         for (Com

fix bug for slow loading of history