package acceptance.fixture;

import static table.FunctionTable.resetFunctionTable;
import static util.Path.getPathPrefix;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.PrintStream;

import environment.RuntimeEnvironment;
import interpreter.LispInterpreter;
import interpreter.LispInterpreterBuilder;
import interpreter.LispInterpreterBuilderImpl;
import table.ExecutionContext;

public class LispInterpreterFixture {

    private static ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    private static ExecutionContext executionContext = ExecutionContext.getInstance();
    private static RuntimeEnvironment environment = RuntimeEnvironment.getInstance();
    private static LispInterpreter interpreter = null;

    public static void buildInterpreter() {
        LispInterpreterBuilder builder = new LispInterpreterBuilderImpl() {};
        builder.setOutput(new PrintStream(outputStream));
        builder.setErrorOutput(new PrintStream(outputStream));
        builder.setNotInteractive();
        builder.setTerminationFunction(LispInterpreterFixture::terminate);
        builder.setErrorTerminationFunction(LispInterpreterFixture::terminateFromError);

        interpreter = builder.build();
    }

    public static void terminate() {}

    public static void terminateFromError() {
        throw new RuntimeException("Error Termination");
    }

    public static void cleanUp() {
        clearFunctionsAndSymbols();
        environment.reset();
    }

    public static void clearFunctionsAndSymbols() {
        resetFunctionTable();
        executionContext.clearContext();
    }

    public String evaluateText(String input) {
        environment.setInputName("fitnesse");
        environment.setInput(new ByteArrayInputStream(input.getBytes()));
        environment.setPath("");

        return evaluate();
    }

    public String evaluateFile(String inputFile) throws FileNotFoundException {
        environment.setInputName(inputFile);
        environment.setInput(new FileInputStream(inputFile));
        environment.setPath(getPathPrefix(inputFile));

        return evaluate();
    }

    private String evaluate() {
        interpreter.interpret();
        String output = outputStream.toString();
        outputStream.reset();

        return output.trim();
    }

}
