package de.ugoe.cs.quest.tasktrees.temporalrelation;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;

import de.ugoe.cs.quest.tasktrees.nodeequality.NodeEquality;
import de.ugoe.cs.quest.tasktrees.nodeequality.NodeEqualityRuleManager;
import de.ugoe.cs.quest.tasktrees.treeifc.ITaskTreeBuilder;
import de.ugoe.cs.quest.tasktrees.treeifc.ITaskTreeNode;
import de.ugoe.cs.quest.tasktrees.treeifc.ITaskTreeNodeFactory;
import de.ugoe.cs.util.console.Console;

/**
 * TODO comment
 * 
 * @version $Revision: $ $Date: 12.02.2012$
 * @author 2012, last modified by $Author: patrick$
 */
public class TemporalRelationshipRuleManager {
    
    /** */
    private NodeEqualityRuleManager nodeEqualityRuleManager;

    /** */
    private List<TemporalRelationshipRule> ruleIndex = new ArrayList<TemporalRelationshipRule>();

    /**
     * TODO: comment
     * 
     */
    public TemporalRelationshipRuleManager(NodeEqualityRuleManager nodeEqualityRuleManager) {
        super();
        this.nodeEqualityRuleManager = nodeEqualityRuleManager;
    }

    /**
     * TODO: comment
     * 
     */
    public void init() {
        ruleIndex.add(new DefaultGuiElementSequenceDetectionRule());
        ruleIndex.add(new DefaultEventTargetSequenceDetectionRule());
        ruleIndex.add(new TrackBarSelectionDetectionRule(nodeEqualityRuleManager));
        ruleIndex.add(new DefaultGuiEventSequenceDetectionRule());
        
        ruleIndex.add(new DefaultIterationDetectionRule
                          (nodeEqualityRuleManager, NodeEquality.LEXICALLY_EQUAL));
        ruleIndex.add(new DefaultIterationDetectionRule
                          (nodeEqualityRuleManager, NodeEquality.SYNTACTICALLY_EQUAL));
        ruleIndex.add(new DefaultIterationDetectionRule
                          (nodeEqualityRuleManager, NodeEquality.SEMANTICALLY_EQUAL));
    }

    /**
     * returns true, if there is a rule that matches the current situation and if, therefore, a new
     * temporal relationship has been added to the tree.
     * 
     * @param parent
     * @param newChild
     * @return
     */
    public void applyRules(ITaskTreeNode        parent,
                           ITaskTreeBuilder     builder,
                           ITaskTreeNodeFactory nodeFactory,
                           boolean              finalize)
    {
        applyRules(parent, builder, nodeFactory, finalize, "");
    }

    /**
     * returns true, if there is a rule that matches the current situation and if, therefore, a new
     * temporal relationship has been added to the tree.
     * 
     * @param parent
     * @param newChild
     * @return
     */
    private int applyRules(ITaskTreeNode        parent,
                           ITaskTreeBuilder     builder,
                           ITaskTreeNodeFactory nodeFactory,
                           boolean              finalize,
                           String               logIndent)
    {
        Console.traceln(Level.FINER, logIndent + "applying rules for " + parent);

        int noOfRuleApplications = 0;

        for (TemporalRelationshipRule rule : ruleIndex) {
            RuleApplicationResult result;
            do {
                // LOG.info(logIndent + "trying to apply rule " + rule + " on " + parent);
                result = rule.apply(parent, builder, nodeFactory, finalize);

                if ((result != null) &&
                    (result.getRuleApplicationStatus() ==
                     RuleApplicationStatus.RULE_APPLICATION_FINISHED))
                {
                    Console.traceln
                        (Level.FINE, logIndent + "applied rule " + rule + " on " + parent);
                    noOfRuleApplications++;

                    for (ITaskTreeNode newParent : result.getNewlyCreatedParentNodes()) {
                        noOfRuleApplications +=
                            applyRules(newParent, builder, nodeFactory, true, logIndent + "  ");
                    }
                }
            }
            while ((result != null) &&
                   (result.getRuleApplicationStatus() ==
                    RuleApplicationStatus.RULE_APPLICATION_FINISHED));

            if ((!finalize) &&
                (result != null) &&
                (result.getRuleApplicationStatus() ==
                 RuleApplicationStatus.RULE_APPLICATION_FEASIBLE))
            {
                // in this case, don't go on applying rules, which should not be applied yet
                break;
            }
        }

        if (noOfRuleApplications <= 0) {
            Console.traceln(Level.INFO, logIndent + "no rules applied --> no temporal " +
                            "relationship generated");
        }

        return noOfRuleApplications;
    }

    /**
   *
   */
    /*
     * private void dumpTask(TaskTreeNode task, String indent) { System.err.print(indent);
     * System.err.print(task); System.err.println(" ");
     * 
     * if ((task.getChildren() != null) && (task.getChildren().size() > 0)) { for (TaskTreeNode
     * child : task.getChildren()) { dumpTask(child, indent + "  "); } } }
     */

}
