/*
 * @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.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Map;
import net.ranides.assira.collection.maps.OrderedMap;
import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.reflection.impl.AArguments;
import net.ranides.assira.reflection.impl.FElements;

/**
 * Fluent interface for collection of IArgument objects
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public interface IArguments extends IElements<IArgument> {

    /**
     * Maps every IArgument into argument.type
     *
     * @return IClasses
     */
    IClasses types();

    @Override
    IExecutables<? extends IExecutable> parent();

    /**
     * Creates map with all arguments, using argument name as a key.
     *
     * Please note, it can throw exception, if any argument does not store information about name.
     *
     * @return map
     */
    Map<String, IArgument> map();

    /**
     * Returns stream which maps every argument into java.lang.reflect.Parameter
     *
     * @return stream
     */
    CQuery<Parameter> reflective();

    /**
     * Factory: returns empty collection
     *
     * @return IArguments
     */
    static IArguments empty() {
        return AArguments.$empty();
    }

    /**
     * Factory: returns arguments for provided method
     * Generates synthetic names like "arg1, arg2, ..." if necessary.
     *
     * @param method method
     * @return arguments
     */
    static IArguments typeinfo(Method method) {
        return IMethod.typeinfo(method).arguments();
    }

    /**
     * Factory: returns arguments for provided constructor
     * Generates synthetic names like "arg1, arg2, ..." if necessary.
     *
     * @param method method
     * @return arguments
     */
    static IArguments typeinfo(Constructor<?> method) {
        return IConstructor.typeinfo(method).arguments();
    }

    /**
     * Factory: creates arguments of specified types.
     *
     * Please note, that information about name is not stored.
     * Synthetic names like "arg1, arg2, ..." are not generated.
     *
     * @param types types
     * @return arguments
     */
    static IArguments typeinfo(IClass<?>... types) {
        return FElements.newArguments(types);
    }

    /**
     * Factory: creates arguments of specified types.
     *
     * Please note, that information about name is not stored.
     * Synthetic names like "arg1, arg2, ..." are not generated.
     *
     * @param types types
     * @return arguments
     */
    static IArguments typeinfo(Class<?>... types) {
        return FElements.newArguments(types);
    }

    /**
     * Factory: creates arguments from provided map.
     * Map keys are used as argument name, map values are used as argument type.
     *
     * Please note that we take OrderedMap, because order of arguments is important
     *
     * @param arguments arguments
     * @return OrderedMap
     */
    static IArguments typeinfo(OrderedMap<String, IClass<?>> arguments) {
        return FElements.newArguments(arguments);
    }
    
}
