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

import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import net.ranides.assira.reflection.*;
import net.ranides.assira.text.StrBuilder;
import net.ranides.assira.collection.query.CQueryBuilder;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class AClass implements IClass {
    
    static final IClass NULL = new AClass(IContext.DEFAULT);
    
    private static final Set<IAttribute> ATTRS = IAttribute.constant(IAttribute.FINAL, IAttribute.NATIVE, IAttribute.PUBLIC);
    
    private static final Object[] EMPTY_ARGS = new Object[0];
    
    private final IContext context;
    
    protected AClass() {
        this(IContext.DEFAULT);
    }
    
    protected AClass(IContext context) {
        this.context = context;
    }
    
    @Override
    public IContext context() {
        return context;
    }
    
    @Override
    public List<IClass> params() {
        return Collections.emptyList();
    }

    @Override
    public IFields fields() {
        return AFields.EMPTY;
    }

    @Override
    public IMethods constructors() {
        return AMethods.EMPTY;
    }

    @Override
    public IMethods methods() {
        return AMethods.EMPTY;
    }

    @Override
    public IClass parent() {
        throw new NoSuchElementException("IClass<NULL> has no parent");
    }

    @Override
    public IClasses parents() {
        return new AClasses(AHints.EMPTY, CQueryBuilder.empty());
    }

    @Override
    public IClasses interfaces() {
        return AClasses.EMPTY;
    }

    @Override
    public IClass outer() {
        throw new NoSuchElementException("IClass<NULL> has no outer class");
    }

    @Override
    public IClasses inner() {
        return AClasses.EMPTY;
    }

    @Override
    public final Object construct() {
        return construct(EMPTY_ARGS);
    }

    @Override
    public final Object construct(Object... arguments) {
        return constructors()
            .require(IAttribute.DECLARED).accepts(arguments).first().call(arguments);
    }

    @Override
    public Type reflective() {
        throw new UnsupportedOperationException("IClass<NULL> is not reflective");
    }

    @Override
    public Class<?> raw() {
       throw new UnsupportedOperationException("IClass<NULL> is not reflective");
    }

    @Override
    public final boolean isSuper(IClass type) {
        return RCompareUtils.isSuper(this, type);
    }

    @Override
    public final boolean isSubclass(IClass type) {
        return RCompareUtils.isSubclass(this, type);
    }

    @Override
    public boolean isPrimitive() {
        return false;
    }

    @Override
    public boolean isInstance(Object value) {
        return true;
    }
    
    @Override
    public final IClasses collect() {
        return new AClasses(AHints.EMPTY, CQueryBuilder.of(this));
    }

    @Override
    public String name() {
        return "$NULL";
    }

    @Override
    public Set<IAttribute> attributes() {
        return ATTRS;
    }

    @Override
    public IAnnotations annotations() {
        return AAnnotations.EMPTY;
    }

    @Override
    public final int compareTo(IClass object) {
        return RCompareUtils.compare(this, object);
    }

    @Override
    public final boolean equals(Object that) {
        return (that instanceof IClass) && RCompareUtils.equals(this, (IClass)that);
    }

    @Override
    public final int hashCode() {
        return RCompareUtils.hashcode(this);
    }
    
    @Override
    public final String toString() {
        List<IClass> params = params();
        if(params.isEmpty()) {
            return name();
        }
        return new StrBuilder().append(name()).open("<",">",", ").append(params).close().toString();
    }
    
}
