package es.ejie.frmk.infraestructura.traza;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import es.ejie.frmk.infraestructura.logs.base.Q70LogInterno;

public class Q70EvaluadorCondicion
{
	private final static int ID_TIPO_VARIABLE = 1;
	private final static int ID_TIPO_VALOR = 2;
	private final static int ID_TIPO_OPERADOR = 3;

	private final static String DEBUG = "DEBUG";
	private final static String INFO = "INFO";
	private final static String WARN = "WARN";
	private final static String ERROR = "ERROR";
	private final static String FATAL = "FATAL";

	Map variables;

	private static Map jerarquiaNiveles = new HashMap();

	static {
		jerarquiaNiveles.put(DEBUG, new Integer(1));
		jerarquiaNiveles.put(INFO, new Integer(2));
		jerarquiaNiveles.put(WARN, new Integer(3));
		jerarquiaNiveles.put(ERROR, new Integer(4));
		jerarquiaNiveles.put(FATAL, new Integer(5));

	}

	/** 
	 *Introducir una representación del estado de las variables.
	 *@param variables hashmap con clave un string identificando la variable,y contenido un String
	 *dentificando su valor.
	 */
	public void setVariables(Map variables)
	{
		this.variables = variables;
	}
	
	/**
	 * Evalúa la expresión 
	 * @param expresionPostFija expresión postfija
	 * @return boolean
	 * @throws Q70ExcepcionEvaluadorCondicion
	 */
	public boolean evaluateBoolExpr(ArrayList expresionPostFija)
		throws Q70ExcepcionEvaluadorCondicion
	{
		
		//Si no hay condiciones entonces devolver true
		if (expresionPostFija==null || expresionPostFija.size()==0)
			return true;
		
		Stack stack = new Stack();
		int size = expresionPostFija.size();
		for (int i = 0; i < size; i++)
		{
			Q70Token s = (Q70Token) expresionPostFija.get(i);
			if (s.getTipo() == ID_TIPO_OPERADOR)
			{
				//el nivel es un caso aparte el operador igual en realidad
				//no significa coincidencia
				if (s.getValor().equals(">"))
				{
					//comparar
					String op1 = (String) stack.pop();
					String op2 = (String) stack.pop();
					Q70LogInterno.log("comparacion " + op2 + " > " + op1);
					//valor del nivel expresado en la condicion
					int nivelCondicion =
						((Integer) jerarquiaNiveles.get(op1)).intValue();
					Q70LogInterno.log("Nivel condicion" + nivelCondicion);
					//nivel resultante de resolver la variable nivel
					int nivelVariable =
						((Integer) jerarquiaNiveles.get(op2)).intValue();
					Q70LogInterno.log("Nivel Variable" + nivelVariable);

					if (nivelVariable >= nivelCondicion)
					{
						stack.push(new Boolean(true));
						if (Q70LogInterno.isEnabled())
							Q70LogInterno.log("apilar : true ");
					}
					else
					{
						stack.push(new Boolean(false));
						if (Q70LogInterno.isEnabled())
							Q70LogInterno.log("apilar : false ");
					}
				}

				else if (s.getValor().equals("="))
				{
					//comparar
					String op1 = (String) stack.pop();
					String op2 = (String) stack.pop();
					Q70LogInterno.log("comparacion " + op2 + " = " + op1);

					if (op1.equals(op2))
					{
						stack.push(new Boolean(true));
						if (Q70LogInterno.isEnabled())
							Q70LogInterno.log("apilar : true ");

					}
					else
					{
						stack.push(new Boolean(false));
						if (Q70LogInterno.isEnabled())
							Q70LogInterno.log("apilar : false ");
					}

				}
				else if (s.getValor().equals("!="))
				{

					//comparar
					String op1 = (String) stack.pop();
					String op2 = (String) stack.pop();
					if (Q70LogInterno.isEnabled())
						Q70LogInterno.log("operador " + op1 + " = " + op2);
					if (!op1.equals(op2))
					{
						stack.push(new Boolean(true));
						if (Q70LogInterno.isEnabled())
							Q70LogInterno.log("apilar : true ");

					}
					else
					{
						stack.push(new Boolean(false));
						if (Q70LogInterno.isEnabled())
							Q70LogInterno.log("apilar : false ");
					}

				}
				else if (s.getValor().equals("AND"))
				{

					boolean op1 = ((Boolean) stack.pop()).booleanValue();
					boolean op2 = ((Boolean) stack.pop()).booleanValue();
					Q70LogInterno.log("operador " + op1 + " AND " + op2);
					if (op1 && op2)
					{
						stack.push(new Boolean(true));
						Q70LogInterno.log("apilar : true ");
					}
					else
					{
						stack.push(new Boolean(false));
						Q70LogInterno.log("apilar : false ");
					}
				}
				else if (s.getValor().equals("OR"))
				{
					boolean op1 = ((Boolean) stack.pop()).booleanValue();
					boolean op2 = ((Boolean) stack.pop()).booleanValue();
					Q70LogInterno.log("operador " + op1 + " OR " + op2);
					if (op1 || op2)
					{
						stack.push(new Boolean(true));
						Q70LogInterno.log("apilar : true ");
					}
					else
					{
						stack.push(new Boolean(false));
						Q70LogInterno.log("apilar : false ");
					}
				}
				else
				{
					if (Q70LogInterno.isEnabled())
						Q70LogInterno.log("operador desconocido: " + s.getValor());
					throw new Q70ExcepcionEvaluadorCondicion(
						"operador desconocido: " + s.getValor());
				}

			}
			else if (s.getTipo() == ID_TIPO_VARIABLE)
			{
				//resolver variable
				if (Q70LogInterno.isEnabled())
					Q70LogInterno.log("apilar : " + variables.get(s.getValor()));
				stack.push(variables.get(s.getValor()));
			}
			else if (s.getTipo() == ID_TIPO_VALOR)
			{
				if (Q70LogInterno.isEnabled())
					Q70LogInterno.log("apilar : " + s.getValor());
				stack.push(s.getValor());
			}
		}

		return ((Boolean) stack.pop()).booleanValue();
	}
}
