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

package org.bson.codecs.pojo;

import java.lang.reflect.Modifier;
import org.bson.codecs.configuration.CodecConfigurationException;
import java.util.Collection;
import java.util.ArrayList;
import java.util.HashMap;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.util.List;
import java.lang.annotation.Annotation;
import java.util.Map;

final class PropertyMetadata<T>
{
    private final String name;
    private final String declaringClassName;
    private final TypeData<T> typeData;
    private final Map<Class<? extends Annotation>, Annotation> readAnnotations;
    private final Map<Class<? extends Annotation>, Annotation> writeAnnotations;
    private TypeParameterMap typeParameterMap;
    private List<TypeData<?>> typeParameters;
    private String error;
    private Field field;
    private Method getter;
    private Method setter;
    
    PropertyMetadata(final String name, final String declaringClassName, final TypeData<T> typeData) {
        this.readAnnotations = new HashMap<Class<? extends Annotation>, Annotation>();
        this.writeAnnotations = new HashMap<Class<? extends Annotation>, Annotation>();
        this.name = name;
        this.declaringClassName = declaringClassName;
        this.typeData = typeData;
    }
    
    public String getName() {
        return this.name;
    }
    
    public List<Annotation> getReadAnnotations() {
        return new ArrayList<Annotation>(this.readAnnotations.values());
    }
    
    public PropertyMetadata<T> addReadAnnotation(final Annotation annotation) {
        if (!this.readAnnotations.containsKey(annotation.annotationType())) {
            this.readAnnotations.put(annotation.annotationType(), annotation);
            return this;
        }
        if (annotation.equals(this.readAnnotations.get(annotation.annotationType()))) {
            return this;
        }
        throw new CodecConfigurationException(String.format("Read annotation %s for '%s' already exists in %s", annotation.annotationType(), this.name, this.declaringClassName));
    }
    
    public List<Annotation> getWriteAnnotations() {
        return new ArrayList<Annotation>(this.writeAnnotations.values());
    }
    
    public PropertyMetadata<T> addWriteAnnotation(final Annotation annotation) {
        if (!this.writeAnnotations.containsKey(annotation.annotationType())) {
            this.writeAnnotations.put(annotation.annotationType(), annotation);
            return this;
        }
        if (annotation.equals(this.writeAnnotations.get(annotation.annotationType()))) {
            return this;
        }
        throw new CodecConfigurationException(String.format("Write annotation %s for '%s' already exists in %s", annotation.annotationType(), this.name, this.declaringClassName));
    }
    
    public Field getField() {
        return this.field;
    }
    
    public PropertyMetadata<T> field(final Field field) {
        this.field = field;
        return this;
    }
    
    public Method getGetter() {
        return this.getter;
    }
    
    public void setGetter(final Method getter) {
        this.getter = getter;
    }
    
    public Method getSetter() {
        return this.setter;
    }
    
    public void setSetter(final Method setter) {
        this.setter = setter;
    }
    
    public String getDeclaringClassName() {
        return this.declaringClassName;
    }
    
    public TypeData<T> getTypeData() {
        return this.typeData;
    }
    
    public TypeParameterMap getTypeParameterMap() {
        return this.typeParameterMap;
    }
    
    public List<TypeData<?>> getTypeParameters() {
        return this.typeParameters;
    }
    
    public <S> PropertyMetadata<T> typeParameterInfo(final TypeParameterMap typeParameterMap, final TypeData<S> parentTypeData) {
        if (typeParameterMap != null && parentTypeData != null) {
            this.typeParameterMap = typeParameterMap;
            this.typeParameters = parentTypeData.getTypeParameters();
        }
        return this;
    }
    
    String getError() {
        return this.error;
    }
    
    void setError(final String error) {
        this.error = error;
    }
    
    public boolean isSerializable() {
        if (this.getter != null) {
            return this.field == null || this.notStaticOrTransient(this.field.getModifiers());
        }
        return this.field != null && this.isPublicAndNotStaticOrTransient(this.field.getModifiers());
    }
    
    public boolean isDeserializable() {
        if (this.setter != null) {
            return this.field == null || (!Modifier.isFinal(this.field.getModifiers()) && this.notStaticOrTransient(this.field.getModifiers()));
        }
        return this.field != null && !Modifier.isFinal(this.field.getModifiers()) && this.isPublicAndNotStaticOrTransient(this.field.getModifiers());
    }
    
    private boolean notStaticOrTransient(final int modifiers) {
        return !Modifier.isTransient(modifiers) && !Modifier.isStatic(modifiers);
    }
    
    private boolean isPublicAndNotStaticOrTransient(final int modifiers) {
        return Modifier.isPublic(modifiers) && this.notStaticOrTransient(modifiers);
    }
    
    @Override
    public String toString() {
        return "PropertyMetadata{name='" + this.name + '\'' + ", declaringClassName='" + this.declaringClassName + '\'' + ", typeData=" + this.typeData + ", readAnnotations=" + this.readAnnotations + ", writeAnnotations=" + this.writeAnnotations + ", typeParameterMap=" + this.typeParameterMap + ", typeParameters=" + this.typeParameters + ", error='" + this.error + '\'' + ", field=" + this.field + ", getter=" + this.getter + ", setter=" + this.setter + '}';
    }
}
