public void endElement(String uri, String localName, String name) throws SAXException {

    if (collectText) {
      if (NAMESPACE_API.equals(uri) && localName.equals(collectTextElement)) {
        switch (this.currentState) {
          case STATE_DESCRIPTION:
            {
              if (this.currentObject instanceof DocumentedElement) {
                DocumentedElement documentedElement = ((DocumentedElement) this.currentObject);
                documentedElement.description = localizedString(this.text.toString());
                documentedElement.isHTMLDescription = this.collectHTML;
              }
              break;
            }
          case STATE_DEPRECIATED:
          case STATE_AVAILABLE:
            {
              if (this.currentObject instanceof DepreciatedOrAvailable) {
                ((DepreciatedOrAvailable) this.currentObject).text =
                    localizedString(this.text.toString());
              }
              break;
            }

          case STATE_ABOUTME:
          case STATE_QOUTE:
            {
              if (this.currentObject instanceof Author) {
                String text = localizedString(this.text.toString());
                Author author = (Author) this.currentObject;
                if (this.currentState == STATE_ABOUTME) author.aboutMe = text;
                else author.quote = text;
              }
              break;
            }
        }
        popState();
        this.collectText = false;
        this.collectHTML = false;
        this.collectTextElement = null;
        this.text = new StringBuffer();
      } else {
        if (pendingEndElement) text.append("/>");
        else text.append("</").append(localName).append(">");
      }
      pendingEndElement = false;
    } else {

      switch (this.currentState) {
        case STATE_API:
          {
            ArrayList collection = getCollection(TAG_CLASS);
            this.apis.classes = (ClassData[]) collection.toArray(new ClassData[collection.size()]);
            collection = getCollection(TAG_METHOD);
            this.apis.globalMethods = (Method[]) collection.toArray(new Method[collection.size()]);
            collection = getCollection(TAG_PROPERTY);
            this.apis.globalVars = (Property[]) collection.toArray(new Property[collection.size()]);
            collection = getCollection(TAG_AUTHOR);
            this.apis.authors = (Author[]) collection.toArray(new Author[collection.size()]);
            collection = getCollection(TAG_ENUM);
            this.apis.enums = (Enum[]) collection.toArray(new Enum[collection.size()]);
            collection = getCollection(TAG_ALIAS);
            this.apis.aliases = (Alias[]) collection.toArray(new Alias[collection.size()]);
            collection = getCollection(TAG_MIXIN);
            this.apis.mixins = (Mixin[]) collection.toArray(new Mixin[collection.size()]);
            collection = getCollection(TAG_NAMESPACE);
            this.apis.namespaces =
                (Namespace[]) collection.toArray(new Namespace[collection.size()]);
            break;
          }
        case STATE_CLASS:
        case STATE_INTERFACE:
          {
            ClassData clazz = (ClassData) this.currentObject;
            ArrayList collection = getCollection(TAG_ANCESTOR);
            clazz.ancestors = (Ancestor[]) collection.toArray(new Ancestor[collection.size()]);
            collection = getCollection(TAG_CONSTRUCTOR);
            clazz.constructors = (Method[]) collection.toArray(new Method[collection.size()]);
            collection = getCollection(TAG_EVENT);
            clazz.events = (Event[]) collection.toArray(new Event[collection.size()]);
            collection = getCollection(TAG_PROPERTY);
            clazz.properties = (Property[]) collection.toArray(new Property[collection.size()]);
            collection = getCollection(TAG_FIELD);
            clazz.fields = (Property[]) collection.toArray(new Property[collection.size()]);
            collection = getCollection(TAG_METHOD);
            clazz.methods = (Method[]) collection.toArray(new Method[collection.size()]);
            collection = getCollection(TAG_AUTHOR);
            clazz.mixins = (Mix[]) collection.toArray(new Mix[collection.size()]);
            collection = getCollection(TAG_ALIAS);
            clazz.aliases = (Alias[]) collection.toArray(new Alias[collection.size()]);
            break;
          }

        case STATE_CONSTRUCTOR:
        case STATE_METHOD:
          {
            Method method = (Method) this.currentObject;
            ArrayList collection = getCollection(TAG_EXCEPTION);
            method.exceptions = (Exception[]) collection.toArray(new Exception[collection.size()]);
            collection = getCollection(TAG_PARAMETER);
            method.parameters = (Parameter[]) collection.toArray(new Parameter[collection.size()]);

            break;
          }

        case STATE_ENUM:
          {
            Enum enumData = (Enum) this.currentObject;
            ArrayList collection = getCollection(TAG_OPTION);
            enumData.options = (Option[]) collection.toArray(new Option[collection.size()]);
            break;
          }

        case STATE_EVENT:
          {
            Event event = (Event) this.currentObject;
            ArrayList collection = getCollection(TAG_PARAMETER);
            event.parameters = (Parameter[]) collection.toArray(new Parameter[collection.size()]);
            break;
          }

        case STATE_EXCEPTION:
          {
            Exception exception = (Exception) this.currentObject;
            ArrayList collection = getCollection(TAG_PARAMETER);
            exception.parameters =
                (Parameter[]) collection.toArray(new Parameter[collection.size()]);
            break;
          }
      }
      popState();
    }
  }
  /**
   * Parses a method type definition
   *
   * @param docMethod
   * @return
   */
  protected static Method ParseMethod(MethodDoc docMethod) {
    assert (docMethod != null);

    Method xmlMethod = new Method();

    xmlMethod.name = docMethod.name();
    xmlMethod.hash = computeHash(docMethod.qualifiedName(), docMethod.signature());
    xmlMethod.qualifiedName = docMethod.qualifiedName();
    xmlMethod.comment = docMethod.commentText();
    xmlMethod.signature = docMethod.signature();
    xmlMethod.isNative = docMethod.isNative();
    xmlMethod.isVarArgs = docMethod.isVarArgs();
    xmlMethod.isSynchronized = docMethod.isSynchronized();
    xmlMethod.isFinal = docMethod.isFinal();
    xmlMethod.isAbstract = docMethod.isAbstract();
    xmlMethod.isStatic = docMethod.isStatic();

    xmlMethod.scope = DetermineScope(docMethod);

    // Parse parameters of the method
    Parameter[] parameters = docMethod.parameters();

    if (parameters != null && parameters.length > 0) {
      ParamTag[] paramComments = docMethod.paramTags();

      ArrayList<Param> paramList = new ArrayList<Param>();

      for (Parameter parameter : parameters) {
        ParamTag paramComment = null;

        // look to see if this parameter has comments
        // if so, paramComment will be set
        for (ParamTag testParam : paramComments) {
          String testParamName = testParam.parameterName();
          if (testParamName != null) {
            if (testParamName.compareTo(parameter.name()) == 0) {
              paramComment = testParam;
              break;
            }
          }
        }

        paramList.add(ParseParameter(parameter, paramComment));
      }

      xmlMethod.parameters = paramList.toArray(new Param[] {});
    } else {
      log.debug("No parameters for method: " + docMethod.name());
    }

    // Parse result data

    Result returnInfo = new Result();

    Tag[] returnTags = docMethod.tags("@return");
    if (returnTags != null && returnTags.length > 0) {
      // there should be only one return tag.  but heck,
      // if they specify two, so what...
      StringBuilder builder = new StringBuilder();
      for (Tag returnTag : returnTags) {
        String returnTagText = returnTag.text();
        if (returnTagText != null) {
          builder.append(returnTagText);
          builder.append("\n");
        }
      }

      returnInfo.comment = builder.substring(0, builder.length() - 1);
    }

    returnInfo.type = ParseType(docMethod.returnType());
    xmlMethod.result = returnInfo;

    // Parse exceptions of the method

    Type[] types = docMethod.thrownExceptionTypes();
    ThrowsTag[] exceptionComments = docMethod.throwsTags();

    if (types != null && types.length > 0) {
      ArrayList<ExceptionInstance> exceptionList = new ArrayList<ExceptionInstance>();

      for (Type exceptionType : types) {
        ExceptionInstance exception = new ExceptionInstance();

        exception.type = ParseType(exceptionType);

        for (ThrowsTag exceptionComment : exceptionComments) {
          if (exceptionType == exceptionComment.exceptionType()) {
            exception.comment = exceptionComment.exceptionComment();

            ClassDoc exceptionDetails = exceptionComment.exception();

            // not yet parsing Exceptions defined within the supplied code set
            exception.type = ParseType(exceptionComment.exceptionType());
            break;
          }
        }

        exceptionList.add(exception);
      }

      xmlMethod.exceptions = exceptionList.toArray(new ExceptionInstance[] {});
    }

    // parse annotations from the method
    xmlMethod.annotationInstances =
        ParseAnnotationInstances(docMethod.annotations(), docMethod.qualifiedName());

    return xmlMethod;
  }