package seedu.task.model.commandmap;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import seedu.task.logic.commands.AddCommand;
import seedu.task.logic.commands.AliasCommand;
import seedu.task.logic.commands.CompleteCommand;
import seedu.task.logic.commands.DeleteCommand;
import seedu.task.logic.commands.EditCommand;
import seedu.task.logic.commands.ExitCommand;
import seedu.task.logic.commands.ExportCommand;
import seedu.task.logic.commands.FindCommand;
import seedu.task.logic.commands.HelpCommand;
import seedu.task.logic.commands.ImportCommand;
import seedu.task.logic.commands.IncompleteCommand;
import seedu.task.logic.commands.ListCommand;
import seedu.task.logic.commands.RedoCommand;
import seedu.task.logic.commands.ResetCommand;
import seedu.task.logic.commands.RevertCommand;
import seedu.task.logic.commands.SelectCommand;
import seedu.task.logic.commands.UndoCommand;
import seedu.task.logic.commands.UnrevertCommand;
import seedu.task.logic.commands.UseCommand;

public class CommandMap {

    private HashMap<String, String> commandMap;
    private final ArrayList<String> originalCommandWords;

    public CommandMap() {
        this.commandMap = new HashMap<String, String>();
        this.originalCommandWords = getOriginalCommandWords();
    }

    public void putAll(HashMap<String, String> map) {
        this.commandMap.putAll(map);
    }

    private static ArrayList<String> getOriginalCommandWords() {
        ArrayList<String> commandWords = new ArrayList<String>();

        commandWords.add(AliasCommand.COMMAND_WORD);
        commandWords.add(AddCommand.COMMAND_WORD);
        commandWords.add(EditCommand.COMMAND_WORD);
        commandWords.add(CompleteCommand.COMMAND_WORD);
        commandWords.add(IncompleteCommand.COMMAND_WORD);
        commandWords.add(SelectCommand.COMMAND_WORD);
        commandWords.add(DeleteCommand.COMMAND_WORD);
        commandWords.add(ResetCommand.COMMAND_WORD);
        commandWords.add(FindCommand.COMMAND_WORD);
        commandWords.add(ListCommand.COMMAND_WORD);
        commandWords.add(ExitCommand.COMMAND_WORD);
        commandWords.add(HelpCommand.COMMAND_WORD);
        commandWords.add(RedoCommand.COMMAND_WORD);
        commandWords.add(UndoCommand.COMMAND_WORD);
        commandWords.add(ImportCommand.COMMAND_WORD);
        commandWords.add(ExportCommand.COMMAND_WORD);
        commandWords.add(RevertCommand.COMMAND_WORD);
        commandWords.add(UnrevertCommand.COMMAND_WORD);
        commandWords.add(UseCommand.COMMAND_WORD);

        return commandWords;
    }

    /**
     * Signals that the operation refers to a non-existing command.
     */
    public static class OriginalCommandNotFoundException extends Exception {
        public OriginalCommandNotFoundException() {
            super("Original command not found!");
        }
    }

    public static class BaseCommandNotAllowedAsAliasException extends Exception {}

    public boolean containsKey(String commandToMap) {
        return this.commandMap.containsKey(commandToMap);
    }

    public boolean isBaseCommandWord(String command) {
        return this.originalCommandWords.contains(command);
    }

    public String get(String commandToMap) {
        return this.commandMap.get(commandToMap);
    }

    public boolean isOriginalCommandValid(String command) {
        return this.commandMap.containsValue(command)
                || isBaseCommandWord(command);
    }

    public void put(String alias, String commandToMap) {
        this.commandMap.put(alias, commandToMap);
    }

    public HashMap<String, String> getCommandMap() {
        HashMap<String, String> copyMap = new HashMap<String, String>();
        copyMap.putAll(commandMap);
        return copyMap;
    }

    public String translateCommand(String original) {
        String commandToMap = original;
        while (commandMap.containsKey(commandToMap)) {
            commandToMap = commandMap.get(commandToMap);
        }
        return commandToMap;
    }

    private HashMap<String, ArrayList<String>> groupByOriginalCommand() {
        HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
        Iterator it = this.commandMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pair = (Map.Entry) it.next();
            if (!map.containsKey((String) pair.getValue())) {
                map.put((String) pair.getValue(), new ArrayList<String>());
            }
            map.get(pair.getValue()).add((String) pair.getKey());
        }
        return map;
    }

    @Override
    public String toString() {
        String mapString = "";
        Iterator it = this.groupByOriginalCommand().entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pair = (Map.Entry) it.next();
            mapString += pair.getKey() + ": " + pair.getValue().toString() + "\n";
        }
        return mapString;
    }
}

@@ -219,32 +219,77 @@
 s.AliasCommand;%0A
+import seedu.task.logic.commands.CalCommand;%0A
 import seedu.tas
@@ -929,32 +929,83 @@
 .SelectCommand;%0A
+import seedu.task.logic.commands.ShowAliasCommand;%0A
 import seedu.tas
@@ -2658,16 +2658,124 @@
 D_WORD);
+%0A        commandWords.add(CalCommand.COMMAND_WORD);%0A        commandWords.add(ShowAliasCommand.COMMAND_WORD);
 %0A%0A      

Add Cal and ShowAlias commands to CommandMap