package seedu.geekeep.ui;

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

import javafx.fxml.FXML;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Region;
import seedu.geekeep.commons.core.LogsCenter;
import seedu.geekeep.commons.events.ui.NewResultAvailableEvent;
import seedu.geekeep.commons.util.FxViewUtil;
import seedu.geekeep.logic.Logic;
import seedu.geekeep.logic.commands.CommandResult;
import seedu.geekeep.logic.commands.exceptions.CommandException;

public class CommandBox extends UiPart<Region> {
    private final Logger logger = LogsCenter.getLogger(CommandBox.class);
    private static final String FXML = "CommandBox.fxml";
    public static final String ERROR_STYLE_CLASS = "error";

    private final Logic logic;

    @FXML
    private TextField commandTextField;

    private Optional<String> currentPrefix = Optional.empty();
    private int commandHistoryIndex;
    private List<String> matchingCommands = new ArrayList<>();
    private int matchingCommandIndex;

    public CommandBox(AnchorPane commandBoxPlaceholder, Logic logic) {
        super(FXML);
        this.logic = logic;
        addToPlaceholder(commandBoxPlaceholder);
        addHistoryEventHandler();
    }

    private void addHistoryEventHandler() {
        commandTextField.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
            if (!(event.getCode().equals(KeyCode.UP) || event.getCode().equals(KeyCode.DOWN))) {
                currentPrefix = Optional.empty();
                return;
            }
            String commandText = commandTextField.getText();
            int caretPosition = commandTextField.getCaretPosition();
            String prefix = commandText.substring(0, caretPosition);
            if (!currentPrefix.equals(Optional.of(prefix))) {
                currentPrefix = Optional.of(prefix);
                commandHistoryIndex = getCommandHistory().size() - 1;
                matchingCommands.clear();
                matchingCommands.add(commandText);
                matchingCommandIndex = 0;
            }
            Optional<String> matchingCommand;
            if (event.getCode().equals(KeyCode.UP)) {
                matchingCommand = findPreviousMatchingCommand(prefix, commandText);
            } else {
                matchingCommand = findNextMatchingCommand(prefix);
            }
            if (matchingCommand.isPresent()) {
                commandTextField.setText(matchingCommand.get());
                commandTextField.positionCaret(caretPosition);
            }
            event.consume();
        });
    }

    private Optional<String> findPreviousMatchingCommand(String prefix, String commandText) {
        logger.fine("Finding previous command that starts with \"" + prefix + "\"");
        if (matchingCommandIndex + 1 < matchingCommands.size()) {
            matchingCommandIndex++;
            return Optional.of(matchingCommands.get(matchingCommandIndex));
        }
        List<String> commandHistory = getCommandHistory();
        while (commandHistoryIndex >= 0) {
            String command = commandHistory.get(commandHistoryIndex);
            commandHistoryIndex--;
            if (command.startsWith(prefix) && !command.equals(commandText)) {
                matchingCommands.add(command);
                matchingCommandIndex++;
                return Optional.of(command);
            }
        }
        return Optional.empty();
    }

    private Optional<String> findNextMatchingCommand(String prefix) {
        logger.fine("Finding next command that starts with \"" + prefix + "\"");
        if (matchingCommandIndex == 0) {
            return Optional.empty();
        }
        matchingCommandIndex--;
        return Optional.of(matchingCommands.get(matchingCommandIndex));
    }

    private List<String> getCommandHistory() {
        return logic.getCommandHistory();
    }

    private void addToPlaceholder(AnchorPane placeHolderPane) {
        SplitPane.setResizableWithParent(placeHolderPane, false);
        placeHolderPane.getChildren().add(commandTextField);
        FxViewUtil.applyAnchorBoundaryParameters(getRoot(), 0.0, 0.0, 0.0, 0.0);
        FxViewUtil.applyAnchorBoundaryParameters(commandTextField, 0.0, 0.0, 0.0, 0.0);
    }

    @FXML
    private void handleCommandInputChanged() {
        try {
            CommandResult commandResult = logic.execute(commandTextField.getText());

            // process result of the command
            setStyleToIndicateCommandSuccess();
            commandTextField.setText("");
            logger.info("Result: " + commandResult.feedbackToUser);
            raise(new NewResultAvailableEvent(commandResult.feedbackToUser));

        } catch (CommandException e) {
            // handle command failure
            setStyleToIndicateCommandFailure();
            logger.info("Invalid command: " + commandTextField.getText());
            raise(new NewResultAvailableEvent(e.getMessage()));
        }
    }


    /**
     * Sets the command box style to indicate a successful command.
     */
    private void setStyleToIndicateCommandSuccess() {
        commandTextField.getStyleClass().remove(ERROR_STYLE_CLASS);
    }

    /**
     * Sets the command box style to indicate a failed command.
     */
    private void setStyleToIndicateCommandFailure() {
        commandTextField.getStyleClass().add(ERROR_STYLE_CLASS);
    }

}

@@ -1557,29 +1557,68 @@
     
-if (!(event.getCode()
+KeyCode keyCode = event.getCode();%0A            if (!(keyCode
 .equ
@@ -1636,31 +1636,23 @@
 .UP) %7C%7C 
-event.get
+key
 Code
-()
 .equals(
@@ -1665,24 +1665,81 @@
 e.DOWN))) %7B%0A
+                if (keyCode.equals(KeyCode.ENTER)) %7B%0A    
             
@@ -1768,32 +1768,50 @@
 tional.empty();%0A
+                %7D%0A
                 
@@ -2048,16 +2048,17 @@
    if (!
+(
 currentP
@@ -2090,16 +2090,103 @@
 prefix))
+%0A                    && matchingCommands.get(matchingCommandIndex).equals(commandText))
 ) %7B%0A    
@@ -2515,31 +2515,23 @@
     if (
-event.get
+key
 Code
-()
 .equals(

Reset matching commands only when changes detected