import org.activemq.openwire.tool.OpenWireScript

/**
 * Generates the Java marshalling code for the Open Wire Format
 *
 * @version $Revision: 1.1.1.1 $
 */
class GenerateJavaMarshalling extends OpenWireScript {

    Object run() {
        def destDir = new File("target/generated/java/org/activemq/openwire")
        destDir.mkdirs()

        def messageClasses = classes.findAll { isMessageType(it) }

        println "Generating Java marshalling code to directory ${destDir}"

        def buffer = new StringBuffer()

        int counter = 0
        Map map = [:]

        for (jclass in messageClasses) {

            println "Processing $jclass.simpleName"

            def properties = jclass.declaredProperties.findAll { isValidProperty(it) }
            def file = new File(destDir, jclass.simpleName + "Marshaller.java")

            String baseClass = "AbstractPacketMarshaller"
            if (jclass.superclass?.simpleName == "ActiveMQMessage") {
                baseClass = "ActiveMQMessageMarshaller"
            }

            buffer << """
${jclass.simpleName}Marshaller.class
"""

            file.withWriter { out |
                out << """/**
 * Marshalling code for Open Wire Format for ${jclass.simpleName}
 *
 *
 * NOTE!: This file is autogenerated - do not modify!
 *        if you need to make a change, please see the Groovy scripts in the
 *        activemq-openwire module
 */

package org.activemq.openwire;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import org.activemq.message.*;
import org.activemq.io.*;
import org.activemq.io.impl.*;

public class ${jclass.simpleName}Marshaller extends $baseClass {

/*
    public ${jclass.simpleName}Marshaller(AbstractDefaultWireFormat wireFormat){
        super(wireFormat);
    }
*/

    /**
     * Return the type of Packet
     *
     * @return integer representation of the type of Packet
     */
    public int getPacketType() {
        return ${getEnum(jclass)};
    }

    /**
     * @return a new Packet instance
     */
    public Packet createPacket() {
        return new ${jclass.simpleName}();
    }

    /**
     * build a Packet instance from the data input stream
     *
     * @param packet A Packet object
     * @param dataIn the data input stream to build the packet from
     * @throws IOException
     */
    public void buildPacket(Packet packet, DataInput dataIn) throws IOException {
        super.buildPacket(packet, dataIn);
        ${jclass.simpleName} info = (${jclass.simpleName}) packet;
"""
                for (property in properties) {
                    out << "        info.${property.setter.simpleName}("

                    def type = property.type.qualifiedName
                    switch (type) {
                        case "java.lang.String":
                            out << "dataIn.readUTF()"
                            break;

                        case "org.activemq.message.ActiveMQDestination":
                            out << "readDestination(dataIn)"
                            break;

                        case "boolean":
                            out << "dataIn.readBoolean()"
                            break;

                        case "byte":
                            out << "dataIn.readByte()"
                            break;

                        case "char":
                            out << "dataIn.readChar()"
                            break;

                        case "short":
                            out << "dataIn.readShort()"
                            break;

                        case "int":
                            out << "dataIn.readInt()"
                            break;

                        case "long":
                            out << "dataIn.readLong()"
                            break;

                        case "float":
                            out << "dataIn.readFloat()"
                            break;

                        case "double":
                            out << "dataIn.readDouble()"
                            break;

                        default:
                            out << "(${type}) readObject(dataIn)"
                    }
                    out << """);
"""
                }

                out << """
    }

    /**
     * Write a Packet instance to data output stream
     *
     * @param packet  the instance to be seralized
     * @param dataOut the output stream
     * @throws IOException thrown if an error occurs
     */
    public void writePacket(Packet packet, DataOutput dataOut) throws IOException {
        super.writePacket(packet, dataOut);
        ${jclass.simpleName} info = (${jclass.simpleName}) packet;
"""
                for (property in properties) {
                    def getter = "info." + property.getter.simpleName + "()"
                    out << "        "

                    def type = property.type.qualifiedName
                    switch (type) {
                        case "java.lang.String":
                            out << "writeUTF($getter, dataOut);"
                            break;

                        case "org.activemq.message.ActiveMQDestination":
                            out << "writeDestination($getter, dataOut);"
                            break;

                        case "boolean":
                            out << "dataOut.writeBoolean($getter);"
                            break;

                        case "byte":
                            out << "dataOut.writeByte($getter);"
                            break;

                        case "char":
                            out << "dataOut.writeChar($getter);"
                            break;

                        case "short":
                            out << "dataOut.writeShort($getter);"
                            break;

                        case "int":
                            out << "dataOut.writeInt($getter);"
                            break;

                        case "long":
                            out << "dataOut.writeLong($getter);"
                            break;

                        case "float":
                            out << "dataOut.writeFloat($getter);"
                            break;

                        case "double":
                            out << "dataOut.writeDouble($getter);"
                            break;

                        default:
                            out << "writeObject($getter, dataOut);"
                    }
                    out << """
"""
                }

                out << """
    }
}
"""
            }
        }
    }
}