content: /**
   * 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.activemq.openwire.tool;
  
  import java.io.File;
  import java.io.PrintWriter;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.Iterator;
  import java.util.List;
  
  import org.codehaus.jam.JAnnotation;
  import org.codehaus.jam.JAnnotationValue;
  import org.codehaus.jam.JClass;
  import org.codehaus.jam.JProperty;
  
  /**
   * 
   */
  public class CSharpMarshallingGenerator extends JavaMarshallingGenerator {
  
      protected String targetDir = "./src/main/csharp";
  
      public Object run() {
          filePostFix = ".cs";
          if (destDir == null) {
              destDir = new File(targetDir + "/ActiveMQ/OpenWire/V" + getOpenwireVersion());
          }
          return super.run();
      }
  
      // ////////////////////////////////////////////////////////////////////////////////////
      // This section is for the tight wire format encoding generator
      // ////////////////////////////////////////////////////////////////////////////////////
  
      protected void generateTightUnmarshalBodyForProperty(PrintWriter out, JProperty property, JAnnotationValue size) {
  
          String propertyName = property.getSimpleName();
          String type = property.getType().getSimpleName();
  
          if (type.equals("boolean")) {
              out.println("        info." + propertyName + " = bs.ReadBoolean();");
          } else if (type.equals("byte")) {
              out.println("        info." + propertyName + " = dataIn.ReadByte();");
          } else if (type.equals("char")) {
              out.println("        info." + propertyName + " = dataIn.ReadChar();");
          } else if (type.equals("short")) {
              out.println("        info." + propertyName + " = dataIn.ReadInt16();");
          } else if (type.equals("int")) {
              out.println("        info." + propertyName + " = dataIn.ReadInt32();");
          } else if (type.equals("long")) {
              out.println("        info." + propertyName + " = TightUnmarshalLong(wireFormat, dataIn, bs);");
          } else if (type.equals("String")) {
              out.println("        info." + propertyName + " = TightUnmarshalString(dataIn, bs);");
          } else if (type.equals("byte[]") || type.equals("ByteSequence")) {
              if (size != null) {
                  out.println("        info." + propertyName + " = ReadBytes(dataIn, " + size.asInt() + ");");
              } else {
                  out.println("        info." + propertyName + " = ReadBytes(dataIn, bs.ReadBoolean());");
              }
          } else if (isThrowable(property.getType())) {
              out.println("        info." + propertyName + " = TightUnmarshalBrokerError(wireFormat, dataIn, bs);");
          } else if (isCachedProperty(property)) {
              out.println("        info." + propertyName + " = (" + type + ") TightUnmarshalCachedObject(wireFormat, dataIn, bs);");
          } else {
              out.println("        info." + propertyName + " = (" + type + ") TightUnmarshalNestedObject(wireFormat, dataIn, bs);");
          }
      }
  
      protected void generateTightUnmarshalBodyForArrayProperty(PrintWriter out, JProperty property, JAnnotationValue size) {
          JClass propertyType = property.getType();
          String arrayType = propertyType.getArrayComponentType().getSimpleName();
          String propertyName = property.getSimpleName();
          out.println();
          if (size != null) {
              out.println("        {");
              out.println("            " + arrayType + "[] value = new " + arrayType + "[" + size.asInt() + "];");
              out.println("            " + "for( int i=0; i < " + size.asInt() + "; i++ ) {");
              out.println("                value[i] = (" + arrayType + ") TightUnmarshalNestedObject(wireFormat,dataIn, bs);");
              out.println("            }");
              out.println("            info." + propertyName + " = value;");
              out.println("        }");
          } else {
              out.println("        if (bs.ReadBoolean()) {");
              out.println("            short size = dataIn.ReadInt16();");
              out.println("            " + arrayType + "[] value = new " + arrayType + "[size];");
              out.println("            for( int i=0; i < size; i++ ) {");
              out.println("                value[i] = (" + arrayType + ") TightUnmarshalNestedObject(wireFormat,dataIn, bs);");
              out.println("            }");
              out.println("            info." + propertyName + " = value;");
              out.println("        }");
              out.println("        else {");
              out.println("            info." + propertyName + " = null;");
              out.println("        }");
          }
      }
  
      protected int generateTightMarshal1Body(PrintWriter out) {
          List properties = getProperties();
          int baseSize = 0;
          for (Iterator iter = properties.iterator(); iter.hasNext();) {
              JProperty property = (JProperty)iter.next();
              JAnnotation annotation = property.getAnnotation("openwire:property");
              JAnnotationValue size = annotation.getValue("size");
              JClass propertyType = property.getType();
              String type = propertyType.getSimpleName();
              String getter = "info." + property.getSimpleName();
  
              if (type.equals("boolean")) {
                  out.println("        bs.WriteBoolean(" + getter + ");");
              } else if (type.equals("byte")) {
                  baseSize += 1;
              } else if (type.equals("char")) {
                  baseSize += 2;
              } else if (type.equals("short")) {
                  baseSize += 2;
              } else if (type.equals("int")) {
                  baseSize += 4;
              } else if (type.equals("long")) {
                  out.println("        rc += TightMarshalLong1(wireFormat, " + getter + ", bs);");
              } else if (type.equals("String")) {
                  out.print("");
                  out.println("        rc += TightMarshalString1(" + getter + ", bs);");
              } else if (type.equals("byte[]") || type.equals("ByteSequence")) {
                  if (size == null) {
                      out.println("        bs.WriteBoolean(" + getter + "!=null);");
                      out.println("        rc += " + getter + "==null ? 0 : " + getter + ".Length+4;");
                  } else {
                      baseSize += size.asInt();
                  }
              } else if (propertyType.isArrayType()) {
                  if (size != null) {
                      out.println("        rc += TightMarshalObjectArrayConstSize1(wireFormat, " + getter + ", bs, " + size.asInt() + ");");
                  } else {
                      out.println("        rc += TightMarshalObjectArray1(wireFormat, " + getter + ", bs);");
                  }
              } else if (isThrowable(propertyType)) {
                  out.println("        rc += TightMarshalBrokerError1(wireFormat, " + getter + ", bs);");
              } else {
                  if (isCachedProperty(property)) {
                      out.println("        rc += TightMarshalCachedObject1(wireFormat, (DataStructure)" + getter + ", bs);");
                  } else {
                      out.println("        rc += TightMarshalNestedObject1(wireFormat, (DataStructure)" + getter + ", bs);");
                  }
              }
          }
          return baseSize;
      }
  
      protected void generateTightMarshal2Body(PrintWriter out) {
          List properties = getProperties();
          for (Iterator iter = properties.iterator(); iter.hasNext();) {
              JProperty property = (JProperty)iter.next();
              JAnnotation annotation = property.getAnnotation("openwire:property");
              JAnnotationValue size = annotation.getValue("size");
              JClass propertyType = property.getType();
              String type = propertyType.getSimpleName();
              String getter = "info." + property.getSimpleName();
  
              if (type.equals("boolean")) {
                  out.println("        bs.ReadBoolean();");
              } else if (type.equals("byte")) {
                  out.println("        dataOut.Write(" + getter + ");");
              } else if (type.equals("char")) {
                  out.println("        dataOut.Write(" + getter + ");");
              } else if (type.equals("short")) {
                  out.println("        dataOut.Write(" + getter + ");");
              } else if (type.equals("int")) {
                  out.println("        dataOut.Write(" + getter + ");");
              } else if (type.equals("long")) {
                  out.println("        TightMarshalLong2(wireFormat, " + getter + ", dataOut, bs);");
              } else if (type.equals("String")) {
                  out.println("        TightMarshalString2(" + getter + ", dataOut, bs);");
              } else if (type.equals("byte[]") || type.equals("ByteSequence")) {
                  if (size != null) {
                      out.println("        dataOut.Write(" + getter + ", 0, " + size.asInt() + ");");
                  } else {
                      out.println("        if(bs.ReadBoolean()) {");
                      out.println("           dataOut.Write(" + getter + ".Length);");
                      out.println("           dataOut.Write(" + getter + ");");
                      out.println("        }");
                  }
              } else if (propertyType.isArrayType()) {
                  if (size != null) {
                      out.println("        TightMarshalObjectArrayConstSize2(wireFormat, " + getter + ", dataOut, bs, " + size.asInt() + ");");
                  } else {
                      out.println("        TightMarshalObjectArray2(wireFormat, " + getter + ", dataOut, bs);");
                  }
              } else if (isThrowable(propertyType)) {
                  out.println("        TightMarshalBrokerError2(wireFormat, " + getter + ", dataOut, bs);");
              } else {
                  if (isCachedProperty(property)) {
                      out.println("        TightMarshalCachedObject2(wireFormat, (DataStructure)" + getter + ", dataOut, bs);");
                  } else {
                      out.println("        TightMarshalNestedObject2(wireFormat, (DataStructure)" + getter + ", dataOut, bs);");
                  }
              }
          }
      }
  
      // ////////////////////////////////////////////////////////////////////////////////////
      // This section is for the loose wire format encoding generator
      // ////////////////////////////////////////////////////////////////////////////////////
  
      protected void generateLooseUnmarshalBodyForProperty(PrintWriter out, JProperty property, JAnnotationValue size) {
  
          String propertyName = property.getSimpleName();
          String type = property.getType().getSimpleName();
  
          if (type.equals("boolean")) {
              out.println("        info." + propertyName + " = dataIn.ReadBoolean();");
          } else if (type.equals("byte")) {
              out.println("        info." + propertyName + " = dataIn.ReadByte();");
          } else if (type.equals("char")) {
              out.println("        info." + propertyName + " = dataIn.ReadChar();");
          } else if (type.equals("short")) {
              out.println("        info." + propertyName + " = dataIn.ReadInt16();");
          } else if (type.equals("int")) {
              out.println("        info." + propertyName + " = dataIn.ReadInt32();");
          } else if (type.equals("long")) {
              out.println("        info." + propertyName + " = LooseUnmarshalLong(wireFormat, dataIn);");
          } else if (type.equals("String")) {
              out.println("        info." + propertyName + " = LooseUnmarshalString(dataIn);");
          } else if (type.equals("byte[]") || type.equals("ByteSequence")) {
              if (size != null) {
                  out.println("        info." + propertyName + " = ReadBytes(dataIn, " + size.asInt() + ");");
              } else {
                  out.println("        info." + propertyName + " = ReadBytes(dataIn, dataIn.ReadBoolean());");
              }
          } else if (isThrowable(property.getType())) {
              out.println("        info." + propertyName + " = LooseUnmarshalBrokerError(wireFormat, dataIn);");
          } else if (isCachedProperty(property)) {
              out.println("        info." + propertyName + " = (" + type + ") LooseUnmarshalCachedObject(wireFormat, dataIn);");
          } else {
              out.println("        info." + propertyName + " = (" + type + ") LooseUnmarshalNestedObject(wireFormat, dataIn);");
          }
      }
  
      protected void generateLooseUnmarshalBodyForArrayProperty(PrintWriter out, JProperty property, JAnnotationValue size) {
          JClass propertyType = property.getType();
          String arrayType = propertyType.getArrayComponentType().getSimpleName();
          String propertyName = property.getSimpleName();
          out.println();
          if (size != null) {
              out.println("        {");
              out.println("            " + arrayType + "[] value = new " + arrayType + "[" + size.asInt() + "];");
              out.println("            " + "for( int i=0; i < " + size.asInt() + "; i++ ) {");
              out.println("                value[i] = (" + arrayType + ") LooseUnmarshalNestedObject(wireFormat,dataIn);");
              out.println("            }");
              out.println("            info." + propertyName + " = value;");
              out.println("        }");
          } else {
              out.println("        if (dataIn.ReadBoolean()) {");
              out.println("            short size = dataIn.ReadInt16();");
              out.println("            " + arrayType + "[] value = new " + arrayType + "[size];");
              out.println("            for( int i=0; i < size; i++ ) {");
              out.println("                value[i] = (" + arrayType + ") LooseUnmarshalNestedObject(wireFormat,dataIn);");
              out.println("            }");
              out.println("            info." + propertyName + " = value;");
              out.println("        }");
              out.println("        else {");
              out.println("            info." + propertyName + " = null;");
              out.println("        }");
          }
      }
  
      protected void generateLooseMarshalBody(PrintWriter out) {
          List properties = getProperties();
          for (Iterator iter = properties.iterator(); iter.hasNext();) {
              JProperty property = (JProperty)iter.next();
              JAnnotation annotation = property.getAnnotation("openwire:property");
              JAnnotationValue size = annotation.getValue("size");
              JClass propertyType = property.getType();
              String type = propertyType.getSimpleName();
              String getter = "info." + property.getSimpleName();
  
              if (type.equals("boolean")) {
                  out.println("        dataOut.Write(" + getter + ");");
              } else if (type.equals("byte")) {
                  out.println("        dataOut.Write(" + getter + ");");
              } else if (type.equals("char")) {
                  out.println("        dataOut.Write(" + getter + ");");
              } else if (type.equals("short")) {
                  out.println("        dataOut.Write(" + getter + ");");
              } else if (type.equals("int")) {
                  out.println("        dataOut.Write(" + getter + ");");
              } else if (type.equals("long")) {
                  out.println("        LooseMarshalLong(wireFormat, " + getter + ", dataOut);");
              } else if (type.equals("String")) {
                  out.println("        LooseMarshalString(" + getter + ", dataOut);");
              } else if (type.equals("byte[]") || type.equals("ByteSequence")) {
                  if (size != null) {
                      out.println("        dataOut.Write(" + getter + ", 0, " + size.asInt() + ");");
                  } else {
                      out.println("        dataOut.Write(" + getter + "!=null);");
                      out.println("        if(" + getter + "!=null) {");
                      out.println("           dataOut.Write(" + getter + ".Length);");
                      out.println("           dataOut.Write(" + getter + ");");
                      out.println("        }");
                  }
              } else if (propertyType.isArrayType()) {
                  if (size != null) {
                      out.println("        LooseMarshalObjectArrayConstSize(wireFormat, " + getter + ", dataOut, " + size.asInt() + ");");
                  } else {
                      out.println("        LooseMarshalObjectArray(wireFormat, " + getter + ", dataOut);");
                  }
              } else if (isThrowable(propertyType)) {
                  out.println("        LooseMarshalBrokerError(wireFormat, " + getter + ", dataOut);");
              } else {
                  if (isCachedProperty(property)) {
                      out.println("        LooseMarshalCachedObject(wireFormat, (DataStructure)" + getter + ", dataOut);");
                  } else {
                      out.println("        LooseMarshalNestedObject(wireFormat, (DataStructure)" + getter + ", dataOut);");
                  }
              }
          }
      }
  
      public String getTargetDir() {
          return targetDir;
      }
  
      public void setTargetDir(String targetDir) {
          this.targetDir = targetDir;
      }
  
      private void generateLicence(PrintWriter out) {
          out.println("/**");
          out.println(" * Licensed to the Apache Software Foundation (ASF) under one or more");
          out.println(" * contributor license agreements.  See the NOTICE file distributed with");
          out.println(" * this work for additional information regarding copyright ownership.");
          out.println(" * The ASF licenses this file to You under the Apache License, Version 2.0");
          out.println(" * (the \"License\"); you may not use this file except in compliance with");
          out.println(" * the License.  You may obtain a copy of the License at");
          out.println(" *");
          out.println(" *      http://www.apache.org/licenses/LICENSE-2.0");
          out.println(" *");
          out.println(" * Unless required by applicable law or agreed to in writing, software");
          out.println(" * distributed under the License is distributed on an \"AS IS\" BASIS,");
          out.println(" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.");
          out.println(" * See the License for the specific language governing permissions and");
          out.println(" * limitations under the License.");
          out.println(" */");
      }
  
      protected void generateFile(PrintWriter out) throws Exception {
          generateLicence(out);
          out.println("");
          out.println("//");
          out.println("// NOTE!: This file is autogenerated - do not modify!");
          out.println("//        if you need to make a change, please see the Groovy scripts in the");
          out.println("//        activemq-core module");
          out.println("//");
          out.println("");
          out.println("using System;");
          out.println("using System.Collections;");
          out.println("using System.IO;");
          out.println("");
          out.println("using ActiveMQ.Commands;");
          out.println("using ActiveMQ.OpenWire;");
          out.println("using ActiveMQ.OpenWire.V" + getOpenwireVersion() + ";");
          out.println("");
          out.println("namespace ActiveMQ.OpenWire.V" + getOpenwireVersion() + "");
          out.println("{");
          out.println("  /// <summary>");
          out.println("  ///  Marshalling code for Open Wire Format for " + jclass.getSimpleName() + "");
          out.println("  /// </summary>");
          out.println("  " + getAbstractClassText() + "class " + getClassName() + " : " + getBaseClass() + "");
          out.println("  {");
  
          if (!isAbstractClass()) {
              out.println("");
              out.println("");
              out.println("    public override DataStructure CreateObject() ");
              out.println("    {");
              out.println("        return new " + jclass.getSimpleName() + "();");
              out.println("    }");
              out.println("");
              out.println("    public override byte GetDataStructureType() ");
              out.println("    {");
              out.println("        return " + jclass.getSimpleName() + ".ID_" + jclass.getSimpleName() + ";");
              out.println("    }");
          }
  
          /*
           * Generate the tight encoding marshallers
           */
          out.println("");
          out.println("    // ");
          out.println("    // Un-marshal an object instance from the data input stream");
          out.println("    // ");
          out.println("    public override void TightUnmarshal(OpenWireFormat wireFormat, Object o, BinaryReader dataIn, BooleanStream bs) ");
          out.println("    {");
          out.println("        base.TightUnmarshal(wireFormat, o, dataIn, bs);");
  
          if (!getProperties().isEmpty() || isMarshallerAware()) {
              out.println("");
              out.println("        " + jclass.getSimpleName() + " info = (" + jclass.getSimpleName() + ")o;");
          }
  
          if (isMarshallerAware()) {
              out.println("");
              out.println("        info.BeforeUnmarshall(wireFormat);");
              out.println("");
          }
  
          generateTightUnmarshalBody(out);
  
          if (isMarshallerAware()) {
              out.println("");
              out.println("        info.AfterUnmarshall(wireFormat);");
          }
  
          out.println("");
          out.println("    }");
          out.println("");
          out.println("    //");
          out.println("    // Write the booleans that this object uses to a BooleanStream");
          out.println("    //");
          out.println("    public override int TightMarshal1(OpenWireFormat wireFormat, Object o, BooleanStream bs) {");
          out.println("        " + jclass.getSimpleName() + " info = (" + jclass.getSimpleName() + ")o;");
  
          if (isMarshallerAware()) {
              out.println("");
              out.println("        info.BeforeMarshall(wireFormat);");
          }
  
          out.println("");
          out.println("        int rc = base.TightMarshal1(wireFormat, info, bs);");
  
          int baseSize = generateTightMarshal1Body(out);
  
          out.println("");
          out.println("        return rc + " + baseSize + ";");
          out.println("    }");
          out.println("");
          out.println("    // ");
          out.println("    // Write a object instance to data output stream");
          out.println("    //");
          out.println("    public override void TightMarshal2(OpenWireFormat wireFormat, Object o, BinaryWriter dataOut, BooleanStream bs) {");
          out.println("        base.TightMarshal2(wireFormat, o, dataOut, bs);");
  
          if (!getProperties().isEmpty() || isMarshallerAware()) {
              out.println("");
              out.println("        " + jclass.getSimpleName() + " info = (" + jclass.getSimpleName() + ")o;");
          }
  
          generateTightMarshal2Body(out);
  
          if (isMarshallerAware()) {
              out.println("");
              out.println("        info.AfterMarshall(wireFormat);");
          }
  
          out.println("");
          out.println("    }");
  
          out.println("");
          out.println("    // ");
          out.println("    // Un-marshal an object instance from the data input stream");
          out.println("    // ");
          out.println("    public override void LooseUnmarshal(OpenWireFormat wireFormat, Object o, BinaryReader dataIn) ");
          out.println("    {");
          out.println("        base.LooseUnmarshal(wireFormat, o, dataIn);");
  
          if (!getProperties().isEmpty() || isMarshallerAware()) {
              out.println("");
              out.println("        " + jclass.getSimpleName() + " info = (" + jclass.getSimpleName() + ")o;");
          }
  
          if (isMarshallerAware()) {
              out.println("");
              out.println("        info.BeforeUnmarshall(wireFormat);");
              out.println("");
          }
  
          generateLooseUnmarshalBody(out);
  
          if (isMarshallerAware()) {
              out.println("");
              out.println("        info.AfterUnmarshall(wireFormat);");
          }
  
          out.println("");
          out.println("    }");
          out.println("");
          out.println("    // ");
          out.println("    // Write a object instance to data output stream");
          out.println("    //");
          out.println("    public override void LooseMarshal(OpenWireFormat wireFormat, Object o, BinaryWriter dataOut) {");
  
          if (!getProperties().isEmpty() || isMarshallerAware()) {
              out.println("");
              out.println("        " + jclass.getSimpleName() + " info = (" + jclass.getSimpleName() + ")o;");
          }
  
          if (isMarshallerAware()) {
              out.println("");
              out.println("        info.BeforeMarshall(wireFormat);");
          }
  
          out.println("");
          out.println("        base.LooseMarshal(wireFormat, o, dataOut);");
  
          generateLooseMarshalBody(out);
  
          if (isMarshallerAware()) {
              out.println("");
              out.println("        info.AfterMarshall(wireFormat);");
          }
          out.println("");
          out.println("    }");
          out.println("  }");
          out.println("}");
  
      }
  
      public void generateFactory(PrintWriter out) {
          generateLicence(out);
          out.println("");
          out.println("//");
          out.println("// NOTE!: This file is autogenerated - do not modify!");
          out.println("//        if you need to make a change, please see the Groovy scripts in the");
          out.println("//        activemq-core module");
          out.println("//");
          out.println("");
          out.println("using System;");
          out.println("using System.Collections;");
          out.println("using System.IO;");
          out.println("");
          out.println("using ActiveMQ.Commands;");
          out.println("using ActiveMQ.OpenWire;");
          out.println("using ActiveMQ.OpenWire.V" + getOpenwireVersion() + ";");
          out.println("");
          out.println("namespace ActiveMQ.OpenWire.V" + getOpenwireVersion() + "");
          out.println("{");
          out.println("    /// <summary>");
          out.println("    /// Used to create marshallers for a specific version of the wire protocol");
          out.println("    /// </summary>");
          out.println("    public class MarshallerFactory : IMarshallerFactory");
          out.println("    {");
          out.println("        public void configure(OpenWireFormat format) ");
          out.println("        {");
          out.println("            format.clearMarshallers();");
  
          List<JClass> list = new ArrayList<JClass>(getConcreteClasses());
          Collections.sort(list, new Comparator<JClass>() {
              public int compare(JClass c1, JClass c2) {
                  return c1.getSimpleName().compareTo(c2.getSimpleName());
              }
          });
  
          for (Iterator iter = list.iterator(); iter.hasNext();) {
              JClass jclass = (JClass)iter.next();
              out.println("            format.addMarshaller(new " + jclass.getSimpleName() + "Marshaller());");
          }
  
          out.println("");
          out.println("        }");
          out.println("    }");
          out.println("}");
  
      }
  }
  