/*
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.reflection;

import java.lang.reflect.Type;
import java.util.Map;
import net.ranides.assira.reflection.impl.AContext;

/**
 * Interface with generic type information.
 *
 * Every reflective element has defined context (possibly default one)
 * used for type resolution. Type contexts try to bypass type-erasure
 * and deduce generic parameters.
 *
 * It is especially usefull if we deduced type parameters for enclosing type and then we want to
 * used this deduced information for declared methods and fields.
 *
 * Context is hierarchical because class declarations can be nested.
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public interface IContext {

    /**
     * Returns immutable "default" context which does not store any information at all.
     *
     * @return IContext
     */
    public static IContext getDefault() {
        return AContext.$default();
    }

    /**
     * Creates new derived context with provided "type" inside it.
     * It inherits all type parameters from this context.
     *
     * Idea of creation context for "type" is to inspect type,
     * and if it is generic then try to deduce actual parameters for it.
     * Actual parameters are stored inside context with their names and can be used by "typeinfo"
     * methods.
     *
     * @param type type
     * @return IContext
     */
    IContext derive(Type type);

    /**
     * Returns true if this context (or its parents) is derived from "type"
     *
     * @param type type
     * @return boolean
     */
    boolean derived(Type type);

    /**
     * Takes "type" and returns corresponding type with resolved type parameters.
     * If type parameters can't be resolved, returns raw type.
     *
     * @param type type
     * @param <R> R
     * @return IClass
     */
    <R> IClass<R> typeinfo(Class<R> type);

    /**
     * Takes "type" and returns corresponding type with resolved type parameters.
     * If type parameters can't be resolved, returns raw type.
     *
     * @param type type
     * @return IClass
     */
    IClass<?> typeinfo(Type type);

    /**
     * Takes parameter name and returns corresponding type with resolved type parameters.
     *
     * If type parameter can't be resolved, returns wildcard type, raw type or {@link IClass#OBJECT}.
     * If there is no parameter with specified name, returns {@code null}.
     *
     * @param type type
     * @return IClass
     */
    IClass<?> typeinfo(String type);

    /**
     * Creates IClass for provided object, using this context for parameter resolution.
     *
     * @param object object
     * @param <R> R
     * @return IClass
     */
    <R> IClass<R> typefor(R object);

    /**
     * Takes "types" and returns corresponding types with resolved type parameters.
     * If type parameters can't be resolved, returns raw types.
     *
     * @param types types
     * @return IClasses
     */
    IClasses typesinfo(Type... types);

    /**
     * Creates IClasses for provided objects, using this context for parameter resolution.
     *
     * @param objects objects
     * @return IClass
     */
    IClasses typesfor(Object... objects);

    /**
     * Returns map with parameter names as keys and parameter actual types as value.
     *
     * @return Map
     */
    Map<String,Type> map();
    
}
