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

package com.google.protobuf;

import java.util.Iterator;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class MapFieldBuilder<KeyT, MessageOrBuilderT extends MessageOrBuilder, MessageT extends MessageOrBuilderT, BuilderT extends MessageOrBuilderT> extends MapFieldReflectionAccessor
{
    Map<KeyT, MessageOrBuilderT> builderMap;
    Map<KeyT, MessageT> messageMap;
    List<Message> messageList;
    Converter<KeyT, MessageOrBuilderT, MessageT> converter;
    
    public MapFieldBuilder(final Converter<KeyT, MessageOrBuilderT, MessageT> converter) {
        this.builderMap = new LinkedHashMap<KeyT, MessageOrBuilderT>();
        this.messageMap = null;
        this.messageList = null;
        this.converter = converter;
    }
    
    private List<MapEntry<KeyT, MessageT>> getMapEntryList() {
        final ArrayList<MapEntry<KeyT, MessageT>> list = new ArrayList<MapEntry<KeyT, MessageT>>(this.messageList.size());
        final Class<?> valueClass = this.converter.defaultEntry().getValue().getClass();
        for (final Message entry : this.messageList) {
            final MapEntry<KeyT, ?> typedEntry = (MapEntry<KeyT, ?>)entry;
            if (valueClass.isInstance(typedEntry.getValue())) {
                list.add((MapEntry<KeyT, MessageT>)typedEntry);
            }
            else {
                list.add(this.converter.defaultEntry().toBuilder().mergeFrom(entry).build());
            }
        }
        return list;
    }
    
    public Map<KeyT, MessageOrBuilderT> ensureBuilderMap() {
        if (this.builderMap != null) {
            return this.builderMap;
        }
        if (this.messageMap != null) {
            this.builderMap = new LinkedHashMap<KeyT, MessageOrBuilderT>(this.messageMap.size());
            for (final Map.Entry<KeyT, MessageT> entry : this.messageMap.entrySet()) {
                this.builderMap.put(entry.getKey(), entry.getValue());
            }
            this.messageMap = null;
            return this.builderMap;
        }
        this.builderMap = new LinkedHashMap<KeyT, MessageOrBuilderT>(this.messageList.size());
        for (final MapEntry<KeyT, MessageT> entry2 : this.getMapEntryList()) {
            this.builderMap.put(entry2.getKey(), entry2.getValue());
        }
        this.messageList = null;
        return this.builderMap;
    }
    
    public List<Message> ensureMessageList() {
        if (this.messageList != null) {
            return this.messageList;
        }
        if (this.builderMap != null) {
            this.messageList = new ArrayList<Message>(this.builderMap.size());
            for (final Map.Entry<KeyT, MessageOrBuilderT> entry : this.builderMap.entrySet()) {
                this.messageList.add(this.converter.defaultEntry().toBuilder().setKey(entry.getKey()).setValue(this.converter.build(entry.getValue())).build());
            }
            this.builderMap = null;
            return this.messageList;
        }
        this.messageList = new ArrayList<Message>(this.messageMap.size());
        for (final Map.Entry<KeyT, MessageT> entry2 : this.messageMap.entrySet()) {
            this.messageList.add(this.converter.defaultEntry().toBuilder().setKey(entry2.getKey()).setValue(entry2.getValue()).build());
        }
        this.messageMap = null;
        return this.messageList;
    }
    
    public Map<KeyT, MessageT> ensureMessageMap() {
        this.messageMap = this.populateMutableMap();
        this.builderMap = null;
        this.messageList = null;
        return this.messageMap;
    }
    
    public Map<KeyT, MessageT> getImmutableMap() {
        return new MapField.MutabilityAwareMap<KeyT, MessageT>(MutabilityOracle.IMMUTABLE, this.populateMutableMap());
    }
    
    private Map<KeyT, MessageT> populateMutableMap() {
        if (this.messageMap != null) {
            return this.messageMap;
        }
        if (this.builderMap != null) {
            final Map<KeyT, MessageT> toReturn = new LinkedHashMap<KeyT, MessageT>(this.builderMap.size());
            for (final Map.Entry<KeyT, MessageOrBuilderT> entry : this.builderMap.entrySet()) {
                toReturn.put(entry.getKey(), this.converter.build(entry.getValue()));
            }
            return toReturn;
        }
        final Map<KeyT, MessageT> toReturn = new LinkedHashMap<KeyT, MessageT>(this.messageList.size());
        for (final MapEntry<KeyT, MessageT> entry2 : this.getMapEntryList()) {
            toReturn.put(entry2.getKey(), entry2.getValue());
        }
        return toReturn;
    }
    
    public void mergeFrom(final MapField<KeyT, MessageT> other) {
        this.ensureBuilderMap().putAll(MapFieldLite.copy((Map<? extends KeyT, ? extends MessageOrBuilderT>)other.getMap()));
    }
    
    public void clear() {
        this.builderMap = new LinkedHashMap<KeyT, MessageOrBuilderT>();
        this.messageMap = null;
        this.messageList = null;
    }
    
    private boolean typedEquals(final MapFieldBuilder<KeyT, MessageOrBuilderT, MessageT, BuilderT> other) {
        return MapFieldLite.equals(this.ensureBuilderMap(), other.ensureBuilderMap());
    }
    
    @Override
    public boolean equals(final Object object) {
        return object instanceof MapFieldBuilder && this.typedEquals((MapFieldBuilder)object);
    }
    
    @Override
    public int hashCode() {
        return MapFieldLite.calculateHashCodeForMap(this.ensureBuilderMap());
    }
    
    public MapFieldBuilder<KeyT, MessageOrBuilderT, MessageT, BuilderT> copy() {
        final MapFieldBuilder<KeyT, MessageOrBuilderT, MessageT, BuilderT> clone = new MapFieldBuilder<KeyT, MessageOrBuilderT, MessageT, BuilderT>(this.converter);
        clone.ensureBuilderMap().putAll(this.ensureBuilderMap());
        return clone;
    }
    
    public MapField<KeyT, MessageT> build(final MapEntry<KeyT, MessageT> defaultEntry) {
        final MapField<KeyT, MessageT> mapField = MapField.newMapField(defaultEntry);
        final Map<KeyT, MessageT> map = mapField.getMutableMap();
        for (final Map.Entry<KeyT, MessageOrBuilderT> entry : this.ensureBuilderMap().entrySet()) {
            map.put(entry.getKey(), this.converter.build(entry.getValue()));
        }
        mapField.makeImmutable();
        return mapField;
    }
    
    @Override
    List<Message> getList() {
        return this.ensureMessageList();
    }
    
    @Override
    List<Message> getMutableList() {
        return this.ensureMessageList();
    }
    
    @Override
    Message getMapEntryMessageDefaultInstance() {
        return this.converter.defaultEntry();
    }
    
    public interface Converter<KeyT, MessageOrBuilderT extends MessageOrBuilder, MessageT extends MessageOrBuilderT>
    {
        MessageT build(final MessageOrBuilderT val);
        
        MapEntry<KeyT, MessageT> defaultEntry();
    }
}
