/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package sdsimulator.runnable.expresiones;
import sdsimulator.runnable.*;
import java.util.Vector;

/**
 *
 * @author Miguel Herreros
 */
public class ExpresionPolaca {
    String[] expresionPolaca;
    private static Operadores operadores=new Operadores();
/**
 * A partir de una expresión infija separada en tokens, obtiene la expresión equi-
 * valente en notacuón tokensOrdenPolaca.
 * @param expresionInfija
 */
    //public ExpresionPolaca(String[] expresionInfija)throws Exception{
    public ExpresionPolaca(String expresion) throws Exception{
         ExpresionTokenizada expresionTokenizada = new ExpresionTokenizada(expresion);
         String token;
         Vector tokensOrdenPolaca=new Vector();
         int longitud=expresionTokenizada.size()+1;
         String[] auxEI=new String[expresionTokenizada.size()+1];
         
         for (int i=0;i<expresionTokenizada.size();i++)
             auxEI[i]=expresionTokenizada.getToken(i);
         
         auxEI[longitud - 1]="$"; //Terminador de expresión
         ///////////////////////////////////////////////////////////////////////
         Pila   pila  =new Pila();
         pila.push("$");//Este es un operador de control, gracias a sus priorida-
         //des, nos ahorrará controlar si la pila está vacía.
         
         for (int i=0; i < auxEI.length; i++){
             token = auxEI[i];
             if (!operadores.esOperador(token)){
                 tokensOrdenPolaca.add(token); //Es un valor, se añade al resultado.
             }
             else{
             //Operador que se apila o añade a la expresión según sus prioridades.
                while(operadores.getPrioridadPila((String)pila.top())>= operadores.getPrioridadEntrada(token)){
                    tokensOrdenPolaca.add((String)pila.pop());
                }   
                if (token.equals(")"))
                    pila.pop(); //Saca el paréntesis abierto. No hace falta cast, no vamos a usarlo.
                else
                    pila.push(token);
             }
         }
       
       //Esto lo hacemos para prescindir de las conversiones de tipo objeto a String al recuperar
       //del vector. expresionPolaca contiene lo mismo, pero te ahorras el cast.
       expresionPolaca=new String[tokensOrdenPolaca.size()];
       for (int i=0;i<tokensOrdenPolaca.size();i++)
             expresionPolaca[i]=(String)tokensOrdenPolaca.get(i);
    }
    
    public Variable evaluar(ContextoEjecucion contexto) throws Exception{
        Variable resultado, operador1, operador2;
        String token;
        
        Pila     pila= new Pila(); //En esta pila se guardan variables
        for (int i=0; i<expresionPolaca.length; i++){
            token = expresionPolaca[i];
            if (! operadores.esOperador(token))
                pila.push(convertirEnVariable(token,contexto));
            else{
                operador1=(Variable)pila.pop();
                if (operadores.getNumeroOperandos(token)==2)
                    operador2= (Variable)pila.pop();
                else
                    operador2=null;
                
                resultado=operadores.aplicar(token, operador1, operador2);
                pila.push(resultado);
            }
        }
        resultado=(Variable)pila.pop();
        return resultado;
    }
    //..........................................................................
    /**
     * Esta función, intenta buscar el token en la tabla de variables. Si la en-
     * cuentra, devuelve esta variable. En otro caso, significará que se ha en-
     * contrado un token que representa HARDCODE (es una constante) Generamos u-
     * na variable falsa, porque la pila de operandos sólo admite variables.
     * @param token
     * @param contexto
     * @return
     */
    private Variable convertirEnVariable(String token, ContextoEjecucion contexto) throws Exception{
        Variable retorno = contexto.get(token);

        if (retorno!=null) //En caso de cumplirse esto, corresponde a una variable existente en contexto.
            return retorno;
        
        if (token.equalsIgnoreCase("true") || token.equalsIgnoreCase("false"))
            return  new Variable("AUX","Boolean",token); 
        
        //Llegados a este punto, o es un número o se elevará una excepción.
        Integer.parseInt(token);
        return new Variable("AUX","Integer",token);
    }
    //..........................................................................
    public static void main(String args[]) {
        // Este párrafo main está escrito para comprobar el evaluador de expresiones.
        //       ExpresionTokenizada expresion1=new ExpresionTokenizada("not(a<nota)");
        //ExpresionTokenizada expresion2=new ExpresionTokenizada("a==mb || c<b && not c");
        try{
            ExpresionPolaca expresion=new ExpresionPolaca("true||false&&true");
            ContextoEjecucion vacio=new ContextoEjecucion((VectorOrdenado)null);
            expresion.evaluar(vacio);
            System.out.println(".");
        } catch (Exception e){
            System.out.println("**** POLACA ****" + e.getMessage());
        }
    }
    //..........................................................................
}
