/*
 *  Rule.java
 * 
 *  RELOAD Editor - An IMS Metadata, Content Packaging and Learning Design tool 
 *  with ADAPTATION AT ACTIVITY LEVEL
 *
 *  Copyright (c) 2006 Miguel Fernandez Lores
 *
 *  Technical Contact:
 *  Miguel Fern�ndez Lores
 *  e-mail: tucias@hotmail.com
 *
 */

package uk.ac.reload.editor.scormadaptive.rules.syntax;

import uk.ac.reload.editor.scormadaptive.rules.jdom.rule.adaptationCriterion;
import uk.ac.reload.editor.scormadaptive.rules.jdom.rule.ruleAction;
import uk.ac.reload.editor.scormadaptive.rules.jdom.rule.RuleCondition;
import uk.ac.reload.editor.scormadaptive.rules.jdom.rule.RuleConditions;
import uk.ac.reload.editor.scormadaptive.rules.user.userAction;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import javax.swing.DefaultListModel;
import org.jdom.Attribute;
//import org.jdom.Content;
import org.jdom.Element;

/**
 * This class contains all the information relative to a adaptation 
 * rule at activity level
 *
 * @author  lagar
 * @version 0.2 
 */
public class Rule {
    
    private String sName;
    
    private Boolean bValid;
    
    private DefaultListModel oModel;
    
    private Stack<userAction> oUserActions;
    
    private ArrayList<Activity> oActs;
    private int iSelectedAct = -1;
    
    private ArrayList<adaptationCriterion> oaCUsed;
    
    private String[] sRuleText = null;
    
    //A partir de aqui es para pasar a arbol JDOM
    //private ArrayList<LogicalExpression> oLE;
    
    private RuleConditions oRC;
    private Element oRuleConditions;
    
    private ruleAction oRA;
    private Element oRuleAction;
    
    private String sCombination = "";
    
    public int iCriteriaUsed = 0;
        
    /** 
     * Constructor
     */
    public Rule(String name, Boolean valid, userAction lastAction, String[] text, 
            RuleConditions rc, ruleAction ra, 
            DefaultListModel oDLM, ArrayList<Activity> acts) {
        sName = name;
        bValid = valid;
        if (lastAction != null) oUserActions.push(lastAction);
        sRuleText = text;
        oRC = rc;
        oRA = ra;
        
        oActs = acts;
        oaCUsed = null;
        
        oModel = oDLM;        
    }
    
     public Rule(String name, Boolean valid, userAction lastAction, 
             String[] text, DefaultListModel oDLM,
             ArrayList<Activity> acts) {
        sName = name;
        bValid = valid;
        if (lastAction != null) oUserActions.push(lastAction);
        sRuleText = text;
        oRuleConditions = null;
        oRuleAction = null;
        oActs = acts;
        oaCUsed = null;
        oModel = oDLM;
    }
     
     public Rule(String name, String[] text, Element oRC, Element oRA) throws Exception {
        sName = name;
        bValid = true;
        oUserActions = null;
        sRuleText = text;
        oRuleConditions = oRC;
        oRuleAction = oRA;
        oActs = null;
        oaCUsed = readAdaptationCriteria(oRC);
        oModel = null;
    }
    
    public void changeRuleText (String[] ruleText) {
        sRuleText = ruleText;
    }
    
    public void changeRuleText (String ruleText) {

        int iCount=0;
        
        char[] cRuleText = new char[ruleText.length()];
        cRuleText = ruleText.toCharArray();
        for (int i=0; i<ruleText.length(); i++) if (cRuleText[i] == '\n') iCount++;
        sRuleText = new String[iCount];
        int iAnt = 0;
        int iLine = 0;
        for (int i=0; i<ruleText.length(); i++) {
            if (cRuleText[i] == '\n') {
                sRuleText[iLine] = ruleText.substring(iAnt, i);
                iAnt = i+1;
                iLine++;
            }
        }
    }
    
    public void pushUserAction (userAction oUA) {
        if (oUserActions == null) oUserActions = new Stack<userAction>();
        oUserActions.push(oUA);
    }
    
    public void setValid (Boolean bNew){
        bValid = bNew;
    }
    
    public void setActivities (ArrayList<Activity> acts){
        if (oActs == null) oActs = new ArrayList<Activity>();  
        //oActs.addAll(acts);
        oActs = acts;
    } 
    
    public void setCriteria (ArrayList<adaptationCriterion> cri){
        if (oaCUsed == null) oaCUsed = new ArrayList<adaptationCriterion>();  
        //oaCUsed.addAll(cri);
        oaCUsed = cri;
    }
    
    public void setListModel (DefaultListModel model){
        if (oModel == null) oModel = new DefaultListModel();
        //for (int i = 0; i<model.size(); i++) oModel.add(i,model.get(i));
        oModel = model;
    }
    
    public Boolean getValid() {
        return bValid;
    }
    
    public String[] getRuleText() {
        return sRuleText;
    }
    
    public String getRuleTextLine (int iIndex) {
        return sRuleText[iIndex];
    }
    
    public userAction popUserAction (){
        if ((oUserActions == null)||(oUserActions.size() == 0)) return null;
        return oUserActions.pop();
    }
    
    public ArrayList<Activity> getActivities(){
        return oActs;
    }
    
    public void addActivity(Activity oAct){
        //if (oActs == null) oActs = new ArrayList<Activity>();
        //oActs.add(oAct);
        //if (oModel.getSize()==0) oModel = new DefaultListModel();
        //oModel.addElement(oAct.getToShow());
    }
    
    public void setSelectedAct(int iIndex){
       iSelectedAct = iIndex; 
    }
    
    public DefaultListModel getListModel(){
        return oModel;
    }
    
    public int getListModelSize(){
        return oModel.getSize();
    }
    
    public ArrayList<adaptationCriterion> getCriteriaUsed(){
        return oaCUsed;
    }
    
    public void validate(){
        //Esta crea la sintaxis de JDOM
        
        Attribute oAtt;
        
        oRuleConditions =  new Element("ruleConditions");
        if (oRC == null) oRC = new RuleConditions();
        if ((oRC.isDefault())||(sName.equals("Default"))){
            //Rule Default
            oAtt =  new Attribute("default","true");
            oRuleConditions.setAttribute(oAtt);
        }
        else {
            oAtt =  new Attribute("conditionCombination",oRC.getConditionCombination());
            oRuleConditions.setAttribute(oAtt);
            for(int i=0; i<oRC.getRuleConditionsSize(); i++){
                Element eRC = oRC.getElement(i);
                oRuleConditions.addContent(eRC);
            }
        }
        
        oRuleAction = new Element("ruleAction");
        Element oShow = new Element("show");
        oRuleAction.addContent(oShow);
        
        Activity oActSel = oActs.get(iSelectedAct);
        switch (oActSel.getType()){
            case Activity.LOGICALEXP:
                for (int i=0; i<oActSel.getLEArray().size(); i++){
                    //Recorremos todas las LE que componen esta activity
                    Element oEL = oActSel.getLE(i).validate();
                    oShow.addContent(oEL);
                }
                break;
            case Activity.ORGANIZATION:
                Element oOrg = new Element ("organization");
                oAtt = new Attribute("IDRef",oActSel.getID());
                oOrg.setAttribute(oAtt);
                oShow.addContent(oOrg);
                break;
            case Activity.ACTCHILD:
            case Activity.ACTWITHCHILD:
                Element oItem = new Element ("item");
                oAtt = new Attribute("IDRef",oActSel.getID());
                oItem.setAttribute(oAtt);
                oShow.addContent(oItem);
                break;
        }
        bValid = true; 
    }
    
    public int getUserActionsSize(){
        if (oUserActions == null) return 0;
        return oUserActions.size();
    }
    
    public String getName(){
        return sName;
    }
    
    public Element getElement(){
        Element oElRule = new Element("rule");
        
        //Anadimos un atributo name al elemento rule para guardar los nombres de las reglas
        oElRule.setAttribute("name", sName);                       
        oElRule.addContent((Element) oRuleConditions.clone());
        oElRule.addContent((Element) oRuleAction.clone());
        return oElRule;
    }
    
    public void addAdaptationCriterion(adaptationCriterion oaC){
        if (oaCUsed == null){
            oaCUsed = new ArrayList<adaptationCriterion>();
            oaCUsed.add(oaC);
        }
        else oaCUsed.add(oaC);
    }
    
    public void deleteAdaptationCriterion(int iIndex){
        if ((oaCUsed == null)||(oaCUsed.size()<=iIndex)) return;
        oaCUsed.remove(iIndex);
    }
    
    public String getCombination(){
        return sCombination;
    }
    
    public void setCombination(String combination){
        sCombination = combination;
    }
    
    public void setRuleConditions(RuleConditions orc){
        oRC = orc;
    }

    private ArrayList<adaptationCriterion> readAdaptationCriteria(Element oRC) throws Exception {
        ArrayList<adaptationCriterion> oAC = new ArrayList<adaptationCriterion>();
        List lRCs = oRC.getChildren("ruleCondition");
        if (lRCs == null) {
            throw new Exception("Rule Conditions: Element <ruleCondition> is mandatory");
        }
        Iterator oIt = lRCs.iterator();
        while (oIt.hasNext()){
            Element oElRC = (Element)oIt.next();
            Element oElAC = oElRC.getChild("adaptationParameter");
            if (oElAC == null) {
                throw new Exception("Rule Condition: Element <adaptationParameter> is mandatory");
            }
            Element oElSource = oElAC.getChild("source");
            Element oElValue = oElAC.getChild("value");
            if ((oElSource == null) || (oElValue == null)) {
                throw new Exception("Adaptation Criterion: Elements <source> " +
                        "and <value> are mandatory");
            }
            adaptationCriterion oaC = new adaptationCriterion(oElValue.getText(), oElSource.getText());
            oAC.add(oaC);
        }
        return oAC;
    }

    public void addRuleCondition(RuleCondition orC){
        if (oRC == null) oRC = new RuleConditions();
        oRC.addRuleCondition(orC);
    }

    public void removeLastRuleCondition(){
        oRC.deleteLastRuleCondition();
    }

    public RuleConditions getRuleConditions() {
        return oRC;
    }

    public void removeLastCriterionUsed() {
        if (oaCUsed == null) return;
        oaCUsed.remove(oaCUsed.size()-1);
    }

    public void addUserActionsStack(Element oElAux) {
        //Tenemos que recorrer todo el arbol buscando
        //Buscando ruleConditions, y dentro de ellas
        //adaptationCriterion items
        //Despues nos queda a�adir la accion de SHOW
        
        //HACER
    }
}