package seedu.address.logic;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;

import java.util.Collections;
import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import com.google.common.eventbus.Subscribe;

import seedu.address.commons.core.EventsCenter;
import seedu.address.commons.events.model.TaskBookChangedEvent;
import seedu.address.commons.events.ui.ShowHelpRequestEvent;
import seedu.address.logic.commands.ClearCommand;
import seedu.address.logic.commands.CommandResult;
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.ReadOnlyTaskBook;
import seedu.address.model.TaskBook;
import seedu.address.model.task.Task;
import seedu.address.model.task.TypicalFloatingTasks;
import seedu.address.storage.StorageManager;

public class LogicManagerTest {

    /**
     * See https://github.com/junit-team/junit4/wiki/rules#temporaryfolder-rule
     */
    @Rule
    public TemporaryFolder saveFolder = new TemporaryFolder();

    private Model model;
    private Logic logic;

    //These are for checking the correctness of the events raised
    private ReadOnlyTaskBook latestSavedTaskBook;
    private boolean helpShown;

    private TypicalFloatingTasks tft = new TypicalFloatingTasks();

    @Subscribe
    private void handleLocalModelChangedEvent(TaskBookChangedEvent abce) {
        latestSavedTaskBook = new TaskBook(abce.data);
    }

    @Subscribe
    private void handleShowHelpRequestEvent(ShowHelpRequestEvent she) {
        helpShown = true;
    }

    @Before
    public void setup() {
        model = new ModelManager();
        String tempConfigFile = saveFolder.getRoot().getPath() + "tempConfig.json";
        String tempTaskBookFile = saveFolder.getRoot().getPath() + "TempTaskBook.json";
        logic = new LogicManager(model, new StorageManager(tempConfigFile, tempTaskBookFile));
        EventsCenter.getInstance().registerHandler(this);

        latestSavedTaskBook = new TaskBook(model.getTaskBook()); // last saved assumed to be up to date before.
        helpShown = false;
    }

    @After
    public void teardown() {
        EventsCenter.clearSubscribers();
    }

    @Test
    public void execute_invalid() throws Exception {
        String invalidCommand = "       ";
        assertCommandBehavior(invalidCommand,
                String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
    }

    /**
     * Executes the command and confirms that the result message is correct.
     * Both the 'address book' and the 'last shown list' are expected to be empty.
     * @see #assertCommandBehavior(String, String, ReadOnlyTaskBook, List)
     */
    private void assertCommandBehavior(String inputCommand, String expectedMessage) throws Exception {
        assertCommandBehavior(inputCommand, expectedMessage, new TaskBook(), Collections.emptyList());
    }

    /**
     * Executes the command and confirms that the result message is correct and
     * also confirms that the following three parts of the LogicManager object's state are as expected:<br>
     *      - the internal task book data are same as those in the {@code expectedTaskBook} <br>
     *      - the backing list shown by UI matches the {@code shownList} <br>
     *      - {@code expectedTaskBook} was saved to the storage file. <br>
     */
    private void assertCommandBehavior(String inputCommand, String expectedMessage,
                                       ReadOnlyTaskBook expectedTaskBook,
                                       List<? extends Task> expectedShownList) throws Exception {

        //Execute the command
        CommandResult result = logic.execute(inputCommand);

        //Confirm the ui display elements should contain the right data
        assertEquals(expectedMessage, result.feedbackToUser);
        assertEquals(expectedShownList, model.getFilteredTaskList());

        //Confirm the state of data (saved and in-memory) is as expected
        assertEquals(expectedTaskBook, model.getTaskBook());
        assertEquals(expectedTaskBook, latestSavedTaskBook);
    }

    @Test
    public void execute_unknownCommandWord() throws Exception {
        String unknownCommand = "uicfhmowqewca";
        assertCommandBehavior(unknownCommand, MESSAGE_UNKNOWN_COMMAND);
    }

    @Test
    public void execute_help() throws Exception {
        assertCommandBehavior("help", HelpCommand.SHOWING_HELP_MESSAGE);
        assertTrue(helpShown);
    }

    @Test
    public void execute_exit() throws Exception {
        assertCommandBehavior("exit", ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT);
    }

    @Test
    public void execute_clear() throws Exception {
        model.addFloatingTask(tft.buyAHelicopter);
        model.addFloatingTask(tft.readABook);

        assertCommandBehavior("clear", ClearCommand.MESSAGE_SUCCESS, new TaskBook(), Collections.emptyList());
    }

}

@@ -72,51 +72,8 @@
 ls;%0A
-import static org.junit.Assert.assertTrue;%0A
 impo
@@ -578,119 +578,8 @@
 nt;%0A
-import seedu.address.commons.events.ui.ShowHelpRequestEvent;%0Aimport seedu.address.logic.commands.ClearCommand;%0A
 impo
@@ -629,57 +629,8 @@
 lt;%0A
-import seedu.address.logic.commands.ExitCommand;%0A
 impo
@@ -863,16 +863,24 @@
 el.task.
+Deadline
 Task;%0Aim
@@ -909,23 +909,59 @@
 el.task.
-Typical
+EventTask;%0Aimport seedu.address.model.task.
 Floating
@@ -964,17 +964,16 @@
 tingTask
-s
 ;%0Aimport
@@ -1385,107 +1385,8 @@
 ook;
-%0A    private boolean helpShown;%0A%0A    private TypicalFloatingTasks tft = new TypicalFloatingTasks();
 %0A%0A  
@@ -1539,128 +1539,8 @@
  %7D%0A%0A
-    @Subscribe%0A    private void handleShowHelpRequestEvent(ShowHelpRequestEvent she) %7B%0A        helpShown = true;%0A    %7D%0A%0A
     
@@ -2051,35 +2051,8 @@
 re.%0A
-        helpShown = false;%0A
     
@@ -2814,32 +2814,112 @@
  new TaskBook(),
+%0A                              Collections.emptyList(), Collections.emptyList(),
  Collections.emp
@@ -3596,18 +3596,191 @@
 ist%3C
-? extends 
+FloatingTask%3E expectedFloatingTaskShownList,%0A                                       List%3CDeadlineTask%3E expectedDeadlineTaskShownList,%0A                                       List%3CEvent
 Task
@@ -3781,32 +3781,41 @@
 ntTask%3E expected
+EventTask
 ShownList) throw
@@ -4083,16 +4083,28 @@
 expected
+FloatingTask
 ShownLis
@@ -4123,16 +4123,198 @@
 Filtered
+FloatingTaskList());%0A        assertEquals(expectedDeadlineTaskShownList, model.getFilteredDeadlineTaskList());%0A        assertEquals(expectedEventTaskShownList, model.getFilteredEvent
 TaskList
@@ -4727,602 +4727,6 @@
  %7D%0A%0A
-    @Test%0A    public void execute_help() throws Exception %7B%0A        assertCommandBehavior(%22help%22, HelpCommand.SHOWING_HELP_MESSAGE);%0A        assertTrue(helpShown);%0A    %7D%0A%0A    @Test%0A    public void execute_exit() throws Exception %7B%0A        assertCommandBehavior(%22exit%22, ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT);%0A    %7D%0A%0A    @Test%0A    public void execute_clear() throws Exception %7B%0A        model.addFloatingTask(tft.buyAHelicopter);%0A        model.addFloatingTask(tft.readABook);%0A%0A        assertCommandBehavior(%22clear%22, ClearCommand.MESSAGE_SUCCESS, new TaskBook(), Collections.emptyList());%0A    %7D%0A%0A
 %7D%0A

remove dependency on getFilteredTaskList()