/*
 * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.model.api;

import static com.google.common.base.Verify.verifyNotNull;
import static java.util.Objects.requireNonNull;

import com.google.common.annotations.Beta;
import java.util.Map;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeRoot;

/**
 * {@link EffectiveStatement}-based result of YANG parser compilation. Unlike a SchemaContext, which it extends,
 * it gives access to individual {@link ModuleEffectiveStatement}s that comprise it. It also supports resolution of
 * schema node identifiers via {@link #findSchemaTreeNode(SchemaNodeIdentifier)}.
 *
 * @author Robert Varga
 */
@Beta
// FIXME: 8.0.0: evaluate if we still need to extend SchemaContext here
public interface EffectiveModelContext extends SchemaContext, SchemaTreeRoot {

    @NonNull Map<QNameModule, ModuleEffectiveStatement> getModuleStatements();

    default @NonNull Optional<ModuleEffectiveStatement> findModuleStatement(final QNameModule moduleName) {
        return Optional.ofNullable(getModuleStatements().get(requireNonNull(moduleName)));
    }

    default @NonNull Optional<ModuleEffectiveStatement> findModuleStatement(final QName moduleName) {
        return findModuleStatement(moduleName.getModule());
    }

    default @NonNull ModuleEffectiveStatement getModuleStatement(final QNameModule moduleName) {
        return verifyNotNull(getModuleStatements().get(requireNonNull(moduleName)));
    }

    default @NonNull ModuleEffectiveStatement getModuleStatement(final QName moduleName) {
        return getModuleStatement(moduleName.getModule());
    }

    /**
     * {@inheritDoc}
     *
     * @implSpec
     *     Default implementation defers locates the module corresponding to the first element of path and then defers
     *     to {@link ModuleEffectiveStatement#findSchemaTreeNode(SchemaNodeIdentifier)}.
     */
    @Override
    default Optional<SchemaTreeEffectiveStatement<?>> findSchemaTreeNode(final SchemaNodeIdentifier path) {
        return findModuleStatement(path.firstNodeIdentifier().getModule())
            .flatMap(module -> module.findSchemaTreeNode(path));
    }
}

@@ -506,16 +506,92 @@
 s.Beta;%0A
+import com.google.common.collect.Collections2;%0Aimport java.util.Collection;%0A
 import j
@@ -604,16 +604,16 @@
 il.Map;%0A
-
 import j
@@ -786,16 +786,76 @@
 Module;%0A
+import org.opendaylight.yangtools.yang.common.XMLNamespace;%0A
 import o
@@ -2115,32 +2115,32 @@
 e moduleName) %7B%0A
-
         return f
@@ -2182,32 +2182,1202 @@
 dule());%0A    %7D%0A%0A
+    /**%0A     * Returns module instances (from the context) with a concrete name. Returned collection is required to have its%0A     * iteration order guarantee that the latest revision is encountered first.%0A     *%0A     * @param name string with the module name%0A     * @return set of module instances with specified name.%0A     */%0A    default @NonNull Collection%3C@NonNull ModuleEffectiveStatement%3E findModuleStatements(final String name) %7B%0A        return Collections2.transform(findModules(name), Module::asEffectiveStatement);%0A    %7D%0A%0A    /**%0A     * Returns module instance (from the context) with concrete namespace. Returned collection is required to have its%0A     * iteration order guarantee that the latest revision is encountered first.%0A     *%0A     * @param namespace XMLNamespace instance with specified namespace%0A     * @return module instance which has namespace equal to the %7B@code namespace%7D or %7B@code null%7D in other cases%0A     */%0A    default @NonNull Collection%3C@NonNull ModuleEffectiveStatement%3E findModuleStatements(%0A            final XMLNamespace namespace) %7B%0A        return Collections2.transform(findModules(namespace), Module::asEffectiveStatement);%0A    %7D%0A%0A
     default @Non

Add a few more utilities to EffectiveModelContext