/*
 * AdaptationGenerator.java
 */

package com.uvigo.tMaestro.SCOCreator.tool.adaptationGenerator;


import com.uvigo.tMaestro.SCOCreator.tool.MainFrame;
import com.uvigo.tMaestro.SCO.adaptation.ObjectFactory;
import com.uvigo.tMaestro.SCO.adaptation.Adaptation;
import com.uvigo.tMaestro.SCO.adaptation.AdaptationType;
import com.uvigo.tMaestro.SCO.adaptation.SourceValue;
import com.uvigo.tMaestro.SCOCreator.tool.adaptation.Rule;
import com.uvigo.tMaestro.SCOCreator.tool.adaptation.Expression;
import com.uvigo.tMaestro.SCOCreator.tool.adaptation.Rule.Product;

/**
 * Clase encargada de la generacion del fihcero de adaptacion.xml
 * @author raul
 * @version 0.1
 */
public class AdaptationGenerator {
    
    /**
     * Cadena de caracteres que identifica la fuente de los parametros que
     * se usaran en el fichero de adaptacion.
     */
    final private static String sSource="tmaestro_idtv_det_uvigo_es";
    
    /**
     * Genera el fichero de adaptacion
     * @param oMainFrame Referencia al MainFrame de la herramienta
     * @param sDefaultOption La opcion por defecto. 
     * @throws java.lang.Exception Si se produce algun error durante la generacion de los ficheros .xml
     */
    public static void generateAdaptationFile(MainFrame oMainFrame,String sDefaultOption) throws Exception {
       //El directorio del proyecto en este punto se supone creado. Obtenemos su ruta
        java.io.File oProjectDir = oMainFrame.fTemp; //M: carpeta TEMP
       java.io.File oAdaptationDir = new java.io.File(oProjectDir, "ADAPTATION");
        try {
            java.io.FileOutputStream oFOS = new java.io.FileOutputStream(new java.io.File(oAdaptationDir,"adaptation.xml"));
            ObjectFactory oFactory = new ObjectFactory(); //El ObjectFactory para crear las estructuras que luego ser�n portadas a .xml
            //Elemento adaptation del fichero .xml:
            Adaptation oAdaptation = oFactory.createAdaptation();
            //Elemento AdaptationRules en .xml:
            Adaptation.AdaptationRulesType oAdaptationRules = oFactory.createAdaptationTypeAdaptationRulesType();
            //Creamos un Array para almacenar los parametros que seran utilizados en oAdaptationRules
            //Esto lo hacemos porque despues los necesitamos para crear el elemento adaptationParameters
            java.util.ArrayList<SourceValue> oParametersList = new java.util.ArrayList<SourceValue>();
            for (int i=0;i<oMainFrame.sizeRules();i++){ //Recorremos todos las reglas validadas
                Rule oValidatedRule=oMainFrame.getRule(i);
                if (!oMainFrame.getRule(i).isValid()) continue; //Si la regla no es valida pasamos a la siguiente
                //Vemos si la regla i-esima se puede expresar como una suma logica de condiciones simples.
                if (oValidatedRule.isSumOfSimpleExpression()) {
                    //Elemento Rule en .xml:
                    Adaptation.AdaptationRulesType.RuleType oRule = oFactory.createAdaptationTypeAdaptationRulesTypeRuleType();
                    //Elemento RuleConditions en .xml:
                    Adaptation.AdaptationRulesType.RuleType.RuleConditionsType oRuleConditions = oFactory.createAdaptationTypeAdaptationRulesTypeRuleTypeRuleConditionsType();
                    oRuleConditions.setConditionCombination("any");
                    //Cada producto de la SOP esta compuesta por una sola expression
                    //Cada una de ellas se codifica en una RuleCondition
                    for (int y=0;y<oValidatedRule.sizeSOP();y++) {
                        Expression oExpression = oValidatedRule.getProduct(y).getExpression(0);
                        //Elemento RuleCondition en .xml:
                        Adaptation.AdaptationRulesType.RuleType.RuleConditionsType.RuleConditionType oRuleCondition = oFactory.createAdaptationTypeAdaptationRulesTypeRuleTypeRuleConditionsTypeRuleConditionType();
                        //Elemento Adaptationparameter en .xml:
                        SourceValue oSourceValue = oFactory.createSourceValue();
                        //Elemento Comparative en .xml:
                        Adaptation.AdaptationRulesType.RuleType.RuleConditionsType.RuleConditionType.ComparativeType oComparative = oFactory.createAdaptationTypeAdaptationRulesTypeRuleTypeRuleConditionsTypeRuleConditionTypeComparativeType();
                        oSourceValue.setSource(sSource);
                        oSourceValue.setValue(oExpression.getParameter()); //Value de AdaptationParameter
                        if (!oParametersList.contains(oSourceValue)) oParametersList.add(oSourceValue);
                        oRuleCondition.setAdaptationParameter(oSourceValue);
                        oRuleCondition.setOperator(oExpression.getBoolean()); //Operador para la RuleCondition
                        oComparative.setOperator(oExpression.getOperator()); //Operador de Comparative
                        oComparative.setValue(oExpression.getValue()); //Valor de comparative
                        oRuleCondition.setComparative(oComparative);
                        oRuleConditions.getRuleCondition().add(oRuleCondition);
                    }
                    oRule.setRuleConditions(oRuleConditions);
                    //Elemento ruleAction en xml:
                    Adaptation.AdaptationRulesType.RuleType.RuleActionType oRuleAction = oFactory.createAdaptationTypeAdaptationRulesTypeRuleTypeRuleActionType();
                    oRuleAction.setFile("OPTIONS/"+oMainFrame.getOption(oValidatedRule.getOption())+".xml");
                    oRule.setRuleAction(oRuleAction);
                    oAdaptationRules.getRule().add(oRule);
                } else { //Esta regla debe ser codificada en el .xml como varios elementos Rule
                    //En concreto, a cada producto de la SOP de la regla le corresponde
                    //un elemento Rule. Todos estos elementos rules compartir�n la mimsa accion.
                    //Las expresiones que forman parte de cada producto se codificaran cada una de ellas
                    //en un elemento RuleCondition
                    //Como la accion es comun la preparamos primero
                    Adaptation.AdaptationRulesType.RuleType.RuleActionType oRuleAction = oFactory.createAdaptationTypeAdaptationRulesTypeRuleTypeRuleActionType();
                    oRuleAction.setFile("OPTIONS/"+oMainFrame.getOption(oValidatedRule.getOption())+".xml");
                    //Recorremos todos los productos de la SOP de la regla
                    for (int y=0;y<oValidatedRule.sizeSOP();y++) {
                        Product oProduct = oValidatedRule.getProduct(y);
                        //Elemento Rule en .xml:
                        Adaptation.AdaptationRulesType.RuleType oRule = oFactory.createAdaptationTypeAdaptationRulesTypeRuleType();
                        //Elemento RuleConditions en .xml:
                        Adaptation.AdaptationRulesType.RuleType.RuleConditionsType oRuleConditions = oFactory.createAdaptationTypeAdaptationRulesTypeRuleTypeRuleConditionsType();
                        //oRuleConditions.setConditionCombination("all"); No hace falta ponerlo, es el valor por defecto
                        //Recorremos todas las expresiones del producto
                        for (int z=0;z<oProduct.sizeExpressions();z++) {
                            Expression oExpression = oProduct.getExpression(z);
                            //Elemento RuleCondition en .xml:
                            Adaptation.AdaptationRulesType.RuleType.RuleConditionsType.RuleConditionType oRuleCondition = oFactory.createAdaptationTypeAdaptationRulesTypeRuleTypeRuleConditionsTypeRuleConditionType();
                            //Elemento AdaptationParameter en .xml:
                            SourceValue oSourceValue = oFactory.createSourceValue();
                            //Elemento Comparative en .xml:
                            Adaptation.AdaptationRulesType.RuleType.RuleConditionsType.RuleConditionType.ComparativeType oComparative = oFactory.createAdaptationTypeAdaptationRulesTypeRuleTypeRuleConditionsTypeRuleConditionTypeComparativeType();
                            oSourceValue.setSource(sSource);
                            oSourceValue.setValue(oExpression.getParameter()); //Value de AdaptationParameter
                            if (!oParametersList.contains(oSourceValue)) oParametersList.add(oSourceValue);
                            oRuleCondition.setAdaptationParameter(oSourceValue);
                            if (oExpression.getBoolean().equals("not")) oRuleCondition.setOperator("not"); //Operador para la RuleCondition
                            oComparative.setOperator(oExpression.getOperator()); //Operador de Comparative
                            oComparative.setValue(oExpression.getValue()); //Valor de comparative
                            oRuleCondition.setComparative(oComparative);
                            oRuleConditions.getRuleCondition().add(oRuleCondition);
                        }
                        oRule.setRuleConditions(oRuleConditions);
                        oRule.setRuleAction(oRuleAction);
                        oAdaptationRules.getRule().add(oRule);
                    }
                }
            }
            //Despues de codificar todas las reglas debemos crear la regla que
            //contendra la opcion por defecto, es decir, aquellas regla que se evaluara
            //siempre que no se haya cumplido ninguna otra anterior.
            Adaptation.AdaptationRulesType.RuleType oDefaultRule = oFactory.createAdaptationTypeAdaptationRulesTypeRuleType();
            Adaptation.AdaptationRulesType.RuleType.RuleConditionsType oDefaultConditions = oFactory.createAdaptationTypeAdaptationRulesTypeRuleTypeRuleConditionsType();
            Adaptation.AdaptationRulesType.RuleType.RuleActionType oDefaultAction = oFactory.createAdaptationTypeAdaptationRulesTypeRuleTypeRuleActionType();
            oDefaultConditions.setDefault(true);
            oDefaultRule.setRuleConditions(oDefaultConditions);
           oDefaultAction.setFile("OPTIONS/"+sDefaultOption+".xml");
            oDefaultRule.setRuleAction(oDefaultAction);
            oAdaptationRules.getRule().add(oDefaultRule);
            
            oAdaptation.setAdaptationRules(oAdaptationRules);
            
            //Ahora debemos listar los parametros que 
            //se utilizaran en este fichero. Esto se consigue mediante el
            //elemento AdaptationParameters en.xml
            AdaptationType.AdaptationParametersType oAdaptationParameters = oFactory.createAdaptationTypeAdaptationParametersType();
            //Por cada uno de los parametros que se han usado para la generacion del elemento adaptationRules anadimos
            //un AdaptationParameter. Recorremos la lista y los vamos creando
            for (int i=0;i<oParametersList.size();i++) oAdaptationParameters.getAdaptationParameter().add(oParametersList.get(i));
            
            //Anadimos el oAdaptationParameters a oAdaptation
            oAdaptation.setAdaptationParameters(oAdaptationParameters);
            
            //Creamos el fichero xml
            javax.xml.bind.JAXBContext oJC=javax.xml.bind.JAXBContext.newInstance("com.uvigo.tMaestro.SCO.adaptation");
            javax.xml.bind.Marshaller oM = oJC.createMarshaller();
            oM.setProperty(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            oM.marshal(oAdaptation, oFOS);
            oFOS.flush();
            oFOS.close();
        } catch(Exception oE) {
            oE.printStackTrace();
            throw new Exception(MainFrame.oMainFrame.getMessage("Error26"));
        }
        
        
        
    }
    
}
