package yokohama.unit.translator;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Arrays;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
import lombok.SneakyThrows;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Lexer;
import yokohama.unit.ast.Group;
import yokohama.unit.ast_junit.CompilationUnit;
import yokohama.unit.ast_junit.OgnlExpressionStrategy;
import yokohama.unit.grammar.YokohamaUnitLexer;
import yokohama.unit.grammar.YokohamaUnitParser;

public class TranslatorUtils {

    public static Group parseDocy(final String input) {
        return parseDocy(input, YokohamaUnitLexer.DEFAULT_MODE);
    }

    @SneakyThrows(IOException.class)
    static Group parseDocy(final String input, final int mode) {
        InputStream bais = new ByteArrayInputStream(input.getBytes());
        CharStream stream = new ANTLRInputStream(bais);
        Lexer lex = new YokohamaUnitLexer(stream);
        lex.mode(mode);
        CommonTokenStream tokens = new CommonTokenStream(lex);
        YokohamaUnitParser parser = new YokohamaUnitParser(tokens);
        return new ParseTreeToAstVisitor().visitGroup(parser.group());
    }

    public static String docyToJava(
            final String docy,
            final String className,
            final String packageName) {
        // Source to AST
        Group ast = parseDocy(docy);

        // AST to JUnit AST
        CompilationUnit junit =
                new AstToJUnitAst().translate(className, ast, packageName);

        // JUnit AST to string
        return junit.getText(new OgnlExpressionStrategy());
    }

    public static boolean compileDocy(
            final String docy,
            final String className,
            final String packageName,
            final String... options) {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        JavaFileObject source = new SimpleJavaFileObject(
                URI.create("string:///"
                        + packageName.replace('.','/') + "/" + className
                        + Kind.SOURCE.extension),
                Kind.SOURCE
        ) {
            @Override
            public CharSequence getCharContent(boolean ignoreEncodingErrors) {
                return docyToJava(docy, className, packageName);
            }
        };

        CompilationTask task = compiler.getTask(
                null, /* Writer out */
                null, /* JavaFileManager fileManager */
                null, /* DiagnosticListener<? super JavaFileObject> diagnosticListener */
                Arrays.asList(options),
                null, /* Iterable<String> classes */
                Arrays.asList(source)
        );
        return task.call(); 
    }
}

@@ -479,32 +479,80 @@
 LRInputStream;%0D%0A
+import org.antlr.v4.runtime.BaseErrorListener;%0D%0A
 import org.antlr
@@ -652,32 +652,124 @@
 runtime.Lexer;%0D%0A
+import org.antlr.v4.runtime.RecognitionException;%0D%0Aimport org.antlr.v4.runtime.Recognizer;%0D%0A
 import yokohama.
@@ -993,40 +993,614 @@
 r;%0D%0A
-%0D%0Apublic class TranslatorUtils %7B
+import yokohama.unit.grammar.YokohamaUnitParser.GroupContext;%0D%0A%0D%0Apublic class TranslatorUtils %7B%0D%0A%0D%0A    public static class TranslationException extends RuntimeException %7B%0D%0A    %7D%0D%0A%0D%0A    private static class ErrorListener extends BaseErrorListener %7B%0D%0A        public int numErrors = 0;%0D%0A        @Override%0D%0A        public void syntaxError(%0D%0A                Recognizer%3C?, ?%3E recognizer,%0D%0A                Object offendingSymbol,%0D%0A                int line,%0D%0A                int charPositionInLine,%0D%0A                String msg,%0D%0A                RecognitionException e) %7B%0D%0A            numErrors++;%0D%0A        %7D%0D%0A    %7D
 %0D%0A%0D%0A
@@ -1831,24 +1831,84 @@
 nt mode) %7B%0D%0A
+        ErrorListener errorListener = new ErrorListener();%0D%0A
         Inpu
@@ -2097,24 +2097,70 @@
 ode(mode);%0D%0A
+        lex.addErrorListener(errorListener);%0D%0A
         Comm
@@ -2276,24 +2276,219 @@
 r(tokens);%0D%0A
+        parser.addErrorListener(errorListener);%0D%0A        GroupContext ctx = parser.group();%0D%0A        if (errorListener.numErrors %3E 0) %7B%0D%0A            throw new TranslationException();%0D%0A        %7D%0D%0A
         retu
@@ -2529,30 +2529,19 @@
 itGroup(
-parser.group()
+ctx
 );%0D%0A    

Throw an exception when errors are found while parsing