// @@author A0130195M

package jfdi.logic;

import com.google.common.eventbus.EventBus;
import jfdi.logic.commands.InvalidCommand;
import jfdi.logic.events.FilesReplacedEvent;
import jfdi.logic.events.InitializationFailedEvent;
import jfdi.logic.interfaces.Command;
import jfdi.logic.interfaces.ILogic;
import jfdi.parser.InputParser;
import jfdi.parser.exceptions.InvalidInputException;
import jfdi.storage.apis.*;
import jfdi.storage.exceptions.FilesReplacedException;
import jfdi.storage.exceptions.InvalidFilePathException;
import jfdi.ui.UI;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.TreeSet;
import java.util.stream.Collectors;

/**
 * @author Liu Xinan
 */
public class ControlCenter implements ILogic {

    private static ControlCenter ourInstance;

    private static EventBus eventBus = UI.getEventBus();

    private static MainStorage mainStorage = MainStorage.getInstance();
    private static TaskDb taskDb = TaskDb.getInstance();
    private static AliasDb aliasDb = AliasDb.getInstance();

    private static InputParser parser = InputParser.getInstance();

    private ControlCenter() {
        initStorage();
        initParser();
    }

    public static ControlCenter getInstance() {
        if (ourInstance == null) {
            ourInstance = new ControlCenter();
        }
        return ourInstance;
    }

    @Override
    public void handleInput(String input) {
        Command command;
        try {
            command = parser.parse(input);
        } catch (InvalidInputException e) {
            command = new InvalidCommand.Builder().build();
        }
        command.execute();
    }

    @Override
    public TreeSet<String> getKeywords() {
        TreeSet<String> keywords = Arrays.stream(InputParser.getInstance()
            .getAllCommandRegexes()
            .replaceAll("\\W+", " ").split("\\s+"))
            .filter(part -> part.length() > 1)
            .collect(Collectors.toCollection(TreeSet::new));

        AliasDb.getInstance()
            .getAll().stream()
            .map(AliasAttributes::getAlias)
            .forEach(keywords::add);

        return keywords;
    }

    @Override
    public ArrayList<TaskAttributes> getIncompleteTasks() {
        return taskDb.getAll().stream()
            .filter(task -> !task.isCompleted())
            .collect(Collectors.toCollection(ArrayList::new));
    }

    @Override
    public ArrayList<TaskAttributes> getCompletedTasks() {
        return taskDb.getAll().stream()
            .filter(TaskAttributes::isCompleted)
            .collect(Collectors.toCollection(ArrayList::new));
    }

    @Override
    public ArrayList<TaskAttributes> getAllTasks() {
        return taskDb.getAll().stream()
            .collect(Collectors.toCollection(ArrayList::new));
    }

    @Override
    public ArrayList<TaskAttributes> getUpcomingTasks() {
        return taskDb.getUpcoming().stream()
            .collect(Collectors.toCollection(ArrayList::new));
    }

    @Override
    public ArrayList<TaskAttributes> getOverdueTasks() {
        return taskDb.getOverdue().stream()
            .collect(Collectors.toCollection(ArrayList::new));
    }

    private void initStorage() {
        // Set a list of permitted commands that can be aliased
        AliasAttributes.setCommandRegex(parser.getAllCommandRegexes());
        try {
            mainStorage.initialize();
        } catch (FilesReplacedException e) {
            eventBus.post(new FilesReplacedEvent(e.getReplacedFilePairs()));
        } catch (InvalidFilePathException e) {
            eventBus.post(new InitializationFailedEvent(InitializationFailedEvent.Error.INVALID_PATH,
                e.getPath()));
        }
    }

    private void initParser() {
        parser.setAliases(aliasDb.getAll());
    }

    //================================================================
    // Methods for testing.
    //================================================================

    public static void removeInstance() {
        ourInstance = null;
    }

    public static void setParser(InputParser parser) {
        ControlCenter.parser = parser;
    }

    public static void setMainStorage(MainStorage mainStorage) {
        ControlCenter.mainStorage = mainStorage;
    }

    public static void setTaskDb(TaskDb taskDb) {
        ControlCenter.taskDb = taskDb;
    }

    public static void setAliasDb(AliasDb aliasDb) {
        ControlCenter.aliasDb = aliasDb;
    }

    public static void setEventBus(EventBus eventBus) {
        ControlCenter.eventBus = eventBus;
    }

}

@@ -81,16 +81,57 @@
 entBus;%0A
+import jfdi.common.utilities.JfdiLogger;%0A
 import j
@@ -661,16 +661,49 @@
 reeSet;%0A
+import java.util.logging.Logger;%0A
 import j
@@ -808,16 +808,82 @@
 ogic %7B%0A%0A
+    private static final Logger logger = JfdiLogger.getLogger();%0A%0A
     priv
@@ -1548,24 +1548,74 @@
 ng input) %7B%0A
+        logger.info(%22Handling input: %22 + input);%0A%0A
         Comm
@@ -3379,24 +3379,73 @@
 Storage() %7B%0A
+        logger.info(%22Initializing Storage...%22);%0A%0A
         // S
@@ -3936,89 +3936,254 @@
   %7D%0A
-    %7D%0A%0A    private void initParser() %7B%0A        parser.setAliases(aliasDb.getAll()
+%0A        logger.info(%22Storage initialized successfully!%22);%0A    %7D%0A%0A    private void initParser() %7B%0A        logger.info(%22Initializing Parser...%22);%0A%0A        parser.setAliases(aliasDb.getAll());%0A%0A        logger.info(%22Parser initialized successfully!%22
 );%0A 

Add some loggings to `ControlCenter`