package terminal;

import java.io.IOException;

import com.googlecode.lanterna.TerminalPosition;
import com.googlecode.lanterna.input.*;
import com.googlecode.lanterna.terminal.*;

public class LispTerminal implements Runnable {

    private IOSafeTerminal terminal;
    private boolean isFinished;
    private String currentLine;

    public LispTerminal() {
        try {
            Terminal unsafe = new DefaultTerminalFactory().createTerminal();
            this.terminal = IOSafeTerminalAdapter.createRuntimeExceptionConvertingAdapter(unsafe);
        } catch (IOException e) {
            // TODO
            e.printStackTrace();
        }

        this.isFinished = false;
        this.currentLine = "";
    }

    public void run() {
        while (!isFinished) {
            handleKeyStroke(getKeyStroke());
            terminal.flush();
        }

        terminal.close();
    }

    private KeyStroke getKeyStroke() {
        KeyStroke keyStroke = null;

        try {
            keyStroke = terminal.readInput();
        } catch (IllegalStateException e) {
            // TODO - lantera is trying to exit private mode on ctrl-c (which we didn't enter)
            terminal.putCharacter('`');
            isFinished = true;
        }

        return keyStroke;
    }

    private void handleKeyStroke(KeyStroke keyStroke) {
        if (keyStroke == null)
            return;

        KeyType keyType = keyStroke.getKeyType();

        if (keyType == KeyType.ArrowLeft)
            moveCursorLeft();
        else if (keyType == KeyType.ArrowRight)
            moveCursorRight();
        else if (keyType == KeyType.Enter)
            doEnter();
        else if (keyType == KeyType.Backspace)
            doBackspace();
        else if (keyType == KeyType.Delete)
            doDelete();
        else if (keyType == KeyType.Character)
            doCharacter(keyStroke);
    }

    private void doEnter() {
        terminal.putCharacter('\n');
        currentLine = "";
    }

    private void moveCursorLeft() {
        TerminalPosition cursorPosition = terminal.getCursorPosition();
        terminal.setCursorPosition(cursorPosition.withRelativeColumn(-1));
    }

    private void moveCursorRight() {
        TerminalPosition cursorPosition = terminal.getCursorPosition();

        if (cursorPosition.getColumn() < currentLine.length())
            terminal.setCursorPosition(cursorPosition.withRelativeColumn(1));
    }

    private void doBackspace() {
        TerminalPosition cursorPosition = terminal.getCursorPosition();

        if (cursorPosition.getColumn() > 0) {
            String remaining = currentLine.substring(cursorPosition.getColumn(), currentLine.length());
            currentLine = currentLine.substring(0, cursorPosition.getColumn() - 1) + remaining;
            terminal.setCursorPosition(cursorPosition.withRelativeColumn(-1));

            for (char c : remaining.toCharArray())
                terminal.putCharacter(c);

            terminal.putCharacter(' ');
            terminal.setCursorPosition(cursorPosition.withRelativeColumn(-1));
        }
    }

    private void doDelete() {
        TerminalPosition cursorPosition = terminal.getCursorPosition();

        if (cursorPosition.getColumn() < currentLine.length()) {
            String remaining = currentLine.substring(cursorPosition.getColumn() + 1, currentLine.length());
            currentLine = currentLine.substring(0, cursorPosition.getColumn()) + remaining;

            for (char c : remaining.toCharArray())
                terminal.putCharacter(c);

            terminal.putCharacter(' ');
            terminal.setCursorPosition(cursorPosition);
        }
    }

    private void doCharacter(KeyStroke keyStroke) {
        TerminalPosition cursorPosition = terminal.getCursorPosition();

        if (cursorPosition.getColumn() < currentLine.length()) {
            String remaining = keyStroke.getCharacter()
                               + currentLine.substring(cursorPosition.getColumn(), currentLine.length());
            currentLine = currentLine.substring(0, cursorPosition.getColumn()) + remaining;

            for (char c : remaining.toCharArray())
                terminal.putCharacter(c);

            terminal.setCursorPosition(cursorPosition.withRelativeColumn(1));
        } else {
            terminal.putCharacter(keyStroke.getCharacter());
            currentLine += keyStroke.getCharacter();
        }
    }

}
