/**
   * Sets the indexed type of IdxPropertyPattern
   *
   * @param type New indexed type of the indexed property
   * @throws SourceException If the modification of source code is impossible
   */
  public void setIndexedType(Type type) throws SourceException {

    if (this.indexedType.compareTo(type, true)) return;

    // Remember the old type & old indexed type
    Type oldIndexedType = this.indexedType;
    Type oldType = this.type;

    // Change the indexed type
    if (indexedGetterMethod != null) {
      indexedGetterMethod.setReturn(type);
    }
    if (indexedSetterMethod != null) {
      MethodParameter[] params = indexedSetterMethod.getParameters();
      if (params.length > 1) {
        params[1].setType(type);
        indexedSetterMethod.setParameters(params);
      }
    }

    // Test if the old type of getter and seter was an array of indexedType
    // if so change the type of that array.
    if (oldType != null
        && oldType.isArray()
        && oldType.getElementType().compareTo(oldIndexedType, false)) {
      Type newArrayType = Type.createArray(type);
      super.setType(newArrayType);
    }

    indexedType = type;
  }
  /**
   * Creates new IdxPropertyPattern.
   *
   * @param patternAnalyser patternAnalyser which creates this Property.
   * @param name Name of the Property.
   * @param type Type of the Property ( i.e. Array or Collection )
   * @param indexedType Indexed type of the property.
   * @throws SourceException If the Property can't be created in the source.
   * @return Newly created IdxPropertyPattern.
   */
  static IdxPropertyPattern create(
      PatternAnalyser patternAnalyser, String name, String type, String indexedType)
      throws SourceException {

    IdxPropertyPattern ipp = new IdxPropertyPattern(patternAnalyser);

    ipp.name = name;
    ipp.type = Type.parse(type);
    ipp.indexedType = Type.parse(indexedType);

    ipp.generateGetterMethod();
    ipp.generateSetterMethod();
    ipp.generateIndexedGetterMethod();
    ipp.generateIndexedSetterMethod();

    return ipp;
  }
  /**
   * Resolves the indexed type of the property from type of getter and setter. Chcecks for
   * conformance to Beans design patterns.
   *
   * @throws IntrospectionException if the property doesnt folow the design patterns
   */
  private void findIndexedPropertyType() throws IntrospectionException {

    indexedType = null;

    if (indexedGetterMethod != null) {
      MethodParameter[] params = indexedGetterMethod.getParameters();
      if (params.length != 1) {
        throw new IntrospectionException("bad indexed read method arg count"); // NOI18N
      }
      if (!params[0].getType().compareTo(Type.INT, false)) {
        throw new IntrospectionException("not int index to indexed read method"); // NOI18N
      }
      indexedType = indexedGetterMethod.getReturn();
      if (indexedType.compareTo(Type.VOID, false)) {
        throw new IntrospectionException("indexed read method return void"); // NOI18N
      }
    }

    if (indexedSetterMethod != null) {
      MethodParameter params[] = indexedSetterMethod.getParameters();
      if (params.length != 2) {
        throw new IntrospectionException("bad indexed write method arg count"); // NOI18N
      }
      if (!params[0].getType().compareTo(Type.INT, false)) {
        throw new IntrospectionException("non int index to indexed write method"); // NOI18N
      }
      if (indexedType != null && !indexedType.compareTo(params[1].getType(), false)) {
        throw new IntrospectionException(
            "type mismatch between indexed read and write methods"); // NOI18N
      }
      indexedType = params[1].getType();
    }

    // type = indexedType;

    Type propType = getType();
    if (propType != null
        && (!propType.isArray() || !propType.getElementType().compareTo(indexedType, false))) {
      throw new IntrospectionException(
          "type mismatch between property type and indexed type"); // NOI18N
    }
  }
  /**
   * Sets the non-indexed type of IdxPropertyPattern
   *
   * @param type New non-indexed type of the indexed property
   * @throws SourceException If the modification of source code is impossible
   */
  public void setType(Type type) throws SourceException {

    if (this.type != null && this.type.compareTo(type, true)) return;

    // Remember the old type & old indexed type
    Type oldIndexedType = this.indexedType;
    Type oldType = this.type;

    if (oldType == null) {
      this.type = type;
      oldType = type;
      int mode = getMode();
      if (mode == READ_WRITE || mode == READ_ONLY) generateGetterMethod();
      if (mode == READ_WRITE || mode == WRITE_ONLY) generateSetterMethod();
    } else
      // Change the type
      super.setType(type);

    // Test if the idexedType is the type of array and change it if so
    if (type.isArray()
        && oldType.isArray()
        && oldType.getElementType().compareTo(oldIndexedType, false)) {
      Type newType = type.getElementType();

      if (indexedGetterMethod != null) {
        indexedGetterMethod.setReturn(newType);
      }
      if (indexedSetterMethod != null) {
        MethodParameter[] params = indexedSetterMethod.getParameters();
        if (params.length > 1) {
          params[1].setType(newType);
          indexedSetterMethod.setParameters(params);
        }
      }

      // Set the type  to new type
      setIndexedType(newType);
    }
  }
  /**
   * Creates new indexed property pattern with extended options
   *
   * @param patternAnalyser patternAnalyser which creates this Property.
   * @param name Name of the Property.
   * @param type Type of the Property.
   * @param mode {@link #READ_WRITE Mode} of the new property.
   * @param bound Is the Property bound?
   * @param constrained Is the property constrained?
   * @param withField Should be the private field for this property genareted?
   * @param withReturn Generate return statement in getter?
   * @param withSet Generate seter statement for private field in setter.
   * @param withSupport Generate PropertyChange support?
   * @param niGetter Non-indexed getter method
   * @param niWithReturn Generate return statement in non-indexed getter?
   * @param niSetter Non-indexed setter method
   * @param niWithSet Generate set field statement in non-indexed setter?
   * @throws SourceException If the Property can't be created in the source.
   * @return Newly created PropertyPattern.
   */
  static IdxPropertyPattern create(
      PatternAnalyser patternAnalyser,
      String name,
      String type,
      int mode,
      boolean bound,
      boolean constrained,
      boolean withField,
      boolean withReturn,
      boolean withSet,
      boolean withSupport,
      boolean niGetter,
      boolean niWithReturn,
      boolean niSetter,
      boolean niWithSet)
      throws SourceException {

    IdxPropertyPattern ipp = new IdxPropertyPattern(patternAnalyser);

    ipp.name = name;
    ipp.type = null;
    ipp.indexedType = Type.parse(type);

    // Set the non-indexed type when needed
    if (withField || withSupport || niGetter || niSetter) {
      ipp.type = Type.createArray(ipp.indexedType);
    }

    // Generate field
    if (withField || withSupport) {
      if (ipp.type != null) ipp.generateField(true);
    }

    // Ensure property change support field and methods exist
    String supportName = null;
    String vetoSupportName = null;

    if (withSupport) {
      if (bound) supportName = BeanPatternGenerator.supportField(ipp.getDeclaringClass());
      if (constrained)
        vetoSupportName = BeanPatternGenerator.vetoSupportField(ipp.getDeclaringClass());

      if (bound) BeanPatternGenerator.supportListenerMethods(ipp.getDeclaringClass(), supportName);
      if (constrained)
        BeanPatternGenerator.vetoSupportListenerMethods(ipp.getDeclaringClass(), vetoSupportName);
    }

    if (mode == READ_WRITE || mode == READ_ONLY) {
      ipp.generateIndexedGetterMethod(
          BeanPatternGenerator.idxPropertyGetterBody(name, withReturn), true);
      if (ipp.type != null && niGetter)
        ipp.generateGetterMethod(BeanPatternGenerator.propertyGetterBody(name, niWithReturn), true);
    }
    if (mode == READ_WRITE || mode == WRITE_ONLY) {
      /*
      ipp.generateIndexedSetterMethod( BeanPatternGenerator.idxPropertySetterBody( name, ipp.getType(),
          bound, constrained, withSet, withSupport, supportName, vetoSupportName ), constrained, true );
      */
      ipp.generateIndexedSetterMethod(
          BeanPatternGenerator.idxPropertySetterBody(
              name,
              ipp.getIndexedType(),
              bound,
              constrained,
              withSet,
              withSupport,
              supportName,
              vetoSupportName),
          constrained,
          true);

      if (ipp.type != null && niSetter)
        ipp.generateSetterMethod(
            BeanPatternGenerator.propertySetterBody(
                name,
                ipp.getType(),
                bound,
                constrained,
                niWithSet,
                withSupport,
                supportName,
                vetoSupportName),
            constrained,
            true);
    }
    return ipp;
  }