//   Copyright 2012 Georg-August-Universität Göttingen, Germany
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

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

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

/**
 * TODO comment
 * 
 * @version $Revision: $ $Date: 28.04.2012$
 * @author 2012, last modified by $Author: patrick$
 */
class TrackBarSelectionDetectionRule implements TemporalRelationshipRule {
    /**
     * <p>
     * the task tree node factory to be used for creating substructures for the temporal
     * relationships identified during rule
     * </p>
     */
    private ITaskTreeNodeFactory taskTreeNodeFactory;
    /**
     * <p>
     * the task tree builder to be used for creating substructures for the temporal relationships
     * identified during rule application
     * </p>
     */
    private ITaskTreeBuilder taskTreeBuilder;

    /**
     * <p>
     * the node equality manager needed for comparing task tree nodes with each other
     * </p>
     */
    private NodeEqualityRuleManager nodeEqualityRuleManager;

    /**
     * <p>
     * instantiates the rule and initializes it with a node equality rule manager and the minimal
     * node equality identified sublist must have to consider them as iterated.
     * </p>
     */
    TrackBarSelectionDetectionRule(NodeEqualityRuleManager nodeEqualityRuleManager,
                                   ITaskTreeNodeFactory    taskTreeNodeFactory,
                                   ITaskTreeBuilder        taskTreeBuilder)
    {
        this.nodeEqualityRuleManager = nodeEqualityRuleManager;
        this.taskTreeNodeFactory = taskTreeNodeFactory;
        this.taskTreeBuilder = taskTreeBuilder;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "TrackBarSelectionDetectionRule";
    }

    /*
     * (non-Javadoc)
     * 
     * @see de.ugoe.cs.tasktree.temporalrelation.TemporalRelationshipRule#apply(TaskTreeNode,
     * boolean)
     */
    @Override
    public RuleApplicationResult apply(ITaskTreeNode parent, boolean finalize) {
        if (!(parent instanceof ISequence)) {
            return null;
        }

        RuleApplicationResult result = new RuleApplicationResult();

        int valueSelectionStartIndex = -1;
        ITrackBar currentTrackBar = null;

        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) &&
                ((currentTrackBar == null) ||
                 (currentTrackBar.equals((((IEventTask) child).getEventTarget())))))
            {
                if (valueSelectionStartIndex < 0) {
                    // let the show begin
                    valueSelectionStartIndex = index;
                    currentTrackBar = (ITrackBar) ((IEventTask) child).getEventTarget();
                }
            }
            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
                    (parent, currentTrackBar, valueSelectionStartIndex, index - 1, result);

                return result;
            }

            index++;
        }

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

        return result;
    }

    /**
     *
     */
    private void handleValueSelections(ITaskTreeNode         parent,
                                       ITrackBar             trackbar,
                                       int                   startIndex,
                                       int                   endIndex,
                                       RuleApplicationResult result)
    {
        IIteration iteration = taskTreeNodeFactory.createNewIteration();
        taskTreeBuilder.setDescription
            (iteration, "value selection on " + trackbar.getStringIdentifier());
        result.addNewlyCreatedParentNode(iteration);

        ISelection selection = taskTreeNodeFactory.createNewSelection();
        result.addNewlyCreatedParentNode(selection);
        taskTreeBuilder.setChild(iteration, selection);

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

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

        result.setRuleApplicationStatus(RuleApplicationStatus.RULE_APPLICATION_FINISHED);
    }

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

            // check, if the new node is a variant for the current event task
            NodeEquality nodeEquality = nodeEqualityRuleManager.applyRules(child, node);
            if (nodeEquality.isAtLeast(NodeEquality.SYNTACTICALLY_EQUAL)) {
                return;
            }
        }

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

}
