/*
 * @author Ranides Atterwim <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.Arrays;
import java.util.List;
import java.util.Optional;

import net.ranides.assira.reflection.impl.AClass;
import net.ranides.assira.reflection.impl.FClass;
import net.ranides.assira.reflection.util.ClassUtils;

/**
 * 
 * @author Ranides Atterwim <ranides@gmail.com>
 */
@SuppressWarnings("PMD.TooManyDifferentMethods")
public interface IClass<T> extends IElement, Comparable<IClass<?>> {
    
    IClass<?> NULL = new AClass(IContext.DEFAULT){};
    
    IClass<?> OBJECT = typeinfo(Object.class);
    
    /**
     * Collect information using java.reflection API
     * @param type
     * @return 
     */
    static IClass<?> typeinfo(Type type) {
        return IContext.DEFAULT.typeinfo(type);
    }
    
    static <R> IClass<R> typeinfo(Class<R> type) {
        return IContext.DEFAULT.typeinfo(type);
    }
    
    static IClass<?> typeinfo(String type) {
        try {
            return IContext.DEFAULT.typeinfo(ClassUtils.forName(type));
        } catch (ClassNotFoundException cause) {
            throw new IllegalArgumentException("Unknown class name: " + type, cause);
        }
    }
    
    static IClass<?> typefor(Object object) {
        return IContext.DEFAULT.typefor(object);
    }
    
    static <R> IClass<R> generic(Class<R> type, IClass<?>... params) {
        return FClass.newClass(type, params);
    }
    
    static <R> IClass<R> generic(Class<R> type, Class<?>... params) {
        return FClass.newClass(type, Arrays.stream(params).map(IClass::typeinfo).toArray(IClass<?>[]::new));
    }
    
    @Override
    IClasses collect();
    
    List<IClass<?>> params();
    
    IFields fields();

    Optional<IField> field(String name);
    
    IMethods constructors();
    
    IMethods methods();

    Optional<IMethod> method(String name);
    
    /**
     * only parent class
     * @return 
     */
    @Override
    IClass<?> parent();
    
    /**
     * 
     * @return only parent classes
     */
    IClasses parents();
    
    IClasses interfaces();
    
    IClass<?> outer();
    
    IClasses inner();
    
    Class<?> raw();
    
    String shortname();
    
    IClass<?> component();
    
    Type reflective();
    
    T construct();
    
    T construct(Object... arguments);
	
	/**
	 * Checks if {@code this} is superclass of {@code type} (or equals)
	 * @param type
	 * @return 
	 */
	boolean isSuper(IClass<?> type);
	
	/**
	 * Checks if {@code this} is a subclass of {@code type} (or equals)
	 * @param type
	 * @return 
	 */
	boolean isSubclass(IClass<?> type);
	
    boolean isEquivalent(IClass<?> type);
    
    boolean isInstance(Object value);
    
    T cast(Object value);

}
