/**
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 */

package net.sourceforge.pmd.lang.symboltable;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * A scope is a region within variables and other declarations are visible.
 * Scopes can be nested and form a tree. This is expressed through "parent
 * scopes". Each scope manages its own declarations.
 *
 * @see AbstractScope AbstractScope as a base class
 * @see <a href=
 *      "http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.3">Java
 *      Language Specification, 6.3: Scope of a Declaration</a>
 */
public interface Scope {
    /**
     * Retrieves this scope's parent
     */
    Scope getParent();

    /**
     * Points this scope to its parent
     */
    void setParent(Scope parent);

    /**
     * Helper method that goes up the parent scopes to find a scope of the
     * specified type
     *
     * @param clazz
     *            the type of the Scope to search for
     * @return the found scope of the specified type or <code>null</code> if no
     *         such scope was found.
     */
    <T extends Scope> T getEnclosingScope(Class<T> clazz);

    /**
     * Gets all the declaration with the occurrences in this scope.
     *
     * @return map of declarations with occurrences.
     */
    Map<NameDeclaration, List<NameOccurrence>> getDeclarations();

    /**
     * Helper method to get only a specific type of name declarations. The
     * return map elemens have already been casted to the correct type. This
     * method usually returns a subset of {@link #getDeclarations()}.
     *
     * @param clazz
     *            the type of name declarations to use
     * @return map of declarations with occurrences.
     */
    <T extends NameDeclaration> Map<T, List<NameOccurrence>> getDeclarations(Class<T> clazz);

    /**
     * Tests whether or not a {@link NameOccurrence} is directly contained in
     * the scope. This means, whether the given {@link NameOccurrence}
     * references a declaration, that has been declared within this scope. Note
     * that this search is just for this scope - it doesn't go diving into any
     * parent scopes.
     */
    boolean contains(NameOccurrence occ);

    /**
     * Adds a new declaration to this scope. Only after the declaration has been
     * added, {@link #contains(NameOccurrence)} and
     * {@link #addNameOccurrence(NameOccurrence)} can be used correctly.
     *
     * @param declaration
     *            the declaration to add
     */
    void addDeclaration(NameDeclaration declaration);

    /**
     * Adds a {@link NameOccurrence} to this scope - only call this after
     * getting a true back from {@link #contains(NameOccurrence)}.
     *
     * @return the {@link NameDeclaration}s that are referenced by the given
     *         {@link NameOccurrence}, if the {@link NameOccurrence} could be
     *         added. Otherwise an empty set is returned.
     */
    Set<NameDeclaration> addNameOccurrence(NameOccurrence occurrence);
}
