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

import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.reflection.*;

import java.io.Serializable;
import java.lang.reflect.Parameter;

/**
 * Implementation of IArgument for reflective data resolution.
 *
 * It stores "java.lang.reflect.Parameter"
 *
 * Stores additional informations (declaring method, index, context).
 * Those informations are used to resolve generic types or generate synthetic name.
 *
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public class RArgument extends AElement implements IArgument, Serializable {

    private static final long serialVersionUID = 1L;

    private final IContext context;
    
    private final AExecutable parent;
    
    private final Parameter param;
    
    private final int index;

    RArgument(IContext context, AExecutable parent, Parameter param, int index) {
        this.parent = parent;
        this.param = param;
        this.context = context;
        this.index = index;
    }

    @Override
    public IContext context() {
        return context;
    }

    @Override
    public IArguments collect() {
        return FElements.newArguments(IHints.none(), CQuery.from().value(this));
    }

    @Override
    public Parameter reflective() {
        return param;
    }

    @Override
    public IClass<?> type() {
        final IContext c = context();
        return FClass.newArgumentClass(parent(), c, param.getParameterizedType(), param.getAnnotatedType());
    }

    @Override
    public String name() {
        if(!param.isNamePresent()) {
            String[] names = parent.$debugParams();
            if(null == names || null == names[index]) {
                return "arg"+index;
            }
            return names[index];
        }
        return param.getName();
    }

    @Override
    public IExecutable parent() {
        return parent;
    }

    @Override
    public IAttributes attributes() {
        return IAttributes.of(param);
    }

    @Override
    public IAnnotations annotations() {
        return FElements.newAnnotations(IHints.none(), CQuery.from().array(param.getAnnotations()));
    }

    @Override
    public final boolean equals(Object object) {
        return (object instanceof IArgument) && ((IArgument)object).type().equals(type());
    }
    
    @Override
    public final int hashCode() {
        return this.type().hashCode();
    }

    @Override
    public String toString() {
        return type() + " " + name();
    }
    
}
