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

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import net.ranides.assira.reflection.GenericClass;
import net.ranides.assira.reflection.inspect.ClassInspector;
import net.ranides.assira.text.LexicalCast;
import net.ranides.assira.text.StrBuilder;
import net.ranides.assira.text.StringUtils;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public final class ReflectFormat {
    
    private ReflectFormat() {
        // utility class
    }
    
    public static String signature(Method method, Object... params) {
        StrBuilder builder = new StrBuilder();
        signature4method(builder, method);
        builder.append(" @ ");
        signature4class(builder, ClassInspector.forObjects(params));
        return builder.toString();
    }
    
    public static String signature(Method method) {
        return signature4method(new StrBuilder(), method).toString();
    }
    
    public static String signature(Constructor<?> ctor) {
        return signature4ctor(new StrBuilder(), ctor).toString();
    }
    
    public static String signature(Class<?>[] params) {
        return signature4class(new StrBuilder(), params).toString();
    }
    
    public static String signature(GenericClass clazz) {
        if (clazz.isParametrised()) {
            return clazz.name() + "<" + StringUtils.join(LexicalCast.asList(clazz.params()), ", ") + ">";
        } else {
            return clazz.name();
        }
    }
    
    /**
     * [F]ull [Q]ualified [S]ignature
     * @param clazz
     * @return 
     */
    public static String fqs(GenericClass clazz) {
        if (!clazz.isParametrised()) {
            return fqname(clazz);
        }
        StrBuilder builder = new StrBuilder();
        builder
            .append(fqname(clazz))
            .append("<")
            .list(", ");
        for(GenericClass param : clazz.params()) {
            builder.item().append(fqname(param));
        }
        return builder.append(">").toString();
    }
    
    private static String fqname(GenericClass clazz) {
        if(!clazz.isResolved()) {
            return clazz.name();
        }
        if(clazz.rawType().isArray()) {
            return clazz.rawType().getComponentType().getName()+"[]";
        }
        return clazz.rawType().getName();
    }
    
    private static StrBuilder signature4method(StrBuilder builder, Method method) {
        Class<?> clazz = method.getDeclaringClass();
        builder
            .append(clazz.getName())
            .append('.')
            .append(method.getName());
        return signature4class(builder, method.getParameterTypes());
    }
    
    private static StrBuilder signature4ctor(StrBuilder builder, Constructor<?> method) {
        Class<?> clazz = method.getDeclaringClass();
        builder
            .append(clazz.getName());
        return signature4class(builder, method.getParameterTypes());
    }
    
    private static StrBuilder signature4class(StrBuilder builder, Class<?>[] params) {
        builder.append('(').list(", ");
        for (Class clazz : params) {
            builder.item().append(clazz.getName());
        }
        return builder.append(')');
    }
}
