//-------------------------------------------------------------------------------------------------
// 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.tasktrees.nodeequality.NodeEquality;
import de.ugoe.cs.quest.tasktrees.nodeequality.NodeEqualityRuleManager;
import de.ugoe.cs.quest.tasktrees.treeifc.InteractionTask;
import de.ugoe.cs.quest.tasktrees.treeifc.Iteration;
import de.ugoe.cs.quest.tasktrees.treeifc.Selection;
import de.ugoe.cs.quest.tasktrees.treeifc.Sequence;
import de.ugoe.cs.quest.tasktrees.treeifc.TaskTreeBuilder;
import de.ugoe.cs.quest.tasktrees.treeifc.TaskTreeNode;
import de.ugoe.cs.quest.tasktrees.treeifc.TaskTreeNodeFactory;
import de.ugoe.cs.tasktree.guimodel.TrackBar;
import de.ugoe.cs.tasktree.userinteraction.ValueSelection;

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

  /** */
  private NodeEqualityRuleManager mNodeEqualityRuleManager;

  //-----------------------------------------------------------------------------------------------
  /**
   * TODO: comment
   *
   */
  //-----------------------------------------------------------------------------------------------
  TrackBarSelectionDetectionRule(NodeEqualityRuleManager nodeEqualityRuleManager)
  {
    super();
    mNodeEqualityRuleManager = nodeEqualityRuleManager;
  }

  //-----------------------------------------------------------------------------------------------
  /* (non-Javadoc)
   * @see TemporalRelationshipRule#apply(TaskTreeNode, TaskTreeBuilder, TaskTreeNodeFactory)
   */
  //-----------------------------------------------------------------------------------------------
  @Override
  public RuleApplicationResult apply(TaskTreeNode        parent,
                                     TaskTreeBuilder     builder,
                                     TaskTreeNodeFactory nodeFactory,
                                     boolean             finalize)
  {
    if (!(parent instanceof Sequence))
    {
      return null;
    }
    
    RuleApplicationResult result = new RuleApplicationResult();
    
    int valueSelectionStartIndex = -1;
    
    int index = 0;
    while (index < parent.getChildren().size())
    {
      TaskTreeNode child = parent.getChildren().get(index);
      
      if ((child instanceof InteractionTask) &&
          (((InteractionTask) child).getGUIElement() instanceof TrackBar) &&
          (((InteractionTask) child).getInteraction() 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,
                                     TaskTreeNode          parent,
                                     TaskTreeBuilder       builder,
                                     TaskTreeNodeFactory   nodeFactory,
                                     RuleApplicationResult result)
  {
    Iteration iteration = nodeFactory.createNewIteration();
    result.addNewlyCreatedParentNode(iteration);
    
    Selection 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((Sequence) parent, startIndex);
    }
    
    builder.addChild((Sequence) parent, startIndex, iteration);
    
    result.setRuleApplicationStatus(RuleApplicationStatus.RULE_APPLICATION_FINISHED);
  }

  //-----------------------------------------------------------------------------------------------
  /**
   *
   */
  //-----------------------------------------------------------------------------------------------
  private void addChildIfNecessary(Selection             parentSelection,
                                   TaskTreeNode          node,
                                   TaskTreeBuilder       builder,
                                   TaskTreeNodeFactory   nodeFactory,
                                   RuleApplicationResult result)
  {
    for (int i = 0; i < parentSelection.getChildren().size(); i++)
    {
      TaskTreeNode child = parentSelection.getChildren().get(i);

      if (child instanceof InteractionTask)
      {
        // check, if the new node is a variant for the current interaction task
        NodeEquality nodeEquality = mNodeEqualityRuleManager.applyRules(child, node);
        if (nodeEquality.getSemanticalEquality())
        {
          // 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.getStructuralEquality())
          {
            Selection 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 Selection)
      {
        // 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 = mNodeEqualityRuleManager.applyRules(child, node);
          if (!nodeEquality.getSemanticalEquality())
          {
            // the new node is no semantical equivalent of the nodes in the current selection -
            // break up
            addNode = false;
            break;
          }
          else if (nodeEquality.getStructuralEquality())
          {
            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((Selection) child, node);
          return;
        }
      }
    }
    
    // if we did not return in the previous checks, then the node must be added
    builder.addChild(parentSelection, node);
  }

}
