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

import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskTreeNode;

/**
 * <p>
 * this node comparison rule is capable of comparing selections. If both selections do not have
 * children, they are treated as identical. If they have children, each child of both selections
 * is compared to each child of the respective other selection. The resulting equality is the most
 * concrete one of all these comparisons. I.e. if all children are at least lexically equal, then
 * the selections are lexically equal. If all children are at least syntactically equal, then the
 * selections are syntactically equal. If all children are at least semantically equal, then the
 * selections are semantically equal. If only one of the selections has children, then the
 * selections are unequal.
 * </p>
 * 
 * @version $Revision: $ $Date: 19.02.2012$
 * @author 2012, last modified by $Author: patrick$
 */
public class SelectionComparisonRule implements NodeComparisonRule {

    /** the rule manager for internally comparing task tree nodes */
    private NodeEqualityRuleManager mRuleManager;

    /**
     * <p>
     * simple constructor to provide the rule with the node equality rule manager to be able
     * to perform comparisons of the children of provided task tree nodes
     * </p>
     * 
     * @param ruleManager the rule manager for comparing task tree nodes
     */
    SelectionComparisonRule(NodeEqualityRuleManager ruleManager) {
        super();
        mRuleManager = ruleManager;
    }

    /*
     * (non-Javadoc)
     * 
     * @see de.ugoe.cs.tasktree.nodeequality.NodeEqualityRule#apply(TaskTreeNode, TaskTreeNode)
     */
    @Override
    public NodeEquality compare(ITaskTreeNode node1, ITaskTreeNode node2) {
        if ((!(node1 instanceof ISelection)) || (!(node2 instanceof ISelection))) {
            return null;
        }

        if (node1 == node2) {
            return NodeEquality.IDENTICAL;
        }

        // if both sequences do not have children, they are identical. If only one of them has
        // children, they are unequal.
        if ((node1.getChildren().size() == 0) && (node2.getChildren().size() == 0)) {
            return NodeEquality.LEXICALLY_EQUAL;
        }
        else if ((node1.getChildren().size() == 0) || (node2.getChildren().size() == 0)) {
            return NodeEquality.UNEQUAL;
        }

        NodeEquality selectionEquality = NodeEquality.LEXICALLY_EQUAL;

        // compare each child of selection one with each child of selection two
        NodeEquality childEquality;
        NodeEquality currentEquality;
        for (ITaskTreeNode child1 : node1.getChildren()) {
            childEquality = null;
            for (ITaskTreeNode child2 : node2.getChildren()) {
                currentEquality = mRuleManager.applyRules(child1, child2);
                if ((currentEquality != null) && (currentEquality != NodeEquality.UNEQUAL)) {
                    if (childEquality == null) {
                        childEquality = currentEquality;
                    }
                    else {
                        childEquality = childEquality.getCommonDenominator(currentEquality);
                    }
                }
            }
            
            if (childEquality != null) {
                selectionEquality = selectionEquality.getCommonDenominator(childEquality);
            }
            else {
                return NodeEquality.UNEQUAL;
            }
        }

        // compare each child of selection two with each child of selection one
        for (ITaskTreeNode child2 : node2.getChildren()) {
            childEquality = null;
            for (ITaskTreeNode child1 : node1.getChildren()) {
                currentEquality = mRuleManager.applyRules(child1, child2);
                if ((currentEquality != null) && (currentEquality != NodeEquality.UNEQUAL)) {
                    if (childEquality == null) {
                        childEquality = currentEquality;
                    }
                    else {
                        childEquality = childEquality.getCommonDenominator(currentEquality);
                    }
                }
            }
            
            if (childEquality != null) {
                selectionEquality = selectionEquality.getCommonDenominator(childEquality);
            }
            else {
                return NodeEquality.UNEQUAL;
            }
        }

        return selectionEquality;
    }

}
