/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package templates;

import API.Utils;
import common.RegistroBase;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Stack;
import templates.TemplateParser.CallContext;

/**
 *
 * @author EUGENIO CARVALHO
 */
public class TListener extends TemplateBaseListener {

    protected RegistroBase ctx;
    protected StringBuilder sb = new StringBuilder();
    protected Stack<ArrayList<String>> args = new Stack<>();
    protected LinkedList<String> stmt = new LinkedList<>();
    protected String append;
    protected String returnCall;
    protected boolean suspend;
    protected String Error = null;

    public TListener(RegistroBase ctx) {
        this.ctx = ctx;
    }

    public String GetError() {
        return Error;
    }

    @Override
    public String toString() {
        return sb.toString(); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitLiteral(TemplateParser.LiteralContext ctx) {
//        System.out.println("@@@@@@@@@@ExitLiteral{" + ctx.parent.getClass().getName() + "}");
        if (ctx.parent.getClass().getName().equals("templates.TemplateParser$InitContext")) {
            sb.append(ctx.any().getText());
        }
        super.exitLiteral(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterExpression(TemplateParser.ExpressionContext ctx) {
        this.append = "";
        super.enterExpression(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitExpression(TemplateParser.ExpressionContext ctx) {
        sb.append(this.append);
        super.exitExpression(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterArgs(TemplateParser.ArgsContext ctx) {
        args.push(new ArrayList<>());
        super.enterArgs(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitArgs(TemplateParser.ArgsContext ctx) {
        super.exitArgs(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitStmt(TemplateParser.StmtContext ctx) {
        if (ctx.call() != null) {
            this.stmt.push(this.returnCall);
        }
        super.exitStmt(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitCall(TemplateParser.CallContext ctx) {
        try {
            ArrayList<String> arguments;

            if (!args.isEmpty()) {
                arguments = args.pop();
            } else {
                arguments = new ArrayList<>();
            }
//            System.out.println("ExitCall:" + ctx.ID().getText() + " -args:" + arguments);
            this.returnCall = Functions.Call(ctx.ID().getText(), this.ctx, arguments);

            super.exitCall(ctx); //To change body of generated methods, choose Tools | Templates.
        } catch (Exception ex) {
            ThrowError(ctx, ex.getMessage());
        }

    }

    @Override
    public void exitPart(TemplateParser.PartContext ctx) {
        if (!this.append.equals("")) {
            return;
        }
        if (!this.stmt.isEmpty() && !Utils.Empty(this.stmt.peek())) {
            if (ctx.pre != null) {
                this.append = ctx.pre.any().getText();
            }

            this.append += this.stmt.pop();

            if (ctx.pos != null) {
                this.append += ctx.pos.any().getText();
            }
        }

        super.exitPart(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitArg(TemplateParser.ArgContext ctx) {
        String value;
        if (ctx.seletor() != null) {
            String seletor = ctx.seletor().getText().replace("'", "");
            if (seletor.equals("label")) {
//                System.out.println("this.ctx(seletor:" + seletor + ":" + this.ctx);
            }
            value = this.ctx.Get(seletor);

        } else if (ctx.call() != null) {
            value = this.returnCall;
        } else if (ctx.literal() != null) {
            value = ctx.literal().any().getText();
        } else {
            value = ctx.number().getText();
        }
//        System.out.println("EXIT ARG:" + value);
        ArrayList<String> arguments = args.empty() ? null : args.peek();

        if (arguments != null) {
            arguments.add(value);
        } else {
            this.stmt.push(value);
        }

        super.exitArg(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    private void ThrowError(CallContext ctx, String message) {
        Error = "<" + ctx.getStart().getLine() + ":" + ctx.getStart().getCharPositionInLine() + "> " + message;
    }

    public boolean hasError() {
        return Error != null;
    }
}
