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

package org.bson.codecs.pojo;

import java.util.Iterator;
import java.lang.reflect.Modifier;
import org.bson.codecs.configuration.CodecConfigurationException;

final class ConventionSetPrivateFieldImpl implements Convention
{
    @Override
    public void apply(final ClassModelBuilder<?> classModelBuilder) {
        for (final PropertyModelBuilder<?> propertyModelBuilder : classModelBuilder.getPropertyModelBuilders()) {
            if (!(propertyModelBuilder.getPropertyAccessor() instanceof PropertyAccessorImpl)) {
                throw new CodecConfigurationException(String.format("The SET_PRIVATE_FIELDS_CONVENTION is not compatible with propertyModelBuilder instance that have custom implementations of org.bson.codecs.pojo.PropertyAccessor: %s", propertyModelBuilder.getPropertyAccessor().getClass().getName()));
            }
            final PropertyAccessorImpl<?> defaultAccessor = (PropertyAccessorImpl)propertyModelBuilder.getPropertyAccessor();
            final PropertyMetadata<?> propertyMetaData = defaultAccessor.getPropertyMetadata();
            if (propertyMetaData.isDeserializable() || propertyMetaData.getField() == null || !Modifier.isPrivate(propertyMetaData.getField().getModifiers())) {
                continue;
            }
            this.setPropertyAccessor(propertyModelBuilder);
        }
    }
    
    private <T> void setPropertyAccessor(final PropertyModelBuilder<T> propertyModelBuilder) {
        propertyModelBuilder.propertyAccessor(new PrivatePropertyAccessor<T>((PropertyAccessorImpl)propertyModelBuilder.getPropertyAccessor()));
    }
    
    private static final class PrivatePropertyAccessor<T> implements PropertyAccessor<T>
    {
        private final PropertyAccessorImpl<T> wrapped;
        
        private PrivatePropertyAccessor(final PropertyAccessorImpl<T> wrapped) {
            this.wrapped = wrapped;
            try {
                wrapped.getPropertyMetadata().getField().setAccessible(true);
            }
            catch (final Exception e) {
                throw new CodecConfigurationException(String.format("Unable to make private field accessible '%s' in %s", wrapped.getPropertyMetadata().getName(), wrapped.getPropertyMetadata().getDeclaringClassName()), e);
            }
        }
        
        @Override
        public <S> T get(final S instance) {
            return this.wrapped.get(instance);
        }
        
        @Override
        public <S> void set(final S instance, final T value) {
            try {
                this.wrapped.getPropertyMetadata().getField().set(instance, value);
            }
            catch (final Exception e) {
                throw new CodecConfigurationException(String.format("Unable to set value for property '%s' in %s", this.wrapped.getPropertyMetadata().getName(), this.wrapped.getPropertyMetadata().getDeclaringClassName()), e);
            }
        }
    }
}
