package interpreter;

import static function.builtin.EVAL.eval;

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

public class LispInterpreter {

    protected RuntimeEnvironment environment;
    private LispParser parser;

    public LispInterpreter() {
        this.environment = RuntimeEnvironment.getInstance();
    }

    public void interpret() {
        createParser();

        for (prompt(); !parser.isEof(); prompt())
            evaluateAndPrintNextSExpression();

        applyFinishingTouches();
    }

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

    protected void prompt() {}

    protected void evaluateAndPrintNextSExpression() {
        try {
            evaluateAndPrintNextSExpressionWithException();
        } catch (LispException e) {
            environment.getErrorManager().handle(e);
        }
    }

    private void evaluateAndPrintNextSExpressionWithException() {
        printSExpression(evaluateNextSExpression());
    }

    protected SExpression evaluateNextSExpression() {
        SExpression sExpression = parser.getNextSExpression();

        return eval(sExpression);
    }

    protected void printSExpression(SExpression sExpression) {
        String result = environment.decorateValueOutput(String.valueOf(sExpression));
        environment.getOutput().println(result);
        environment.getOutput().flush();
    }

    protected void applyFinishingTouches() {
        environment.getOutput().println();
        environment.getOutput().flush();
    }

}
