// Module    : $RCSfile: TrackBarSelectionDetectionRule.java,v $
// Version   : $Revision: 0.0 $  $Author: patrick $  $Date: 28.04.2012 $
// Project   : TaskTreeTemporalRelationship
// Creation  : 2012 by patrick
// Copyright : Patrick Harms, 2012

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

import de.ugoe.cs.quest.eventcore.gui.ValueSelection;
import de.ugoe.cs.quest.eventcore.guimodel.ITrackBar;
import de.ugoe.cs.quest.tasktrees.nodeequality.NodeEquality;
import de.ugoe.cs.quest.tasktrees.nodeequality.NodeEqualityRuleManager;
import de.ugoe.cs.quest.tasktrees.treeifc.IEventTask;
import de.ugoe.cs.quest.tasktrees.treeifc.IIteration;
import de.ugoe.cs.quest.tasktrees.treeifc.ISelection;
import de.ugoe.cs.quest.tasktrees.treeifc.ISequence;
import de.ugoe.cs.quest.tasktrees.treeifc.ITaskTreeBuilder;
import de.ugoe.cs.quest.tasktrees.treeifc.ITaskTreeNode;
import de.ugoe.cs.quest.tasktrees.treeifc.ITaskTreeNodeFactory;

/**
 * TODO comment
 * 
 * @version $Revision: $ $Date: 28.04.2012$
 * @author 2012, last modified by $Author: patrick$
 */
public class TrackBarSelectionDetectionRule implements TemporalRelationshipRule {

    /** */
    private NodeEqualityRuleManager nodeEqualityRuleManager;

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

    /*
     * (non-Javadoc)
     * 
     * @see TemporalRelationshipRule#apply(TaskTreeNode, TaskTreeBuilder, TaskTreeNodeFactory)
     */
    @Override
    public RuleApplicationResult apply(ITaskTreeNode        parent,
                                       ITaskTreeBuilder     builder,
                                       ITaskTreeNodeFactory nodeFactory,
                                       boolean              finalize)
    {
        if (!(parent instanceof ISequence)) {
            return null;
        }

        RuleApplicationResult result = new RuleApplicationResult();

        int valueSelectionStartIndex = -1;

        int index = 0;
        while (index < parent.getChildren().size()) {
            ITaskTreeNode child = parent.getChildren().get(index);

            if ((child instanceof IEventTask) &&
                (((IEventTask) child).getEventTarget() instanceof ITrackBar) &&
                (((IEventTask) child).getEventType() instanceof ValueSelection))
            {
                if (valueSelectionStartIndex < 0) {
                    // let the show begin
                    valueSelectionStartIndex = index;
                }
            }
            else if (valueSelectionStartIndex >= 0) {
                // current child is no more value selection. But the preceding tasks were.
                // Therefore,
                // create an iteration with the different selectable values as selection children
                handleValueSelections(valueSelectionStartIndex, index - 1, parent, builder,
                                      nodeFactory, result);

                return result;
            }

            index++;
        }

        if (valueSelectionStartIndex >= 0) {
            if (finalize) {
                handleValueSelections(valueSelectionStartIndex, parent.getChildren().size() - 1,
                                      parent, builder, nodeFactory, result);
            }
            else {
                result.setRuleApplicationStatus(RuleApplicationStatus.RULE_APPLICATION_FEASIBLE);
            }
        }

        return result;
    }

    /**
     * TODO: comment
     * 
     * @param valueSelectionStartIndex
     * @param i
     */
    private void handleValueSelections(int                   startIndex,
                                       int                   endIndex,
                                       ITaskTreeNode         parent,
                                       ITaskTreeBuilder      builder,
                                       ITaskTreeNodeFactory  nodeFactory,
                                       RuleApplicationResult result)
    {
        IIteration iteration = nodeFactory.createNewIteration();
        result.addNewlyCreatedParentNode(iteration);

        ISelection selection = nodeFactory.createNewSelection();
        result.addNewlyCreatedParentNode(selection);
        builder.setChild(iteration, selection);

        for (int i = endIndex - startIndex; i >= 0; i--) {
            addChildIfNecessary(selection, parent.getChildren().get(startIndex), builder,
                                nodeFactory, result);
            builder.removeChild((ISequence) parent, startIndex);
        }

        builder.addChild((ISequence) parent, startIndex, iteration);

        result.setRuleApplicationStatus(RuleApplicationStatus.RULE_APPLICATION_FINISHED);
    }

    /**
   *
   */
    private void addChildIfNecessary(ISelection            parentSelection,
                                     ITaskTreeNode         node,
                                     ITaskTreeBuilder      builder,
                                     ITaskTreeNodeFactory  nodeFactory,
                                     RuleApplicationResult result)
    {
        for (int i = 0; i < parentSelection.getChildren().size(); i++) {
            ITaskTreeNode child = parentSelection.getChildren().get(i);

            if (child instanceof IEventTask) {
                // check, if the new node is a variant for the current event task
                NodeEquality nodeEquality = nodeEqualityRuleManager.applyRules(child, node);
                if (nodeEquality.isAtLeast(NodeEquality.SEMANTICALLY_EQUAL)) {
                    // the node is a variant. If it not structurally equal, a new sub-selection for
                    // the existing and the new node must be created. Otherwise, the new node does
                    // not need to be added
                    if (!nodeEquality.isAtLeast(NodeEquality.LEXICALLY_EQUAL)) {
                        ISelection selection = nodeFactory.createNewSelection();
                        result.addNewlyCreatedParentNode(selection);
                        builder.addChild(parentSelection, selection);

                        builder.addChild(selection, child);
                        builder.addChild(selection, node);
                        builder.removeChild(parentSelection, child);
                    }

                    return;
                }
            }
            else if (child instanceof ISelection) {
                // check, if the new node is a variant for the semantically equal children of the
                // current
                // selection
                boolean addNode = true;
                for (int j = 0; j < child.getChildren().size(); j++) {
                    NodeEquality nodeEquality = nodeEqualityRuleManager.applyRules(child, node);
                    if (!nodeEquality.isAtLeast(NodeEquality.SEMANTICALLY_EQUAL)) {
                        // the new node is no semantical equivalent of the nodes in the current
                        // selection - break up
                        addNode = false;
                        break;
                    }
                    else if (nodeEquality.isAtLeast(NodeEquality.LEXICALLY_EQUAL)) {
                        addNode = false;
                        break;
                    }
                }

                if (addNode) {
                    // the node is a semantical equivalent to all the nodes in the existing
                    // sub-selection
                    // but it is not structurally identical to either of them. Therefore add it.
                    builder.addChild((ISelection) child, node);
                    return;
                }
            }
        }

        // if we did not return in the previous checks, then the node must be added
        builder.addChild(parentSelection, node);
    }

}
