/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.qpid.proton4j.codec.decoders.primitives;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.qpid.proton4j.buffer.ProtonBuffer;
import org.apache.qpid.proton4j.codec.DecoderState;
import org.apache.qpid.proton4j.codec.EncodingCodes;
import org.apache.qpid.proton4j.codec.PrimitiveTypeDecoder;
import org.apache.qpid.proton4j.codec.TypeDecoder;

/**
 * Base for the various Map type decoders used to read AMQP Map values.
 */
public abstract class AbstractMapTypeDecoder implements MapTypeDecoder {

    @Override
    public Map<Object, Object> readValue(ProtonBuffer buffer, DecoderState state) throws IOException {
        int size = readSize(buffer);
        int count = readCount(buffer);

        if (count > buffer.getReadableBytes()) {
            throw new IllegalArgumentException(String.format(
                    "Map encoded size %d is specified to be greater than the amount " +
                    "of data available (%d)", size, buffer.getReadableBytes()));
        }

        TypeDecoder<?> keyDecoder = null;
        TypeDecoder<?> valueDecoder = null;

        // Count include both key and value so we must include that in the loop
        Map<Object, Object> map = new LinkedHashMap<>(count);
        for (int i = 0; i < count / 2; i++) {
            keyDecoder = findNextDecoder(buffer, state, keyDecoder);
            Object key = keyDecoder.readValue(buffer, state);

            valueDecoder = findNextDecoder(buffer, state, valueDecoder);
            Object value = valueDecoder.readValue(buffer, state);

            map.put(key, value);
        }

        return map;
    }

    private TypeDecoder<?> findNextDecoder(ProtonBuffer buffer, DecoderState state, TypeDecoder<?> prevoudDecoder) throws IOException {
        if (prevoudDecoder == null) {
            return state.getDecoder().readNextTypeDecoder(buffer, state);
        } else {
            buffer.markReadIndex();

            byte encodingCode = buffer.readByte();
            if (encodingCode == EncodingCodes.DESCRIBED_TYPE_INDICATOR || !(prevoudDecoder instanceof PrimitiveTypeDecoder<?>)) {
                buffer.resetReadIndex();
                return state.getDecoder().readNextTypeDecoder(buffer, state);
            } else {
                PrimitiveTypeDecoder<?> primitiveTypeDecoder = (PrimitiveTypeDecoder<?>) prevoudDecoder;
                if (encodingCode != primitiveTypeDecoder.getTypeCode()) {
                    buffer.resetReadIndex();
                    return state.getDecoder().readNextTypeDecoder(buffer, state);
                }
            }
        }

        return prevoudDecoder;
    }

    @Override
    public void skipValue(ProtonBuffer buffer, DecoderState state) throws IOException {
        buffer.skipBytes(readSize(buffer));
    }
}

@@ -1048,172 +1048,8 @@
 ate;
-%0Aimport org.apache.qpid.proton4j.codec.EncodingCodes;%0Aimport org.apache.qpid.proton4j.codec.PrimitiveTypeDecoder;%0Aimport org.apache.qpid.proton4j.codec.TypeDecoder;
 %0A%0A/*
@@ -1689,95 +1689,8 @@
  %7D%0A%0A
-        TypeDecoder%3C?%3E keyDecoder = null;%0A        TypeDecoder%3C?%3E valueDecoder = null;%0A%0A
     
@@ -1889,250 +1889,50 @@
     
-keyDecoder = findNextDecoder(buffer, state, keyDecoder);%0A            Object key = keyDecoder.readValue(buffer, state);%0A%0A            valueDecoder = findNextDecoder(buffer, state, valueDecoder);%0A            Object value = valueDecoder.readValue
+Object key = state.getDecoder().readObject
 (buf
@@ -1944,17 +1944,16 @@
 state);%0A
-%0A
         
@@ -1960,1027 +1960,102 @@
     
-map.put(key, value);%0A        %7D%0A%0A        return map;%0A    %7D%0A%0A    private TypeDecoder%3C?%3E findNextDecoder(ProtonBuffer buffer, DecoderState state, TypeDecoder%3C?%3E prevoudDecoder) throws IOException %7B%0A        if (prevoudDecoder == null) %7B%0A            return state.getDecoder().readNextTypeDecoder(buffer, state);%0A        %7D else %7B%0A            buffer.markReadIndex();%0A%0A            byte encodingCode = buffer.readByte();%0A            if (encodingCode == EncodingCodes.DESCRIBED_TYPE_INDICATOR %7C%7C !(prevoudDecoder instanceof PrimitiveTypeDecoder%3C?%3E)) %7B%0A                buffer.resetReadIndex();%0A                return state.getDecoder().readNextTypeDecoder(buffer, state);%0A            %7D else %7B%0A                PrimitiveTypeDecoder%3C?%3E primitiveTypeDecoder = (PrimitiveTypeDecoder%3C?%3E) prevoudDecoder;%0A                if (encodingCode != primitiveTypeDecoder.getTypeCode()) %7B%0A                    buffer.resetReadIndex();%0A                    return state.getDecoder().readNextTypeDecoder(buffer, state);%0A                %7D%0A            %7D
+Object value = state.getDecoder().readObject(buffer, state);%0A%0A            map.put(key, value);
 %0A   
@@ -2081,22 +2081,11 @@
 urn 
-prevoudDecoder
+map
 ;%0A  

Simplify the MapTypeDecoder