/**
   * Creates a {@link Property} instance and sets its required values and adds it to the current
   * list of {@link Property} instances held by the specified <code>entityPropertiesWrapper</code>
   * for a given {@link Entity}
   *
   * @param propertyCategory the type of property to be created i.e. a collection type property, a
   *     property with simple annotations or an Id property for a non-primary entity in case of
   *     One-To-One relation.
   * @param propertyName the property name to set
   * @param propertyType the fully qualified type name of the property.
   * @param relationType the {@link RelationType} enum value
   * @param jpaAnnotationTypesArr an array of {@link String} holding the types of JPA annotation(s)
   *     to be added to the property
   * @param genericTypeParameter the parameterised type of generic collection type if the property
   *     to be created is a collection type property
   * @param mappedBy if the specified <code>relationType</code> is
   *     <ul>
   *       <li>{@link RelationType#ONE_TO_MANY} and is marked as bidirectional then this parameter
   *           holds value for the <i>mappedBy<i> attribute of the relationship annotation i.e.
   *           {@link OneToMany} on the entity specified at "one" end of the relation in
   *           <i>relations definition XML</i>
   *       <li>{@link RelationType#ONE_TO_ONE} then this parameter holds value for the
   *           <i>mappedBy<i> attribute of the relationship annotation i.e. {@link OneToOne} on the
   *           entity specified at "many" end of the relation in <i>relations definition XML</i>
   *     </ul>
   *
   * @param oneToOnePrimaryEntityPropertyName if the specified <code>relationType</code> is {@link
   *     RelationType#ONE_TO_ONE} then this parameter holds the {@link GenericGenerator}'s {@link
   *     Parameter} annotation's {@link Parameter#value()} attribute's value
   * @param entityPropertiesWrapper the {@link Properties} instance of a given entity
   * @param addTypesFullNameShortName var-args of type {@link String} holding the property type(s)
   *     to be added to {@link PropertyTypeName} for creating a short name of the type against the
   *     fully qualified type name
   */
  private void createAndAddProperty(
      int propertyCategory,
      String propertyName,
      String propertyType,
      RelationType relationType,
      String[] jpaAnnotationTypesArr,
      String genericTypeParameter,
      String mappedBy,
      String oneToOnePrimaryEntityPropertyName,
      Properties entityPropertiesWrapper,
      String... addTypesFullNameShortName) {

    Property newProperty = null;

    if (CREATE_COLLECTION_TYPE_PROPERTY == propertyCategory) {

      newProperty =
          createCollectionProperty(
              propertyName,
              propertyType,
              relationType,
              jpaAnnotationTypesArr,
              genericTypeParameter,
              mappedBy);

    } else if (CREATE_PROPERTY == propertyCategory) {

      newProperty =
          createProperty(
              propertyName, propertyType,
              relationType, jpaAnnotationTypesArr);

      if (mappedBy != null) {
        newProperty.setMappedBy(mappedBy);
      }

    } else if (CREATE_ONE_TO_ONE_RELATED_NON_PRIMARY_ENTITY_ID_PROPERTY == propertyCategory) {

      newProperty =
          createOneToOneRelatedNonPrimaryEntityIdProperty(
              propertyName, propertyType, jpaAnnotationTypesArr, oneToOnePrimaryEntityPropertyName);
    }

    addNewPropertyToCurrentPropertyList(entityPropertiesWrapper, newProperty);

    addPropertyTypesName(addTypesFullNameShortName);
  }
  /**
   * Adds the specified <code>newProperty</code> to the specified <code>entityPropertiesWrapper
   * </code>.
   *
   * @param entityPropertiesWrapper the {@link Properties} instance of a given entity
   * @param newProperty the {@link Property} instance to be added to the specified <code>
   *     entityPropertiesWrapper</code>
   */
  private void addNewPropertyToCurrentPropertyList(
      Properties entityPropertiesWrapper, Property newProperty) {

    if (newProperty.isId()) {
      // Id Property should be first in the properties list
      entityPropertiesWrapper.getProperties().add(0, newProperty);
    } else {
      entityPropertiesWrapper.getProperties().add(newProperty);
    }
  }
  /**
   * @param propertyName the property name to set
   * @param propertyTypeFullyQualifiedName the fully qualified type name of the property.
   * @param propertyRelationType the {@link RelationType} enum value
   * @param jpaAnnotationTypes an array of {@link String} holding the types of JPA annotation(s) to
   *     be added to the property
   * @param isIdProperty a boolean value <code>true</code> indicating the property to be created is
   *     Id type property, <code>false</code> otherwise.
   * @param idAnnotationType the {@link IdAnnotationType} enum value
   * @param oneToOnePrimaryEntityPropertyName if the specified <code>relationType</code> is {@link
   *     RelationType#ONE_TO_ONE} then this parameter holds the {@link GenericGenerator}'s {@link
   *     Parameter} annotation's {@link Parameter#value()} attribute's value
   * @param isPropertyTypeGeneric a boolean value <code>true</code> indicating the property to be
   *     created is of a generic type, <code>false</code> otherwise.
   * @param genericTypeParameter the parameterised type of generic collection type if the property
   *     to be created is a collection type property
   * @param mappedBy if the specified <code>propertyRelationType</code> is
   *     <ul>
   *       <li>{@link RelationType#ONE_TO_MANY} and is marked as bidirectional then this parameter
   *           holds value for the <i>mappedBy<i> attribute of the relationship annotation i.e.
   *           {@link OneToMany} on the entity specified at "one" end of the relation in
   *           <i>relations definition XML</i>
   *       <li>{@link RelationType#ONE_TO_ONE} then this parameter holds value for the
   *           <i>mappedBy<i> attribute of the relationship annotation i.e. {@link OneToOne} on the
   *           entity specified at "many" end of the relation in <i>relations definition XML</i>
   *     </ul>
   *
   * @return the {@link Property} instance whose properties are set to values held by the arguments
   *     to this method.
   */
  private Property createProperty(
      String propertyName,
      String propertyTypeFullyQualifiedName,
      RelationType propertyRelationType,
      String[] jpaAnnotationTypes,
      boolean isIdProperty,
      IdAnnotationType idAnnotationType,
      String oneToOnePrimaryEntityPropertyName,
      boolean isPropertyTypeGeneric,
      String genericTypeParameter,
      String mappedBy) {

    Property property = new Property();
    property.setName(propertyName);
    property.setType(propertyTypeFullyQualifiedName);
    property.setRelationType(propertyRelationType);
    property.setJpaAnnotationTypes(jpaAnnotationTypes);
    property.setMappedBy(mappedBy);

    if (isPropertyTypeGeneric) {
      property.setGenericType(isPropertyTypeGeneric);
      property.setGenericTypeParameter(genericTypeParameter);
    }

    if (isIdProperty) {
      property.setId(isIdProperty);
      property.setIdAnnotationType(idAnnotationType);

      if (IdAnnotationType.ONE_TO_ONE == idAnnotationType) {
        property.setOneToOnePrimaryEntityPropertyName(oneToOnePrimaryEntityPropertyName);
      }
    }

    return property;
  }