/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ca.mcmaster.cas.matlab2smt;

import ca.mcmaster.cas.matlab2smt.VariableParserParser.Bool_typeContext;
import ca.mcmaster.cas.matlab2smt.VariableParserParser.DefaulttypeContext;
import ca.mcmaster.cas.matlab2smt.VariableParserParser.Fixed_typeContext;
import ca.mcmaster.cas.matlab2smt.VariableParserParser.Real_typeContext;
import ca.mcmaster.cas.matlab2smt.VariableParserParser.VarContext;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.antlr.v4.runtime.tree.TerminalNode;

/**
 *
 * @author Matthew Dawson
 */
public class VariableParser {
    public VariableParser(String vars) {
        parseStringToVariables(vars);
    }
    
    public Variable getVar(String name) {
        return m_variables.get(name);
    }
    
    public Collection<Variable> getVarList() {
        return m_variables.values();
    }
    
    public String getCheckerOutput(CheckerGenerator generator) {
        String out = "";
        
        for(Entry<String, Variable> entry:m_variables.entrySet()) {
            out += generator.GenerateVariableDecleration(entry.getValue()) + "\n";
        }
        return out;
    }
    
    private void parseStringToVariables(String variables) {
        // create a CharStream that reads from standard input
        ANTLRInputStream input = new ANTLRInputStream(variables) {

            @Override
            public int LA(int i) {
                return Character.toLowerCase(super.LA(i));
            }
            
        };

        // create a lexer that feeds off of input CharStream
        VariableParserLexer lexer = new VariableParserLexer(input);

        // create a buffer of tokens pulled from the lexer
        CommonTokenStream tokens = new CommonTokenStream(lexer);

        // create a parser that feeds off the tokens buffer
        VariableParserParser parser = new VariableParserParser(tokens);

        ParseTree tree = parser.varlist();
        ParseTreeWalker walker = new ParseTreeWalker();
        VariableParserListener listener = new VariablesParserToVaribles();
        walker.walk(listener, tree);
    }
    
    private Map<String, Variable>  m_variables = new HashMap<String, Variable>();
    
    private class VariablesParserToVaribles extends VariableParserBaseListener {
        private String currentName;
        private VariableType currentType;

        @Override
        public void enterVar(VarContext ctx) {
            currentName = ctx.ID().getText();
        }

        @Override
        public void enterDefaulttype(DefaulttypeContext ctx) {
            currentType = new RealVariableType();
        }

        @Override
        public void enterReal_type(Real_typeContext ctx) {
            currentType = new RealVariableType();
        }

        @Override
        public void enterBool_type(Bool_typeContext ctx) {
            currentType = new BooleanVariableType();
        }

        @Override
        public void enterFixed_type(Fixed_typeContext ctx) {
            boolean signed = (ctx.NAT(0).getText().equals("0"))?false:true;
            int digits = Integer.parseInt(ctx.NAT(1).getText());
            int fractionPart = 0;
            TerminalNode fractionNode;
            if ((fractionNode = ctx.NAT(2)) != null) {
                fractionPart = Integer.parseInt(fractionNode.getText());
            }
            currentType = new FixedPointVariableType(signed, digits, fractionPart);
        }
        
        @Override
        public void exitVar(VarContext ctx) {
            m_variables.put(currentName, new Variable(currentName, currentType));
            currentName = null;
            currentType = null;
        }
    }
}
