/**
   * Generate MAVLink Java Enum classes
   *
   * @param mavlink
   * @param targetPath
   * @param implementations
   */
  protected void generateEnumClass(
      MAVLinkData mavlink, String targetPath, Map<String, String> implementations) {
    String packageRootName = "org.mavlink.messages";
    String packageName = packageRootName;
    String directory = targetPath + "/org/mavlink/messages/";
    OutputStream output = null;
    PrintWriter writer = null;

    for (MAVLinkEnum message : mavlink.getEnums().values()) {
      try {
        String className = message.getName();
        String filename = directory + className + ".java";
        output = new FileOutputStream(filename, false);
        writer = new PrintWriter(output);
        writer.print("/**\n * Generated class : " + className + "\n * DO NOT MODIFY!\n **/\n");
        writer.print("package " + packageName + ";\n");
        String description = message.getDescription();
        writer.print(
            "/**\n * Interface "
                + className
                + "\n * "
                + (description == null ? "" : message.getDescription().trim())
                + "\n **/\n");
        writer.print("public interface " + className + " {\n");
        implementations.put(className.trim(), className.trim());
        for (int j = 0; j < message.getEntries().size(); j++) {
          MAVLinkEntry entry = message.getEntries().get(j);
          writer.print("    /**\n     * " + entry.getDescription() + "\n");
          for (int k = 0; k < entry.getParams().size(); k++) {
            MAVLinkParam param = entry.getParams().get(k);
            writer.print("     * PARAM " + param.getIndex() + " : " + param.getComment() + "\n");
          }
          writer.print("     */\n");
          writer.print(
              "    public final static int " + entry.getName() + " = " + entry.getValue() + ";\n");
        }
        writer.print("}\n");
      } catch (Exception e) {
        System.err.println("ERROR : " + e);
        e.printStackTrace();
      } finally {
        try {
          writer.close();
          output.close();
        } catch (Exception ex) {
          System.err.println("ERROR : " + ex);
          ex.printStackTrace();
        }
      }
    }
  }
 /**
  * Generate Interface with all MAVLink messages ID
  *
  * @param mavlink
  * @param targetPath
  */
 protected void generateIMavlinkId(MAVLinkData mavlink, String targetPath) {
   String packageRootName = "org.mavlink.messages";
   String packageName = packageRootName;
   String directory = targetPath + "/org/mavlink/messages/";
   OutputStream output = null;
   PrintWriter writer = null;
   String className = "IMAVLinkMessageID";
   String filename = directory + className + ".java";
   try {
     File file = new File(directory);
     file.mkdirs();
     output = new FileOutputStream(filename, false);
     writer = new PrintWriter(output);
     // Write Header
     writer.print("/**\n * Generated class : " + className + "\n * DO NOT MODIFY!\n **/\n");
     writer.print("package " + packageName + ";\n");
     writer.print(
         "/**\n * Interface IMAVLinkMessageId\n * Generate al MAVLink message Id in an interface\n **/\n");
     writer.print("public interface IMAVLinkMessageID {\n");
     for (MAVLinkMessage message : mavlink.getMessages().values()) {
       String id = MAVLINK_MSG + "_ID_" + message.getName();
       writer.print("  public static int " + id + " = " + message.getId() + ";\n");
     }
     writer.print("}\n");
   } catch (Exception e) {
     System.err.println("ERROR : " + e);
     e.printStackTrace();
   } finally {
     try {
       writer.close();
       output.close();
     } catch (Exception ex) {
       System.err.println("ERROR : " + ex);
       ex.printStackTrace();
     }
   }
 }
 /**
  * Parse a MAVLink xml messages descriptor file.
  *
  * @param mavlink MAVLink data used and to fill
  * @param file Parsed file
  * @param path Path to file
  * @param target Path for generation
  * @param inInclude True if we are in an include file
  * @return implementation code for readers and writers.
  * @throws ParserConfigurationException
  * @throws SAXException
  * @throws IOException
  */
 public Map<String, String> parseFile(
     MAVLinkData mavlink, String file, String path, String target, boolean inInclude)
     throws ParserConfigurationException, SAXException, IOException {
   Map<String, String> implementations = new HashMap<String, String>();
   SAXParserFactory fabrique = SAXParserFactory.newInstance();
   SAXParser parseur = fabrique.newSAXParser();
   if (!inInclude) {
     mavlink.setFile(file.substring(0, file.indexOf('.')));
     System.out.println("MAVLinkData : " + mavlink.getFile());
   } else {
     System.out.println("MAVLinkData INCLUDE : " + file.substring(0, file.indexOf('.')));
   }
   MAVLinkHandler gestionnaire = new MAVLinkHandler(this, mavlink, path, target);
   parseur.parse(new File(path + File.separator + file), gestionnaire);
   mavlink = gestionnaire.getMavlink();
   generateMessageClass(mavlink, target);
   mavlink.getEnums().putAll(mavlink.getEnums());
   mavlink.getMessages().putAll(mavlink.getMessages());
   generateEnumClass(mavlink, target, implementations);
   return implementations;
 }
 /**
  * Generate a factory classe which generate MAVLink messages from byte array
  *
  * @param mavlink
  * @param targetPath
  */
 protected void generateFactoryClass(MAVLinkData mavlink, String targetPath) {
   String packageRootName = "org.mavlink.messages";
   String packageName = packageRootName;
   String directory = targetPath + "/org/mavlink/messages/";
   OutputStream output = null;
   PrintWriter writer = null;
   String className = "MAVLinkMessageFactory";
   String filename = directory + className + ".java";
   try {
     File file = new File(directory);
     file.mkdirs();
     output = new FileOutputStream(filename, false);
     writer = new PrintWriter(output);
     // Write Header
     writer.print("/**\n * Generated class : " + className + "\n * DO NOT MODIFY!\n **/\n");
     writer.print("package " + packageName + ";\n");
     writer.print("import " + packageRootName + ".MAVLinkMessage;\n");
     writer.print("import org.mavlink.IMAVLinkMessage;\n");
     writer.print("import java.io.IOException;\n");
     if (forEmbeddedJava) {
       if (isLittleEndian) {
         writer.print("import org.mavlink.io.LittleEndianDataInputStream;\n");
         writer.print("import java.io.ByteArrayInputStream;\n");
       } else {
         writer.print("import java.io.DataInputStream;\n");
         writer.print("import java.io.ByteArrayInputStream;\n");
       }
     } else {
       writer.print("import java.nio.ByteBuffer;\n");
       writer.print("import java.nio.ByteOrder;\n");
     }
     writer.print(imports);
     writer.print(
         "/**\n * Class MAVLinkMessageFactory\n * Generate MAVLink message classes from byte array\n **/\n");
     writer.print(
         "public class MAVLinkMessageFactory implements IMAVLinkMessage, IMAVLinkMessageID {\n");
     writer.print(
         "public static MAVLinkMessage getMessage(int msgid, int sysId, int componentId, byte[] rawData) throws IOException {\n");
     writer.print("    MAVLinkMessage msg=null;\n");
     if (forEmbeddedJava) {
       if (isLittleEndian) {
         writer.print(
             "    LittleEndianDataInputStream dis = new LittleEndianDataInputStream(new ByteArrayInputStream(rawData));\n");
       } else {
         writer.print(
             "    DataInputStream dis = new DataInputStream(new ByteArrayInputStream(rawData));\n");
       }
     } else {
       if (isLittleEndian) {
         writer.print(
             "    ByteBuffer dis = ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN);\n");
       } else {
         writer.print(
             "    ByteBuffer dis = ByteBuffer.wrap(rawData).order(ByteOrder.BIG_ENDIAN);\n");
       }
     }
     writer.print("    switch(msgid) {\n");
     for (MAVLinkMessage message : mavlink.getMessages().values()) {
       String msgClassName = "msg_" + message.getName().toLowerCase();
       String id = MAVLINK_MSG + "_ID_" + message.getName();
       writer.print("  case " + id + ":\n");
       writer.print("      msg = new " + msgClassName + "(sysId, componentId);\n");
       writer.print("      msg.decode(dis);\n");
       writer.print("      break;\n");
     }
     writer.print("  default:\n");
     writer.print(
         "      System.out.println(\"Mavlink Factory Error : unknown MsgId : \" + msgid);\n");
     writer.print("    }\n");
     writer.print("    return msg;\n");
     writer.print("  }\n");
     writer.print("}\n");
   } catch (Exception e) {
     System.err.println("ERROR : " + e);
     e.printStackTrace();
   } finally {
     try {
       writer.close();
       output.close();
     } catch (Exception ex) {
       System.err.println("ERROR : " + ex);
       ex.printStackTrace();
     }
   }
 }
  /**
   * Generate MAVLink messages Java classes
   *
   * @param mavlink
   * @param targetPath
   */
  protected void generateMessageClass(MAVLinkData mavlink, String targetPath) {
    StringBuffer sbRead, sbWrite, fieldWrite;
    String packageRootName = "org.mavlink.messages";
    String xmlFilename = mavlink.getFile();
    String packageName = packageRootName + "." + xmlFilename;
    String directory = targetPath + "/org/mavlink/messages/" + xmlFilename + "/";
    OutputStream output = null;
    PrintWriter writer = null;
    String forToString = "";
    for (MAVLinkMessage message : mavlink.getMessages().values()) {
      String className = "msg_" + message.getName().toLowerCase();
      String filename = directory + className + ".java";
      imports = imports + "import " + packageName + "." + className + ";\n";
      try {
        File file = new File(directory);
        file.mkdirs();
        output = new FileOutputStream(filename, false);
        writer = new PrintWriter(output);
        sbRead = new StringBuffer();
        sbWrite = new StringBuffer();
        fieldWrite = new StringBuffer();
        if (forEmbeddedJava) {
          sbWrite.append("  dos.writeByte((byte)0xFE);\n");
          sbWrite.append("  dos.writeByte(length & 0x00FF);\n");
          sbWrite.append("  dos.writeByte(sequence & 0x00FF);\n");
          sbWrite.append("  dos.writeByte(sysId & 0x00FF);\n");
          sbWrite.append("  dos.writeByte(componentId & 0x00FF);\n");
          sbWrite.append("  dos.writeByte(messageType & 0x00FF);\n");
        } else {
          sbWrite.append("  dos.put((byte)0xFE);\n");
          sbWrite.append("  dos.put((byte)(length & 0x00FF));\n");
          sbWrite.append("  dos.put((byte)(sequence & 0x00FF));\n");
          sbWrite.append("  dos.put((byte)(sysId & 0x00FF));\n");
          sbWrite.append("  dos.put((byte)(componentId & 0x00FF));\n");
          sbWrite.append("  dos.put((byte)(messageType & 0x00FF));\n");
        }
        // Write Header
        writer.print("/**\n * Generated class : " + className + "\n * DO NOT MODIFY!\n **/\n");
        writer.print("package " + packageName + ";\n");
        writer.print("import " + packageRootName + ".MAVLinkMessage;\n");
        writer.print("import org.mavlink.IMAVLinkCRC;\n");
        writer.print("import org.mavlink.MAVLinkCRC;\n");
        writer.print("import java.io.ByteArrayOutputStream;\n");
        writer.print("import java.io.IOException;\n");
        if (forEmbeddedJava) {
          if (isLittleEndian) {
            writer.print("import org.mavlink.io.LittleEndianDataInputStream;\n");
            writer.print("import org.mavlink.io.LittleEndianDataOutputStream;\n");
          } else {
            writer.print("import java.io.DataInputStream;\n");
            writer.print("import java.io.DataOutputStream;\n");
          }
        } else {
          writer.print("import java.nio.ByteBuffer;\n");
          writer.print("import java.nio.ByteOrder;\n");
        }
        String description = message.getDescription();
        writer.print(
            "/**\n * Class "
                + className
                + "\n * "
                + (description == null ? "" : message.getDescription().trim())
                + "\n **/\n");
        writer.print("public class " + className + " extends MAVLinkMessage {\n");
        String id = MAVLINK_MSG + "_ID_" + message.getName();
        writer.print("  public static final int " + id + " = " + message.getId() + ";\n");
        writer.print("  private static final long serialVersionUID = " + id + ";\n");
        writer.print(
            "  public "
                + className
                + "(int sysId, int componentId) {\n    messageType = "
                + id
                + ";\n    this.sysId = sysId;\n    this.componentId = componentId;\n");

        // Calculate extra_crc for Mavlinl 1.0
        String extraCrcBuffer = message.getName() + " ";
        // Write Fields
        int fieldLen = 0;
        Collections.sort(message.getFields(), new FieldCompare());
        for (int j = 0; j < message.getFields().size(); j++) {
          MAVLinkField field = message.getFields().get(j);
          fieldWrite.append("  /**\n   * " + field.getDescription().trim() + "\n   */\n");
          MAVLinkDataType type = field.getType();
          fieldWrite.append("  public " + type.getJavaType(field.getName()) + "\n");
          sbRead.append(type.getReadType(field.getName(), forEmbeddedJava));
          sbWrite.append(type.getWriteType(field.getName(), forEmbeddedJava));
          String attr = field.getName();
          if (type.isArray && type.type == MAVLinkDataType.CHAR) {
            String first = "" + attr.charAt(0);
            attr = first.toUpperCase() + field.getName().substring(1);
            fieldWrite.append("  public void set" + attr + "(String tmp) {\n");
            fieldWrite.append("    int len = Math.min(tmp.length(), " + type.arrayLenth + ");\n");
            fieldWrite.append(
                "    for (int i=0; i<len; i++) {\n      "
                    + field.getName()
                    + "[i] = tmp.charAt(i);\n    }\n");
            fieldWrite.append(
                "    for (int i=len; i<"
                    + type.arrayLenth
                    + "; i++) {\n      "
                    + field.getName()
                    + "[i] = 0;\n    }\n  }\n");
            fieldWrite.append("  public String get" + attr + "() {\n");
            fieldWrite.append("    String result=\"\";\n");
            fieldWrite.append(
                "    for (int i=0; i<"
                    + type.arrayLenth
                    + "; i++) {\n      if ("
                    + field.getName()
                    + "[i] != 0) result=result+"
                    + field.getName()
                    + "[i]; else break;\n    }\n    return result;\n  }\n");
          }
          fieldLen += type.getLengthType();
          forToString =
              forToString
                  + (j != 0 ? "+" : "")
                  + "  \"  "
                  + field.getName()
                  + "=\"+"
                  + (field.getType().isArray && field.getType().type == MAVLinkDataType.CHAR
                      ? "get" + attr + "()"
                      : field.getName());
          extraCrcBuffer = extraCrcBuffer + type.getCType() + " " + field.getName() + " ";
          if (type.isArray) {
            extraCrcBuffer = extraCrcBuffer + (char) type.arrayLenth;
          }
        }
        writer.print("    length = " + fieldLen + ";\n}\n\n");
        writer.print(fieldWrite.toString());
        int extra_crc = MAVLinkCRC.crc_calculate(MAVLinkCRC.stringToByte(extraCrcBuffer));
        int magicNumber = (extra_crc & 0x00FF) ^ ((extra_crc >> 8 & 0x00FF));
        MAVLINK_MESSAGE_CRCS[message.getId()] = magicNumber;

        writer.print("/**\n");
        writer.print(" * Decode message with raw data\n");
        writer.print(" */\n");
        if (forEmbeddedJava) {
          if (isLittleEndian) {
            writer.print(
                "public void decode(LittleEndianDataInputStream dis) throws IOException {\n");
          } else {
            writer.print("public void decode(DataInputStream dis) throws IOException {\n");
          }
        } else {
          writer.print("public void decode(ByteBuffer dis) throws IOException {\n");
        }

        writer.print(sbRead.toString());
        writer.print("}\n");

        writer.print("/**\n");
        writer.print(" * Encode message with raw data and other informations\n");
        writer.print(" */\n");
        writer.print("public byte[] encode() throws IOException {\n");
        writer.print("  byte[] buffer = new byte[8+" + fieldLen + "];\n");
        if (forEmbeddedJava) {
          if (isLittleEndian) {
            writer.print(
                "   LittleEndianDataOutputStream dos = new LittleEndianDataOutputStream(new ByteArrayOutputStream());\n");
          } else {
            writer.print("   ByteArrayOutputStream baos = new ByteArrayOutputStream();\n");
            writer.print("   DataOutputStream dos = new DataOutputStream(baos);\n");
          }
        } else {
          if (isLittleEndian) {
            writer.print(
                "   ByteBuffer dos = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN);\n");
          } else {
            writer.print(
                "   ByteBuffer dos = ByteBuffer.wrap(buffer).order(ByteOrder.BIG_ENDIAN);\n");
          }
        }
        writer.print(sbWrite.toString());
        if (forEmbeddedJava) {
          if (isLittleEndian) {
            writer.print("  dos.flush();\n  byte[] tmp = dos.toByteArray();\n");
          } else {
            writer.print("  dos.flush();\n  byte[] tmp = baos.toByteArray();\n");
          }
          writer.print("  for (int b=0; b<tmp.length; b++) buffer[b]=tmp[b];\n");
        } else {
          // nothing
        }
        writer.print("  int crc = MAVLinkCRC.crc_calculate_encode(buffer, " + fieldLen + ");\n");
        writer.print(
            "  crc = MAVLinkCRC.crc_accumulate((byte) IMAVLinkCRC.MAVLINK_MESSAGE_CRCS[messageType], crc);\n");
        writer.print("  byte crcl = (byte) (crc & 0x00FF);\n");
        writer.print("  byte crch = (byte) ((crc >> 8) & 0x00FF);\n");
        writer.print("  buffer[" + (fieldLen + 6) + "] = crcl;\n");
        writer.print("  buffer[" + (fieldLen + 7) + "] = crch;\n");
        writer.print("  return buffer;\n}\n");

        if (debug) {
          writer.print("public String toString() {\n");
          writer.print("return \"" + id + " : \" + " + forToString + ";");
          writer.print("}\n");
        }
        writer.print("}\n");
        forToString = "";
      } catch (Exception e) {
        System.err.println("ERROR : " + e);
        e.printStackTrace();
      } finally {
        try {
          writer.close();
          output.close();
        } catch (Exception ex) {
          System.err.println("ERROR : " + ex);
          ex.printStackTrace();
        }
      }
    }
  }