// 
// Decompiled by Procyon v0.6.0
// 

package org.bson.codecs.pojo;

import org.bson.codecs.configuration.CodecConfigurationException;
import java.lang.annotation.Annotation;
import org.bson.codecs.pojo.annotations.BsonId;
import java.util.Collection;
import java.util.Arrays;
import java.util.ArrayList;
import java.lang.reflect.Type;
import org.bson.codecs.pojo.annotations.BsonProperty;
import java.util.List;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;

final class CreatorExecutable<T>
{
    private final Class<T> clazz;
    private final Constructor<T> constructor;
    private final Method method;
    private final List<BsonProperty> properties;
    private final Integer idPropertyIndex;
    private final List<Class<?>> parameterTypes;
    private final List<Type> parameterGenericTypes;
    
    CreatorExecutable(final Class<T> clazz, final Constructor<T> constructor) {
        this(clazz, constructor, null);
    }
    
    CreatorExecutable(final Class<T> clazz, final Method method) {
        this(clazz, null, method);
    }
    
    private CreatorExecutable(final Class<T> clazz, final Constructor<T> constructor, final Method method) {
        this.properties = new ArrayList<BsonProperty>();
        this.parameterTypes = new ArrayList<Class<?>>();
        this.parameterGenericTypes = new ArrayList<Type>();
        this.clazz = clazz;
        this.constructor = constructor;
        this.method = method;
        Integer idPropertyIndex = null;
        if (constructor != null || method != null) {
            final Class<?>[] paramTypes = (constructor != null) ? constructor.getParameterTypes() : method.getParameterTypes();
            final Type[] genericParamTypes = (constructor != null) ? constructor.getGenericParameterTypes() : method.getGenericParameterTypes();
            this.parameterTypes.addAll(Arrays.asList(paramTypes));
            this.parameterGenericTypes.addAll(Arrays.asList(genericParamTypes));
            final Annotation[][] parameterAnnotations = (constructor != null) ? constructor.getParameterAnnotations() : method.getParameterAnnotations();
            for (int i = 0; i < parameterAnnotations.length; ++i) {
                final Annotation[] array;
                final Annotation[] parameterAnnotation = array = parameterAnnotations[i];
                for (final Annotation annotation : array) {
                    if (annotation.annotationType().equals(BsonProperty.class)) {
                        this.properties.add((BsonProperty)annotation);
                        break;
                    }
                    if (annotation.annotationType().equals(BsonId.class)) {
                        this.properties.add(null);
                        idPropertyIndex = i;
                        break;
                    }
                }
            }
        }
        this.idPropertyIndex = idPropertyIndex;
    }
    
    Class<T> getType() {
        return this.clazz;
    }
    
    List<BsonProperty> getProperties() {
        return this.properties;
    }
    
    Integer getIdPropertyIndex() {
        return this.idPropertyIndex;
    }
    
    List<Class<?>> getParameterTypes() {
        return this.parameterTypes;
    }
    
    List<Type> getParameterGenericTypes() {
        return this.parameterGenericTypes;
    }
    
    T getInstance() {
        this.checkHasAnExecutable();
        try {
            if (this.constructor != null) {
                return this.constructor.newInstance(new Object[0]);
            }
            return (T)this.method.invoke(this.clazz, new Object[0]);
        }
        catch (final Exception e) {
            throw new CodecConfigurationException(e.getMessage(), e);
        }
    }
    
    T getInstance(final Object[] params) {
        this.checkHasAnExecutable();
        try {
            if (this.constructor != null) {
                return this.constructor.newInstance(params);
            }
            return (T)this.method.invoke(this.clazz, params);
        }
        catch (final Exception e) {
            throw new CodecConfigurationException(e.getMessage(), e);
        }
    }
    
    CodecConfigurationException getError(final Class<?> clazz, final String msg) {
        return getError(clazz, this.constructor != null, msg);
    }
    
    private void checkHasAnExecutable() {
        if (this.constructor == null && this.method == null) {
            throw new CodecConfigurationException(String.format("Cannot find a public constructor for '%s'.", this.clazz.getSimpleName()));
        }
    }
    
    private static CodecConfigurationException getError(final Class<?> clazz, final boolean isConstructor, final String msg) {
        return new CodecConfigurationException(String.format("Invalid @BsonCreator %s in %s. %s", isConstructor ? "constructor" : "method", clazz.getSimpleName(), msg));
    }
}
