/**
   * Serializes an unbounded sequence.
   *
   * @param nestedFieldName The name of the field (including scope)
   * @param seqType The type of the sequence.
   * @param data The data to serialize.
   */
  private void serializeUnboundedSequence(
      StringWriter writer, String nestedFieldName, MetaCollection seqType, UserData data) {
    String value;
    String typeName;
    StringTokenizer tokenizer;
    MetaField subType = seqType.getSubType();
    String token;
    String seqTypeName;

    seqTypeName = seqType.getTypeName();

    if (subType instanceof MetaPrimitive) {
      value = data.getFieldValue(nestedFieldName);

      if (value != null) {
        if (value.equals("NULL")) {
          writer.write("<NULL>");
        } else if (value.equals("[]")) {
          writer.write("<size>0</size>");
        } else {
          tokenizer = new StringTokenizer(value.substring(1, value.length() - 1), ",");
          int size = tokenizer.countTokens();

          writer.write("<size>" + size + "</size>");

          for (int i = 0; i < size; i++) {
            token = tokenizer.nextToken();
            writer.write("<element>" + token + "</element>");
          }
        }
      } else {
        // also check for the alternative notation
        value = data.getFieldValue(nestedFieldName + "[0]");
        if (value != null) {
          List<String> values = new ArrayList<String>();
          int index = 1;
          while (value != null) {
            values.add(value);
            value = data.getFieldValue(nestedFieldName + "[" + index + "]");
            index++;
          }
          writer.write("<size>" + values.size() + "</size>");
          Iterator<String> it = values.iterator();
          while (it.hasNext()) {
            writer.write("<element>" + it.next() + "</element>");
          }
        } else {
          writer.write("&lt;NULL&gt;");
        }
      }
    } else if (subType instanceof MetaCollection) {
      typeName = subType.getTypeName();

      if ((typeName.equals("c_string"))
          || (typeName.equals("c_wstring"))
          || (typeName.startsWith("C_STRING<"))
          || (typeName.startsWith("C_WSTRING<"))) {
        value = data.getFieldValue(nestedFieldName);

        if (value != null) {
          if (value.equals("NULL")) {
            writer.write("&lt;NULL&gt;");
          } else if (value.equals("[]")) {
            if (!(seqTypeName.startsWith("C_ARRAY"))) {
              writer.write("<size>0</size>");
            }
          } else {
            tokenizer = new StringTokenizer(value.substring(1, value.length() - 1), ",");
            int size = tokenizer.countTokens();

            if (!(seqTypeName.startsWith("C_ARRAY"))) {
              writer.write("<size>" + size + "</size>");
            }
            for (int i = 0; i < size; i++) {
              token = tokenizer.nextToken();
              writer.write("<element>" + token + "</element>");
            }
          }
        } else {
          writer.write("&lt;NULL&gt;");
        }
      }
    } else if (subType instanceof MetaStruct) {
      int size = 0;
      StringWriter localWriter = new StringWriter();
      // Verify if member "size" exists, if so, then serialize and
      // increment
      LinkedHashSet<String> fields = data.getFieldNames();
      boolean found = true;
      while (found) {
        String entryFieldName = nestedFieldName + "[" + size + "]";
        boolean fieldExists = false;
        Iterator<String> it = fields.iterator();
        while (!fieldExists && it.hasNext()) {
          if (it.next().startsWith(entryFieldName)) {
            fieldExists = true;
          }
        }
        if (fieldExists) {
          localWriter.write("<element>");
          serializeStruct(localWriter, entryFieldName, (MetaStruct) subType, data);
          localWriter.write("</element>");
          size++;
        } else {
          found = false;
        }
      }
      if (size == 0) {
        writer.write("&lt;NULL&gt;");
      } else {
        writer.write("<size>" + size + "</size>");
      }
      writer.write(localWriter.toString());
    } else if (subType instanceof MetaUnion) {
      int size = 0;
      StringWriter localWriter = new StringWriter();
      // Verify if member "size" exists, if so, then serialize and
      // increment
      LinkedHashSet<String> fields = data.getFieldNames();
      boolean found = true;
      while (found) {
        String entryFieldName = nestedFieldName + "[" + size + "]";
        boolean fieldExists = false;
        Iterator<String> it = fields.iterator();
        while (!fieldExists && it.hasNext()) {
          if (it.next().startsWith(entryFieldName)) {
            fieldExists = true;
          }
        }
        if (fieldExists) {
          localWriter.write("<element>");
          this.serializeUnion(localWriter, entryFieldName, (MetaUnion) subType, data);
          localWriter.write("</element>");
          size++;
        } else {
          found = false;
        }
      }
      if (size == 0) {
        writer.write("&lt;NULL&gt;");
      } else {
        writer.write("<size>" + size + "</size>");
      }
      writer.write(localWriter.toString());

    } else {
      writer.write("&lt;NULL&gt;");
    }
    return;
  }
  /**
   * Acquires the number of elements of the supplied sequence.
   *
   * @param nestedFieldName The name of the field (including scope)
   * @param seqType The type of the sequence.
   * @param data The data that is being serialized.
   * @return The number of elements in the given sequence.
   */
  private int getSequenceSize(String nestedFieldName, MetaCollection seqType, UserData data) {
    /*
     * This is very much based on how serializeUnboundedSequence get
     * the size of its unbounded sequence.
     * The same actions can be used on bounded sequences as well to
     * get their actual size (which can be less then their maximum
     * size).
     */
    int size = 0;

    StringTokenizer tokenizer;
    String typeName;
    String value;
    String token;
    MetaField subType = seqType.getSubType();

    if (subType instanceof MetaPrimitive) {
      value = data.getFieldValue(nestedFieldName);

      if (value != null) {
        if (!(value.equals("NULL") || value.equals("[]"))) {
          tokenizer = new StringTokenizer(value.substring(1, value.length() - 1), ",");
          size = tokenizer.countTokens();
        }
      } else {
        // also check for the alternative notation
        value = data.getFieldValue(nestedFieldName + "[0]");
        if (value != null) {
          List<String> values = new ArrayList<String>();
          int index = 1;
          while (value != null) {
            values.add(value);
            value = data.getFieldValue(nestedFieldName + "[" + index + "]");
            index++;
          }
          size = values.size();
        }
      }
    } else if (subType instanceof MetaCollection) {
      typeName = subType.getTypeName();

      if ((typeName.equals("c_string"))
          || (typeName.equals("c_wstring"))
          || (typeName.startsWith("C_STRING<"))
          || (typeName.startsWith("C_WSTRING<"))) {
        value = data.getFieldValue(nestedFieldName);

        if (value != null) {
          if (!(value.equals("NULL") || value.equals("[]"))) {
            tokenizer = new StringTokenizer(value.substring(1, value.length() - 1), ",");
            size = tokenizer.countTokens();
          }
        }
      }
    } else if ((subType instanceof MetaStruct) || (subType instanceof MetaUnion)) {
      // Verify if member "size" exists, if so, then serialize and
      // increment
      LinkedHashSet<String> fields = data.getFieldNames();
      boolean found = true;
      while (found) {
        String entryFieldName = nestedFieldName + "[" + size + "]";
        boolean fieldExists = false;
        Iterator<String> it = fields.iterator();
        while (!fieldExists && it.hasNext()) {
          if (it.next().startsWith(entryFieldName)) {
            fieldExists = true;
          }
        }
        if (fieldExists) {
          size++;
        } else {
          found = false;
        }
      }
    }
    return size;
  }