//   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 java.util.List;

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

/**
 * This rule applies a node scope rule (working only in the scope of the provided parent node)
 * as a tree scope rule, i.e. it applies the provided wrapped rule recursively on the subtree
 * provided by the parent node. It traverses the nodes in post order.
 * 
 * @author 2013, last modified by $Author: patrick$
 */
class TreeScopeWrapperRule implements TemporalRelationshipRule {

    /**
     * <p>
     * the node scope rule wrapped by this wrapper
     * </p>
     */
    private TemporalRelationshipRule rule;
    
    /**
     * <p>
     * instantiates the wrapper with the rule to be wrapped
     * </p>
     * 
     * @param rule the rule to be wrapped and applied recursively
     */
    TreeScopeWrapperRule(TemporalRelationshipRule rule) {
        if (rule == null) {
            throw new IllegalArgumentException("rule must not be null");
        }
        
        this.rule = rule;
    }
    
    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return this.rule.toString() + " (tree scope)";
    }

    /*
     * (non-Javadoc)
     * 
     * @see de.ugoe.cs.tasktree.temporalrelation.TemporalRelationshipRule#apply(TaskTreeNode,
     * boolean)
     */
    @Override
    public RuleApplicationResult apply(ITaskTreeNode parent, boolean finalize) {
        RuleApplicationResult result = null;
        
        if (parent != null) {
            result = new RuleApplicationResult();
            
            List<ITaskTreeNode> children = parent.getChildren();
            if (children != null) {
                for (ITaskTreeNode child : children) {
                    merge(result, apply(child, finalize));
                }
            }
            
            merge(result, rule.apply(parent, finalize));
        }

        return result;
    }

    /**
     * <p>
     * merges the overall rule application result with an intermediate result
     * </p>
     *
     * @param overallResult the current overall result
     * @param intermediate  the intermediate result to be merged into the overall result
     */
    private void merge(RuleApplicationResult overallResult, RuleApplicationResult intermediate) {
        if (intermediate == null) {
            return;
        }
        
        RuleApplicationStatus overallStatus = overallResult.getRuleApplicationStatus();
        RuleApplicationStatus intermediateStatus = intermediate.getRuleApplicationStatus();
        
        if ((intermediateStatus == RuleApplicationStatus.FINISHED) ||
            ((intermediateStatus == RuleApplicationStatus.FEASIBLE) &&
             (overallStatus == RuleApplicationStatus.NOT_APPLIED)))
        {
            overallResult.setRuleApplicationStatus(intermediateStatus);
        }
        
        for (ITaskTreeNode newlyCreatedNode : intermediate.getNewlyCreatedParentNodes()) {
            overallResult.addNewlyCreatedParentNode(newlyCreatedNode);
        }
    }

}
