package interpreter;

import static function.builtin.EVAL.eval;

import java.io.*;

import environment.RuntimeEnvironment;
import error.*;
import parser.LispParser;
import sexpression.SExpression;

public class LispInterpreter {

    protected RuntimeEnvironment environment;
    protected ErrorManager errorManager;
    protected PrintStream output;
    private LispParser parser;

    public LispInterpreter() {
        this.environment = RuntimeEnvironment.getInstance();
        this.errorManager = this.environment.getErrorManager();
        this.output = environment.getOutput();
    }

    public void setInput(InputStream input, String inputName) {
        environment.setInput(input);
        environment.setInputName(inputName);
    }

    public void interpret() {
        createParser();
        printGreeting();

        for (displayPrompt(); !parser.isEof(); displayPrompt())
            printValueOfNextSExpression();

        printFarewell();
    }

    private void createParser() {
        parser = new LispParser(environment.getInput(), environment.getInputName());
    }

    protected void printGreeting() {}

    protected void displayPrompt() {}

    private void printValueOfNextSExpression() {
        try {
            printValueOfNextSExpressionWithException();
        } catch (LispException e) {
            erasePrompt();
            errorManager.handle(e);
        }
    }

    private void printValueOfNextSExpressionWithException() {
        SExpression sExpression = parser.getNextSExpression();
        String result = environment.decorateValueOutput(String.valueOf(eval(sExpression)));

        erasePrompt();
        output.println(result);
    }

    protected void erasePrompt() {}

    protected void printFarewell() {
        output.println();
    }

}
