<?xml version='1.0'?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org"> 

<!-- this class contains the templates for generating C++ source code for a given framing model -->

<xsl:import href="utils.xsl"/>
<xsl:output method="text" indent="yes" name="textFormat"/> 

<xsl:template match="/"> 
    <xsl:apply-templates mode="generate-multi" select="frames"/>
    <xsl:apply-templates mode="method-list-header" select="frames"/>
    <xsl:apply-templates mode="method-list-source" select="frames"/>
    <xsl:apply-templates mode="method-interface" select="frames"/>
</xsl:template>

<!-- processes all frames outputting the classes in a single stream -->
<xsl:template match="frames" mode="generate-single"> 
    <xsl:result-document href="amqp_methods.h" format="textFormat">
#include "qpid/framing/amqp_framing.h"
        <xsl:for-each select="frame">      
           <xsl:call-template name="generate-class">
                <xsl:with-param name="f" select="."/>
            </xsl:call-template>
        </xsl:for-each>      
    </xsl:result-document>
</xsl:template>

<!-- generates seperate file for each class/frame -->
<xsl:template match="frame" mode="generate-multi"> 
    <xsl:variable name="uri" select="concat(@name, '.h')"/> 
    <xsl:result-document href="{$uri}" format="textFormat"> 
#include "qpid/framing/amqp_types.h"
#include "AMQP_ServerOperations.h"
#include "qpid/framing/AMQMethodBody.h"
#include "qpid/framing/Buffer.h"
#include "qpid/framing/FieldTable.h"

#ifndef _<xsl:value-of select="@name"/>_
#define _<xsl:value-of select="@name"/>_

namespace qpid {
namespace framing {

    <xsl:call-template name="generate-class">
        <xsl:with-param name="f" select="."/>
    </xsl:call-template>
}
}

#endif

</xsl:result-document> 
</xsl:template> 


<!-- main class generation template -->
<xsl:template name="generate-class"> 
    <xsl:param name="f"/>
/**
 * This class is autogenerated, do not modify. [From <xsl:value-of select="$f/parent::frames/@protocol"/>]
 */
class <xsl:value-of select="$f/@name"/> : virtual public AMQMethodBody
{ 
    <xsl:for-each select="$f/field"> 
        <xsl:value-of select="@cpp-type"/>
        <xsl:text> </xsl:text>
        <xsl:value-of select="@name"/>;    
    </xsl:for-each> 

public:
    typedef boost::shared_ptr&lt;<xsl:value-of select="$f/@name"/>&gt; shared_ptr;   

    virtual ~<xsl:value-of select="$f/@name"/>() {}

    <xsl:for-each select="$f/field"> 
        inline <xsl:value-of select="concat(@cpp-arg-type, ' get', amqp:upper-first(@name), '() { return ', @name)"/>; }    
    </xsl:for-each> 
 

    inline void print(std::ostream&amp; out) const{
	out &lt;&lt; "<xsl:value-of select="$f/@declaration_name"/>"
        <xsl:for-each select="$f/field"> 
	    <xsl:text> &lt;&lt; ", </xsl:text>
            <xsl:value-of select="@name"/>="&lt;&lt;
            <xsl:value-of select="@name"/>    
        </xsl:for-each> 
        ;
    }

    inline u_int16_t amqpClassId() const {
        return <xsl:value-of select="$f/@class-id"/>;
    }
   
    inline u_int16_t amqpMethodId() const {
        return <xsl:value-of select="$f/@method-id"/>;
    }

    inline u_int32_t bodySize() const {
        <xsl:choose> 
        <xsl:when test="$f/field">
        return
        <xsl:for-each select="$f/field">
            <xsl:if test="position() != 1">+
            </xsl:if>
            <xsl:value-of select="amqp:field-length(.)"/>
        </xsl:for-each>		 
        ;
        </xsl:when>
        <xsl:otherwise>return 0;</xsl:otherwise>
        </xsl:choose> 
    }

    <xsl:if test="@server='true'">
    inline void invoke(AMQP_ServerOperations&amp; target, u_int16_t channel) {
	<xsl:if test="field">
            <xsl:value-of select="concat('target.get', amqp:upper-first(parent::class/@name), 'Handler()->', @invocation_name, '(channel, ')"/>
            <xsl:value-of select="$f/field/@name" separator=", "/>);
	</xsl:if>
	<xsl:if test="not(field)">
            <xsl:value-of select="concat('target.get', amqp:upper-first(parent::class/@name), 'Handler()->', @invocation_name, '(channel)')"/>;
	</xsl:if>
    }
    </xsl:if>

    inline void encodeContent(Buffer&amp; <xsl:if test="$f/field">buffer</xsl:if>) const
    {
        <xsl:if test="$f/field[@type='bit']">        
	    u_int8_t flags = 0;
            <xsl:for-each select="$f/field[@type='bit']">
                <xsl:value-of select="concat('flags |= ', @name,' &lt;&lt; (', @boolean-index, ' - 1)')"/>; 
            </xsl:for-each>
        </xsl:if>
        <xsl:for-each select="$f/field">
            <xsl:if test="@type != 'bit'">
                <xsl:value-of select="amqp:encoder(.)"/>;
            </xsl:if>
            <xsl:if test="@type = 'bit' and @boolean-index = 1">
                <xsl:text>buffer.putOctet(flags)</xsl:text>;
            </xsl:if>
        </xsl:for-each>		 
    }

    inline void decodeContent(Buffer&amp; <xsl:if test="$f/field">buffer</xsl:if>)
    {
        <xsl:for-each select="$f/field">
            <xsl:choose>
		<xsl:when test="@type = 'bit' and @boolean-index = 1">
		    <xsl:text>u_int8_t flags = buffer.getOctet()</xsl:text>;
		    <xsl:value-of select="amqp:decoder(.)"/>;
		</xsl:when>
		<xsl:otherwise>
		    <xsl:value-of select="amqp:decoder(.)"/>;
		</xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>		 
    }

    <xsl:if test="$f/field">        
    <!-- only generate overloaded constructor if there are fields in this method -->
    inline <xsl:value-of select="$f/@name"/>(<xsl:value-of select="$f/field/concat(@cpp-arg-type, ' _', @name)" separator=", "/>) : <xsl:value-of select="$f/field/concat(@name, '(_', @name, ')')" separator=", "/>
    {
    }
    </xsl:if>

    inline <xsl:value-of select="$f/@name"/>()
    {
    }
};

</xsl:template> 

<xsl:template match="frames" mode="method-list-header">	
<xsl:result-document href="amqp_methods.h" format="textFormat">
/**
 * This file is autogenerated, do not modify.
 */

#ifndef AMQ_METHODS_H
#define AMQ_METHODS_H

        <xsl:for-each select="class/frame">
#include "<xsl:value-of select="@name"/>.h"
        </xsl:for-each>

namespace qpid {
namespace framing {

        <xsl:for-each select="class/frame">
const <xsl:value-of select="concat(@name, ' ', @declaration_name)"/>;
        </xsl:for-each>

AMQMethodBody* createAMQMethodBody(u_int16_t classId, u_int16_t methodId);

}
}

#endif
</xsl:result-document>
</xsl:template> 

<xsl:template match="frames" mode="method-list-source">	
    <xsl:result-document href="amqp_methods.cpp" format="textFormat">
#include "amqp_methods.h"
#include "qpid/QpidError.h"

namespace qpid {
namespace framing {
/**
 * This method is autogenerated, do not modify.
 */
AMQMethodBody* createAMQMethodBody(u_int16_t classId, u_int16_t methodId){
    switch(classId * 1000 + methodId)
    {
        <xsl:for-each select="class/frame">
            <xsl:text>case </xsl:text>
            <xsl:value-of select="@class-id"/>         
	    <xsl:text> * 1000 + </xsl:text> 
            <xsl:value-of select="@method-id"/>         
	    <xsl:text>: return new </xsl:text> 
            <xsl:value-of select="@name"/>();         
        </xsl:for-each>
    }
    THROW_QPID_ERROR(FRAMING_ERROR, "Unknown method");	
}

}
}
</xsl:result-document>
</xsl:template> 

<xsl:template match="frames" mode="generate-interface">	
    <xsl:result-document href="AMQPServer.h" format="textFormat">
#include "qpid/framing/amqp_types.h"
#include "qpid/framing/FieldTable.h"

#ifndef _AMQPServer_
#define _AMQPServer_

namespace qpid {
namespace framing {

class AMQPServer
{
    public:

    <xsl:for-each select="class">
    class <xsl:value-of select="concat(amqp:upper-first(@name), 'Handler')"/>{
        public:
        <xsl:for-each select="frame[@server='true']">      
        <xsl:if test="field">
            virtual void <xsl:value-of select="@invocation_name"/>(u_int16_t channel, <xsl:value-of select="field/concat(@cpp-arg-type, ' ', @name)" separator=", "/>) = 0; 
        </xsl:if>
        <xsl:if test="not(field)">
            virtual void <xsl:value-of select="@invocation_name"/>(u_int16_t channel) = 0; 
        </xsl:if>
        </xsl:for-each>      
            virtual ~<xsl:value-of select="concat(amqp:upper-first(@name), 'Handler')"/>(){}
    };

    virtual <xsl:value-of select="concat(amqp:upper-first(@name), 'Handler* get', amqp:upper-first(@name), 'Handler')"/>() = 0;       
 
    </xsl:for-each>      
    virtual ~AMQPServer(){}
};

}
}

#endif
</xsl:result-document>

    <xsl:result-document href="AMQPClient.h" format="textFormat">
#include "qpid/framing/amqp_types.h"
#include "qpid/framing/FieldTable.h"

#ifndef _AMQPClient_
#define _AMQPClient_

namespace qpid {
namespace framing {

class AMQPClient
{
    public:

    <xsl:for-each select="class">
    class <xsl:value-of select="concat(amqp:upper-first(@name), 'Handler')"/>{
        public:
        <xsl:for-each select="frame[@client='true']">      
        <xsl:if test="field">
            virtual void <xsl:value-of select="@invocation_name"/>(u_int16_t channel, <xsl:value-of select="field/concat(@cpp-arg-type, ' ', @name)" separator=", "/>) = 0; 
        </xsl:if>
        <xsl:if test="not(field)">
            virtual void <xsl:value-of select="@invocation_name"/>(u_int16_t channel) = 0; 
        </xsl:if>
        </xsl:for-each>      
            virtual ~<xsl:value-of select="concat(amqp:upper-first(@name), 'Handler')"/>(){}
    };

    virtual <xsl:value-of select="concat(amqp:upper-first(@name), 'Handler* get', amqp:upper-first(@name), 'Handler')"/>() = 0;       
 
    </xsl:for-each>      

    virtual ~AMQPClient(){}
};

}
}

#endif
</xsl:result-document>

</xsl:template> 

</xsl:stylesheet>
