/**
   * Checks if a type is derived from another by any combination of restriction, list ir union. See:
   * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#TypeInfo-isDerivedFrom
   *
   * @param ancestorNS The namspace of the ancestor type declaration
   * @param ancestorName The name of the ancestor type declaration
   * @param derivationMethod A short indication the method of derivation
   * @param type The reference type definition
   * @return boolean True if the type is derived by any method for the reference type
   */
  private boolean isDerivedByAny(
      String ancestorNS, String ancestorName, int derivationMethod, XSTypeDefinition type) {
    XSTypeDefinition oldType = null;
    boolean derivedFrom = false;
    while (type != null && type != oldType) {

      // If the ancestor type is reached or is the same as this type.
      if ((ancestorName.equals(type.getName()))
          && ((ancestorNS == null && type.getNamespace() == null)
              || (ancestorNS != null && ancestorNS.equals(type.getNamespace())))) {
        derivedFrom = true;
        break;
      }

      // Check if this type is derived from the base by restriction or
      // extension
      if (isDerivedByRestriction(ancestorNS, ancestorName, derivationMethod, type)) {
        return true;
      } else if (!isDerivedByExtension(ancestorNS, ancestorName, derivationMethod, type)) {
        return true;
      }
      oldType = type;
      type = type.getBaseType();
    }

    return derivedFrom;
  }
  /**
   * Checks if a type is derived from another by extension. See:
   * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#TypeInfo-isDerivedFrom
   *
   * @param ancestorNS The namspace of the ancestor type declaration
   * @param ancestorName The name of the ancestor type declaration
   * @param derivationMethod A short indication the method of derivation
   * @param type The reference type definition
   * @return boolean True if the type is derived by extension for the reference type
   */
  private boolean isDerivedByExtension(
      String ancestorNS, String ancestorName, int derivationMethod, XSTypeDefinition type) {

    boolean extension = false;
    XSTypeDefinition oldType = null;
    while (type != null && type != oldType) {
      // If ancestor is anySimpleType return false.
      if (ancestorNS != null
          && ancestorNS.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA)
          && ancestorName.equals(SchemaSymbols.ATTVAL_ANYSIMPLETYPE)
          && SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(type.getNamespace())
          && SchemaSymbols.ATTVAL_ANYTYPE.equals(type.getName())) {
        break;
      }

      if ((ancestorName.equals(type.getName()))
          && ((ancestorNS == null && type.getNamespace() == null)
              || (ancestorNS != null && ancestorNS.equals(type.getNamespace())))) {
        // returns true if atleast one derivation step was extension
        return extension;
      }

      // If the base type is a complexType with simpleContent
      if (type instanceof XSSimpleTypeDecl) {
        if (ancestorNS.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA)
            && ancestorName.equals(SchemaSymbols.ATTVAL_ANYTYPE)) {
          ancestorName = SchemaSymbols.ATTVAL_ANYSIMPLETYPE;
        }

        // derivationMethod extension will always return false for a
        // simpleType,
        // we treat it like a restriction
        if ((derivationMethod & DERIVATION_EXTENSION) != 0) {
          return extension
              & ((XSSimpleTypeDecl) type)
                  .isDOMDerivedFrom(
                      ancestorNS, ancestorName, (derivationMethod & DERIVATION_RESTRICTION));
        } else {
          return extension
              & ((XSSimpleTypeDecl) type)
                  .isDOMDerivedFrom(ancestorNS, ancestorName, derivationMethod);
        }

      } else {
        // If the base type is a complex type
        // At least one derivation step upto the ancestor type should be
        // extension.
        if (((XSComplexTypeDecl) type).getDerivationMethod() == XSConstants.DERIVATION_EXTENSION) {
          extension = extension | true;
        }
      }
      oldType = type;
      type = type.getBaseType();
    }

    return false;
  }
  /**
   * Checks if a type is derived from another by restriction. See:
   * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#TypeInfo-isDerivedFrom
   *
   * @param ancestorNS The namspace of the ancestor type declaration
   * @param ancestorName The name of the ancestor type declaration
   * @param derivationMethod A short indication the method of derivation *
   * @param type The reference type definition
   * @return boolean True if the type is derived by restriciton for the reference type
   */
  private boolean isDerivedByRestriction(
      String ancestorNS, String ancestorName, int derivationMethod, XSTypeDefinition type) {

    XSTypeDefinition oldType = null;
    while (type != null && type != oldType) {

      // ancestor is anySimpleType, return false
      if (ancestorNS != null
          && ancestorNS.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA)
          && ancestorName.equals(SchemaSymbols.ATTVAL_ANYSIMPLETYPE)) {
        return false;
      }

      // if the name and namespace of this type is the same as the
      // ancestor return true
      if ((ancestorName.equals(type.getName()))
              && (ancestorNS != null && ancestorNS.equals(type.getNamespace()))
          || ((type.getNamespace() == null && ancestorNS == null))) {

        return true;
      }

      // If the base type is a complexType with simpleContent
      if (type instanceof XSSimpleTypeDecl) {
        if (ancestorNS.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA)
            && ancestorName.equals(SchemaSymbols.ATTVAL_ANYTYPE)) {
          ancestorName = SchemaSymbols.ATTVAL_ANYSIMPLETYPE;
        }
        return ((XSSimpleTypeDecl) type)
            .isDOMDerivedFrom(ancestorNS, ancestorName, derivationMethod);
      } else {
        // If the base type is a complex type
        // Every derivation step till the base type should be
        // restriction. If not return false
        if (((XSComplexTypeDecl) type).getDerivationMethod()
            != XSConstants.DERIVATION_RESTRICTION) {
          return false;
        }
      }
      oldType = type;
      type = type.getBaseType();
    }

    return false;
  }
  public boolean derivedFrom(String ancestorNS, String ancestorName, short derivationMethod) {
    // ancestor is null, retur false
    if (ancestorName == null) return false;
    // ancestor is anyType, return true
    if (ancestorNS != null
        && ancestorNS.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA)
        && ancestorName.equals(SchemaSymbols.ATTVAL_ANYTYPE)) {
      return true;
    }

    // recursively get base, and compare it with ancestor
    XSTypeDefinition type = this;
    while (!(ancestorName.equals(type.getName())
            && ((ancestorNS == null && type.getNamespace() == null)
                || (ancestorNS != null && ancestorNS.equals(type.getNamespace()))))
        && // compare with ancestor
        type != SchemaGrammar.fAnySimpleType
        && // reached anySimpleType
        type != SchemaGrammar.fAnyType) { // reached anyType
      type = (XSTypeDefinition) type.getBaseType();
    }

    return type != SchemaGrammar.fAnySimpleType && type != SchemaGrammar.fAnyType;
  }