/*
 * 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 template;

import API.Utils;
import java.util.ArrayList;
import java.util.LinkedList;

/**
 *
 * @author EUGENIO CARVALHO
 */
public class TListener extends TemplateBaseListener {
    
    protected TemplateCtx ctx;
    protected StringBuilder sb = new StringBuilder();
    protected LinkedList<ArrayList<String>> args = new LinkedList<>();
    protected LinkedList<String> stmt = new LinkedList<>();
    protected String append;
    protected String returnCall;
    protected boolean suspend;
    protected TemplateCtx gctx;
    
    public TListener(TemplateCtx ctx, TemplateCtx gctx) {
        this.ctx = ctx;
        this.gctx = gctx;
    }
    
    @Override
    public String toString() {
        return sb.toString(); //To change body of generated methods, choose Tools | Templates.
    }
    
    @Override
    public void exitLiteral(TemplateParser.LiteralContext ctx) {
        if (ctx.parent.getClass().getName().equals("template.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<String>());
        super.enterArgs(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) {
        ExecCall(ctx);
        super.exitCall(ctx); //To change body of generated methods, choose Tools | Templates.
    }
    
    public ArrayList<String> ExecCall(TemplateParser.CallContext ctx) {
        ArrayList<String> arguments;
        if (!args.isEmpty()) {
            arguments = args.pop();
        } else {
            arguments = new ArrayList<>();
        }

//        System.out.println("Exec:" + ctx.ID().getText() + ":" + arguments);
        switch (ctx.ID().getText()) {
            case "T":  // Adiciona tabulacoes
                this.returnCall = T(arguments);
                break;
            case "HEX": // Convert valor hex
                this.returnCall = HEX(arguments);
                break;
            case "L": // Lavel function
                this.returnCall = L(arguments);
                break;
//            case "A": // Lavel function
//                this.returnCall = A(arguments);
//                break;
            case "PAD": // Lavel function
                this.returnCall = PAD(arguments);
                break;
            default:
                this.returnCall = "";
        }
        return arguments;
    }
    
    @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("'", "");
            // Global context
            if (seletor.substring(0, 1).equals("_")) {
                value = this.gctx.G(seletor);
            } else {
                value = this.ctx.G(seletor);
            }
            
        } else if (ctx.call() != null) {
            value = this.returnCall;
        } else if (ctx.literal() != null) {
            value = ctx.literal().any().getText();
        } else {
            value = ctx.number().getText();
        }
        ArrayList<String> arguments = args.peek();
        if (arguments != null) {
            arguments.add(value);
        } else {
//            this.append = value;
            this.stmt.push(value);
        }
        super.exitArg(ctx); //To change body of generated methods, choose Tools | Templates.
    }
    
    protected String HEX(ArrayList<String> arguments) {
        String value = arguments.get(0);
        if (!value.equals("")) {
            value = Get(value);
            value = hex(value);
            arguments.set(0, value);
            return PAD(arguments);
        }
        return "";
    }
    
    protected String T(ArrayList<String> arguments) {
        return Utils.Repeat("\t", arguments.get(0));
    }
    
    protected String L(ArrayList<String> arguments) {
        return " <" + arguments.get(0) + ">";
    }
    
    protected String hex(String value) {
        return Integer.toHexString(Integer.parseInt(value));
    }
    
    protected String PAD(ArrayList<String> arguments) {
        String value = arguments.get(0);
        if (arguments.size() > 1) {
            value = PAD(value, arguments.get(2), Integer.parseInt(arguments.get(1)));
        }
        return value;
    }
    
    protected String PAD(String value, String replace, int i) {
        return String.format("%" + i + "s", value).replace(" ", replace);
    }
    
//    protected String A(ArrayList<String> params) {
//        return String.format("%" + i + "s", value).replace(" ", replace);
//    }
    
    protected String Get(String value) {
        if (Utils.isNumber(value)) {
            return value;
        }
        if (value.substring(0, 1).equals("_")) {
            return gctx.G(value);
        } else {
            return ctx.G(value);
        }
    }
    
    protected String FormatNum(int value, String format) {
        switch (format) {
            case "hex":
                return Integer.toHexString(value);
            case "bin":
                return Integer.toBinaryString(value);
            case "oct":
                return Integer.toOctalString(value);
        }
        return value + "";
    }
    
}
