/**
   * 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;
  }
  /**
   * Sets the properties to values of other indexed property pattern. If the properties change fires
   * PropertyChange event.
   *
   * @param src Source IdxPropertyPattern it's properties will be copied.
   */
  void copyProperties(IdxPropertyPattern src) {

    boolean changed =
        !src.getIndexedType().equals(getIndexedType())
            || !(src.getType() == null ? getType() == null : src.getType().equals(getType()))
            || !src.getName().equals(getName())
            || !(src.getMode() == getMode())
            || !(src.getEstimatedField() == null
                ? estimatedField == null
                : src.getEstimatedField().equals(estimatedField));

    if (src.getIndexedGetterMethod() != indexedGetterMethod)
      indexedGetterMethod = src.getIndexedGetterMethod();
    if (src.getIndexedSetterMethod() != indexedSetterMethod)
      indexedSetterMethod = src.getIndexedSetterMethod();

    if (src.getGetterMethod() != getterMethod) {
      changed = true;
      getterMethod = src.getGetterMethod();
    }
    if (src.getSetterMethod() != setterMethod) {
      changed = true;
      setterMethod = src.getSetterMethod();
    }
    if (src.getEstimatedField() != estimatedField) estimatedField = src.getEstimatedField();

    if (changed) {
      try {
        type = findPropertyType();
        findIndexedPropertyType();
      } catch (java.beans.IntrospectionException e) {
        // User's error
      }
      name = findIndexedPropertyName();

      firePropertyChange(new java.beans.PropertyChangeEvent(this, null, null, null));
    }
  }
  /**
   * 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;
  }