package compiler;

import filehandler.JsonWriter;
import grammar.ReceiptLexer;
import grammar.ReceiptParser;
import infrastructure.SemanticListener;
import infrastructure.exceptions.JsonExportException;
import infrastructure.exceptions.SemanticException;
import infrastructure.exceptions.TranslationException;
import infrastructure.json.JsonStructure;
import infrastructure.translator.Translator;
import java.io.File;
import java.io.FileInputStream;
import java.util.LinkedList;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.RecognitionException;

/**
 *
 * @author Lucas
 */
public class Compiler {

    private static LinkedList<String> filesToCompile;

    private String in;
    private String out;
    
    private static int Id;

    Compiler(String in) {
        try {
            if (in.isEmpty()) {
                throw new IllegalArgumentException("Parameter in cannot be an empty String");
            }

            this.in = in;
            
            String parent = new File(in).getParentFile().getName();
            out = in.substring(0, in.indexOf("input")) + "output\\";
            
            if (!parent.equals("input")) {
                out += parent + "\\";
            }
            
            out += (++Id) + ".json";
        } catch (NullPointerException e) {
            throw new IllegalArgumentException(e.getMessage());
        }
    }
    
    Compiler(String in, String out) {
        this(in);
        this.out = out;
    }

    /**
     * @param args the command line arguments
     * @throws java.lang.Exception
     */
    public static void main(String[] args) throws Exception {
        filesToCompile = new LinkedList<>();

        if (args.length > 0) {
            File file = new File(args[0]);
            
            if (file.isDirectory()) {
                for (File child : file.listFiles()) {
                    filesToCompile.add(child.getPath());
                }
            } else {
                filesToCompile.add(file.getPath());
            }
        } else {
            filesToCompile.add("src/input/test.txt");
        }
        
        for (String file : filesToCompile) {
            try {
                new Compiler(file).start();
            
            } catch (IllegalArgumentException e) {
                System.err.println("The input file name is invalid: \"" + file + "\"");
            
            } catch (RecognitionException e) {
                System.err.println("Recognition error on file \"" + file + "\": "
                + e.getMessage());

            } catch (SemanticException e) {
                System.err.println("Semantic error on file \"" + file + "\".\n"
                        + "The compilation of this specific file cannot continue.");

            } catch (TranslationException e) {
                System.err.println("Translation error on file \"" + file + "\": "
                    + e.getMessage());
                
            } catch (JsonExportException e) {
                System.err.println("Json exportation error on file \"" + file + "\": "
                    + e.getMessage());
            } catch (Exception e) {
                System.err.println("An error has occured while compiling file \"" + file + "\": "
                    + e.getMessage());
            }
        }
    }

    private void start() throws Exception {
        System.out.println("\nInput file: " + in);

        System.out.print("Parsing has started... ");
        ANTLRInputStream inputStream = new ANTLRInputStream(new FileInputStream(in));

        ReceiptLexer lexer   = new ReceiptLexer(inputStream);
        ReceiptParser parser = new ReceiptParser(new CommonTokenStream(lexer));

        // parse input file and retrieve its JsonStructure
        JsonStructure tree = parser.receipt().e;
        System.out.println("Done!");
        
        SemanticListener semantics = new SemanticListener(tree);
        
        if(semantics.hasErrors()) {
            System.err.println("Semantic errors were found:");
            
            for (String error : semantics.errors()) {
                System.err.println(error);
            }
            
            throw new SemanticException();
        }

        System.out.print("Translation has started... ");
        // print JsonStructure to the String result
        String result = new Translator(tree)
                .run()
                .export();
        System.out.println("Done!");

        System.out.print("Exporting .json file... ");

        // export file with printed JsonStructure
        new JsonWriter(out, result)
                .export();

        System.out.println("Done!");
    }
}

@@ -144,24 +144,68 @@
 cListener;%0D%0A
+import infrastructure.SyntacticalListener;%0D%0A
 import infra
@@ -280,24 +280,132 @@
 eptions.
-Semantic
+LexicalException;%0D%0Aimport infrastructure.exceptions.SemanticException;%0D%0Aimport infrastructure.exceptions.Syntactical
 Exceptio
@@ -503,24 +503,70 @@
 Structure;%0D%0A
+import infrastructure.messagebag.MessageBag;%0D%0A
 import infra
@@ -650,24 +650,58 @@
 putStream;%0D%0A
+import java.text.ParseException;%0D%0A
 import java.
@@ -2949,16 +2949,58 @@
  catch (
+LexicalException %7C SyntacticalException %7C 
 Semantic
@@ -3054,80 +3054,8 @@
 tln(
-%22Semantic error on file %5C%22%22 + file + %22%5C%22.%5Cn%22%0D%0A                        + 
 %22The
@@ -3832,32 +3832,34 @@
 started... %22);%0D%0A
+%0D%0A
         ANTLRInp
@@ -3927,24 +3927,398 @@
 am(in));%0D%0A%0D%0A
+        // instantiating error bag and listeners%0D%0A        MessageBag lexicalBag     = new MessageBag();%0D%0A        MessageBag syntacticalBag = new MessageBag();%0D%0A        %0D%0A        SyntacticalListener lexics     = new SyntacticalListener(lexicalBag);%0D%0A        SyntacticalListener syntactics = new SyntacticalListener(syntacticalBag);%0D%0A        %0D%0A        // injecting listeners%0D%0A
         Rece
@@ -4364,24 +4364,65 @@
 utStream);%0D%0A
+        lexer.addErrorListener(lexics);%0D%0A
         Rece
@@ -4485,24 +4485,70 @@
 am(lexer));%0D
+%0A        parser.addErrorListener(syntactics);%0D
 %0A%0D%0A        /
@@ -4647,16 +4647,282 @@
 pt().e;%0D
+%0A%0D%0A        // stops compilation proccess if errors were found%0D%0A        if (!lexicalBag.isEmpty()) %7B%0D%0A            throw new LexicalException();%0D%0A        %7D%0D%0A%0D%0A        if (!syntacticalBag.isEmpty()) %7B%0D%0A            throw new SyntacticalException();%0D%0A        %7D%0D%0A        %0D
 %0A       
@@ -5543,24 +5543,34 @@
 .export();%0D%0A
+        %0D%0A
         Syst

Update Compiler.java