/* -*- mode: java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */
/*
 * Copyright 2013 Real Logic Ltd.
 *
 * Licensed 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 uk.co.real_logic.sbe.xml;

import org.w3c.dom.Node;
import uk.co.real_logic.sbe.util.Verify;

import java.nio.ByteOrder;
import java.util.Collection;
import java.util.Map;

import static uk.co.real_logic.sbe.xml.XmlSchemaParser.*;

/**
 * Message schema composite for schema attributes, messageHeader, and reference for multiple {@link Message} objects.
 */
public class MessageSchema
{
    private static final String MESSAGE_HEADER_KEY = "messageHeader";

    private final String packageName;                 // package (optional?)
    private final String description;                 // description (optional)
    private final int id;                             // identifier for the schema (required)
    private final int version;                        // version (optional - default is 0)
    private final String semanticVersion;             // semanticVersion (optional)
    private final ByteOrder byteOrder;                // byteOrder (optional - default is littleEndian)
    private final Map<String, Type> typeByNameMap;
    private final Map<Long, Message> messageByIdMap;

    public MessageSchema(final Node schemaNode,
                         final Map<String, Type> typeByNameMap,
                         final Map<Long, Message> messageByIdMap)
    {
        Verify.present(typeByNameMap, MESSAGE_HEADER_KEY, "Message header");

        this.packageName = getAttributeValue(schemaNode, "package");
        this.description = getAttributeValueOrNull(schemaNode, "description");
        this.id = Integer.parseInt(getAttributeValue(schemaNode, "id"));
        this.version = Integer.parseInt(getAttributeValue(schemaNode, "version", "0"));  // default version is 0
        this.semanticVersion = getAttributeValueOrNull(schemaNode, "semanticVersion");
        this.byteOrder = getByteOrder(getAttributeValue(schemaNode, "byteOrder", "littleEndian"));
        this.typeByNameMap = typeByNameMap;
        this.messageByIdMap = messageByIdMap;

        ((CompositeType)typeByNameMap.get(MESSAGE_HEADER_KEY)).checkForWellFormedMessageHeader(schemaNode);
    }

    /**
     * @return the Schema messageHeader type or null if not defined. This should be a {@link CompositeType}.
     */
    public CompositeType messageHeader()
    {
        return (CompositeType)typeByNameMap.get(MESSAGE_HEADER_KEY);
    }

    /**
     * The package name for the schema.
     *
     * @return he package name for the schema.
     */
    public String packageName()
    {
        return packageName;
    }

    /**
     * The description of the schema.
     *
     * @return the description of the scheam.
     */
    public String description()
    {
        return description;
    }

    /**
     * The id number of the schema.
     *
     * @return the id number of the schema.
     */
    public int id()
    {
        return id;
    }

    /**
     * The version number of the schema.
     *
     * @return the version number of the schema.
     */
    public int version()
    {
        return version;
    }

    /**
     * The semantic version number of the schema. Typically use to reference a third party standard such as FIX.
     *
     * @return the semantic version number of the schema.
     */
    public String semanticVersion()
    {
        return semanticVersion;
    }

    /**
     * Return a given {@link Message} object with the given schemaId.
     *
     * @param schemaId of the message to return.
     * @return a given {@link Message} for the schemaId.
     */
    public Message getMessage(final long schemaId)
    {
        return messageByIdMap.get(Long.valueOf(schemaId));
    }

    /**
     * Get the {@link Collection} of {@link Message}s for this Schema.
     *
     * @return the {@link Collection} of {@link Message}s for this Schema.
     */
    public Collection<Message> messages()
    {
        return messageByIdMap.values();
    }

    /**
     * Return the byte order specified by the messageSchema
     *
     * @return {@link ByteOrder} of the message encoding.
     */
    public ByteOrder byteOrder()
    {
        return byteOrder;
    }
}

@@ -1069,22 +1069,21 @@
 %0A%7B%0A    p
-rivate
+ublic
  static 
@@ -1095,34 +1095,35 @@
  String 
-MESSAGE_HEADER_KEY
+HEADER_TYPE_DEFAULT
  = %22mess
@@ -1665,16 +1665,122 @@
 Endian)%0A
+    private final String headerType;                  // headerType (optional - default to messageHeader)%0A
     priv
@@ -2064,86 +2064,8 @@
   %7B%0A
-        Verify.present(typeByNameMap, MESSAGE_HEADER_KEY, %22Message header%22);%0A%0A
     
@@ -2372,33 +2372,8 @@
 %22));
-  // default version is 0
 %0A   
@@ -2642,24 +2642,265 @@
 geByIdMap;%0A%0A
+        final String headerType = getAttributeValueOrNull(schemaNode, %22headerType%22);%0A        this.headerType = null == headerType ? HEADER_TYPE_DEFAULT : headerType;%0A        Verify.present(typeByNameMap, this.headerType, %22Message header%22);%0A%0A
         ((Co
@@ -2929,34 +2929,31 @@
 Map.get(
-MESSAGE_HEADER_KEY
+this.headerType
 )).check
@@ -3014,25 +3014,17 @@
 %0A     * 
-@return t
+T
 he Schem
@@ -3029,49 +3029,38 @@
 ema 
-messageH
+h
 eader
- t
+T
 ype 
+f
 or 
-null if not defined
+message headers
 . Th
@@ -3097,16 +3097,80 @@
 eType%7D.%0A
+     *%0A     * @return the Schema headerType for message headers%0A
      */%0A
@@ -3268,26 +3268,18 @@
 get(
-MESSAGE_HEADER_KEY
+headerType
 );%0A 
@@ -3562,18 +3562,18 @@
 the sche
-a
 m
+a
 .%0A     *

Fix for #190 - messageSchema.headerType is now used or defaulted to messageHeader if not present.