/*
 * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.yangtools.yang.data.tree.leafref;

import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;

public final class LeafRefUtils {
    private LeafRefUtils() {
        // Hidden on purpose
    }

    /**
     * Create an absolute leafref path.
     *
     * @param leafRefPath leafRefPath
     * @param contextNodeSchemaPath contextNodeSchemaPath
     * @param module module
     * @return LeafRefPath object
     */
    public static LeafRefPath createAbsoluteLeafRefPath(
            final LeafRefPath leafRefPath, final SchemaPath contextNodeSchemaPath,
            final Module module) {
        if (leafRefPath.isAbsolute()) {
            return leafRefPath;
        }

        final Deque<QNameWithPredicate> absoluteLeafRefTargetPathList = schemaPathToXPathQNames(
                contextNodeSchemaPath, module);
        final Iterator<QNameWithPredicate> leafRefTgtPathFromRootIterator = leafRefPath.getPathFromRoot().iterator();

        while (leafRefTgtPathFromRootIterator.hasNext()) {
            final QNameWithPredicate qname = leafRefTgtPathFromRootIterator.next();
            if (qname.equals(QNameWithPredicate.UP_PARENT)) {
                absoluteLeafRefTargetPathList.removeLast();
            } else {
                absoluteLeafRefTargetPathList.add(qname);
            }
        }

        return LeafRefPath.create(absoluteLeafRefTargetPathList, true);
    }

    private static Deque<QNameWithPredicate> schemaPathToXPathQNames(final SchemaPath nodePath, final Module module) {
        final Deque<QNameWithPredicate> xpath = new LinkedList<>();
        final Iterator<QName> nodePathIterator = nodePath.getPathFromRoot().iterator();

        DataNodeContainer currenDataNodeContainer = module;
        while (nodePathIterator.hasNext()) {
            final QName qname = nodePathIterator.next();
            final DataSchemaNode child = currenDataNodeContainer.dataChildByName(qname);

            if (child instanceof DataNodeContainer) {
                if (!(child instanceof CaseSchemaNode)) {
                    xpath.add(new SimpleQNameWithPredicate(qname));
                }
                currenDataNodeContainer = (DataNodeContainer) child;
            } else if (child instanceof ChoiceSchemaNode) {
                if (nodePathIterator.hasNext()) {
                    currenDataNodeContainer = ((ChoiceSchemaNode) child).findCase(nodePathIterator.next()).orElse(null);
                } else {
                    break;
                }
            } else if (child instanceof LeafSchemaNode || child instanceof LeafListSchemaNode) {
                xpath.add(new SimpleQNameWithPredicate(qname));
                break;
            } else if (child == null) {
                throw new IllegalArgumentException("No child " + qname + " found in node container "
                        + currenDataNodeContainer + " in module " + module.getName());
            } else {
                throw new IllegalStateException("Illegal schema node type in the path: " + child.getClass());
            }
        }

        return xpath;
    }

    public static LeafRefPath schemaPathToLeafRefPath(final SchemaPath nodePath, final Module module) {
        return LeafRefPath.create(schemaPathToXPathQNames(nodePath, module), true);
    }
}

@@ -2880,16 +2880,26 @@
 ontainer
+ container
 ) %7B%0A    
@@ -3084,26 +3084,17 @@
 r = 
-(DataNodeC
+c
 ontainer
 ) ch
@@ -3089,23 +3089,16 @@
 ontainer
-) child
 ;%0A      
@@ -3139,32 +3139,39 @@
 ChoiceSchemaNode
+ choice
 ) %7B%0A            
@@ -3258,34 +3258,14 @@
 r = 
-((C
+c
 hoice
-SchemaNode) child)
 .fin

Use instanceof pattern