/*
   * ************************************************************************
   * EDM Complex Property Name - RULES
   * ************************************************************************
   * The first character of JPA complex attribute name is converted to
   * uppercase. The modified JPA complex attribute name is assigned as EDM
   * complex property name. The unmodified JPA complex attribute name is
   * assigned as internal name.
   * ************************************************************************
   * EDM Complex Property Name - RULES
   * ************************************************************************
   */
  public static void build(
      final JPAEdmComplexPropertyView complexView, final JPAEdmPropertyView propertyView) {

    ComplexProperty complexProperty = complexView.getEdmComplexProperty();

    String jpaAttributeName = propertyView.getJPAAttribute().getName();
    String jpaEntityTypeName = propertyView.getJPAEdmEntityTypeView().getJPAEntityType().getName();

    JPAEdmMappingModelAccess mappingModelAccess = complexView.getJPAEdmMappingModelAccess();
    String propertyName = null;

    if (mappingModelAccess != null && mappingModelAccess.isMappingModelExists()) {
      propertyName = mappingModelAccess.mapJPAAttribute(jpaEntityTypeName, jpaAttributeName);
    }

    if (propertyName == null) {
      propertyName =
          Character.toUpperCase(jpaAttributeName.charAt(0)) + jpaAttributeName.substring(1);
    }
    // change for navigation property issue
    JPAEdmMapping mapping = new JPAEdmMappingImpl();
    ((Mapping) mapping).setInternalName(jpaAttributeName);
    mapping.setJPAType(propertyView.getJPAAttribute().getJavaType());
    complexProperty.setMapping((Mapping) mapping);

    complexProperty.setName(propertyName);
  }
  /*
   * ************************************************************************
   * EDM Property Name - RULES
   * ************************************************************************
   * OData Property Names are represented in Camel Case. The first character
   * of JPA Attribute Name is converted to an UpperCase Character and set as
   * OData Property Name. JPA Attribute Name is set as Internal Name for OData
   * Property. The Column name (annotated as @Column(name="x")) is set as
   * column name in the mapping object.
   * ************************************************************************
   * EDM Property Name - RULES
   * ************************************************************************
   */
  public static void build(final JPAEdmPropertyView view, final boolean isComplexMode) {
    Attribute<?, ?> jpaAttribute = view.getJPAAttribute();
    String jpaAttributeName = jpaAttribute.getName();
    String propertyName = null;

    JPAEdmMappingModelAccess mappingModelAccess = view.getJPAEdmMappingModelAccess();
    if (mappingModelAccess != null && mappingModelAccess.isMappingModelExists()) {
      if (isComplexMode) {
        propertyName =
            mappingModelAccess.mapJPAEmbeddableTypeAttribute(
                view.getJPAEdmComplexTypeView()
                    .getJPAEmbeddableType()
                    .getJavaType()
                    .getSimpleName(),
                jpaAttributeName);
      } else {
        propertyName =
            mappingModelAccess.mapJPAAttribute(
                view.getJPAEdmEntityTypeView().getJPAEntityType().getName(), jpaAttributeName);
      }
    }
    if (propertyName == null) {
      propertyName =
          Character.toUpperCase(jpaAttributeName.charAt(0)) + jpaAttributeName.substring(1);
    }

    view.getEdmSimpleProperty().setName(propertyName);

    JPAEdmMapping mapping = new JPAEdmMappingImpl();
    ((Mapping) mapping).setInternalName(jpaAttributeName);

    AnnotatedElement annotatedElement = (AnnotatedElement) jpaAttribute.getJavaMember();
    if (annotatedElement != null) {
      Column column = annotatedElement.getAnnotation(Column.class);
      if (column != null) {
        mapping.setJPAColumnName(column.name());
      }
    } else {
      ManagedType<?> managedType = jpaAttribute.getDeclaringType();
      if (managedType != null) {
        Class<?> clazz = managedType.getJavaType();
        try {
          Field field = clazz.getDeclaredField(jpaAttributeName);
          Column column = field.getAnnotation(Column.class);
          if (column != null) {
            mapping.setJPAColumnName(column.name());
          }
        } catch (SecurityException e) {

        } catch (NoSuchFieldException e) {

        }
      }
    }
    view.getEdmSimpleProperty().setMapping((Mapping) mapping);
  }
  public static void build(
      final JPAEdmComplexPropertyView complexView, final String parentComplexTypeName) {
    ComplexProperty complexProperty = complexView.getEdmComplexProperty();

    JPAEdmMappingModelAccess mappingModelAccess = complexView.getJPAEdmMappingModelAccess();
    JPAEdmPropertyView propertyView = ((JPAEdmPropertyView) complexView);
    String jpaAttributeName = propertyView.getJPAAttribute().getName();
    String propertyName = null;
    if (mappingModelAccess != null && mappingModelAccess.isMappingModelExists()) {
      propertyName =
          mappingModelAccess.mapJPAEmbeddableTypeAttribute(parentComplexTypeName, jpaAttributeName);
    }
    if (propertyName == null) {
      propertyName =
          Character.toUpperCase(jpaAttributeName.charAt(0)) + jpaAttributeName.substring(1);
    }
    JPAEdmMapping mapping = new JPAEdmMappingImpl();
    ((Mapping) mapping).setInternalName(jpaAttributeName);
    mapping.setJPAType(propertyView.getJPAAttribute().getJavaType());
    complexProperty.setMapping((Mapping) mapping);
    complexProperty.setName(propertyName);
  }
  /*
   * ************************************************************************
   * EDM Association End Name - RULES
   * ************************************************************************
   * Association End name = Namespace + Entity Type Name
   * ************************************************************************
   * EDM Association End Name - RULES
   * ************************************************************************
   */
  public static void build(
      final JPAEdmAssociationEndView assocaitionEndView,
      final JPAEdmEntityTypeView entityTypeView,
      final JPAEdmPropertyView propertyView) {

    String namespace = buildNamespace(assocaitionEndView);

    String name = entityTypeView.getEdmEntityType().getName();
    FullQualifiedName fQName = new FullQualifiedName(namespace, name);
    assocaitionEndView.getEdmAssociationEnd1().setType(fQName);

    name = null;
    String jpaEntityTypeName = null;
    try {

      PluralAttribute<?, ?, ?> jpattr = (PluralAttribute<?, ?, ?>) propertyView.getJPAAttribute();

      jpaEntityTypeName = jpattr.getElementType().getJavaType().getSimpleName();

    } catch (Exception e) {
      jpaEntityTypeName = propertyView.getJPAAttribute().getJavaType().getSimpleName();
    }

    JPAEdmMappingModelAccess mappingModelAccess = assocaitionEndView.getJPAEdmMappingModelAccess();

    if (mappingModelAccess != null && mappingModelAccess.isMappingModelExists()) {
      name = mappingModelAccess.mapJPAEntityType(jpaEntityTypeName);
    }

    if (name == null) {
      name = jpaEntityTypeName;
    }

    fQName = new FullQualifiedName(namespace, name);
    assocaitionEndView.getEdmAssociationEnd2().setType(fQName);
  }
  public static void build(
      final JPAEdmAssociationView associationView,
      final JPAEdmPropertyView propertyView,
      final JPAEdmNavigationPropertyView navPropertyView,
      final int count) {

    String toName = null;
    String fromName = null;
    String navPropName = null;
    NavigationProperty navProp = navPropertyView.getEdmNavigationProperty();
    String namespace = buildNamespace(associationView);

    Association association = associationView.getEdmAssociation();
    navProp.setRelationship(new FullQualifiedName(namespace, association.getName()));

    FullQualifiedName associationEndTypeOne = association.getEnd1().getType();
    FullQualifiedName associationEndTypeTwo = association.getEnd2().getType();

    Attribute<?, ?> jpaAttribute = propertyView.getJPAAttribute();
    navProp.setMapping(new Mapping().setInternalName(jpaAttribute.getName()));

    String jpaEntityTypeName = propertyView.getJPAEdmEntityTypeView().getJPAEntityType().getName();
    JPAEdmMappingModelAccess mappingModelAccess = navPropertyView.getJPAEdmMappingModelAccess();

    try {
      PluralAttribute<?, ?, ?> jpattr = (PluralAttribute<?, ?, ?>) propertyView.getJPAAttribute();

      if (mappingModelAccess != null && mappingModelAccess.isMappingModelExists()) {
        toName =
            mappingModelAccess.mapJPAEntityType(
                jpattr.getElementType().getJavaType().getSimpleName());
        fromName = mappingModelAccess.mapJPAEntityType(jpaEntityTypeName);
        navPropName = mappingModelAccess.mapJPARelationship(jpaEntityTypeName, jpattr.getName());
      }
      if (toName == null) {
        toName = jpattr.getElementType().getJavaType().getSimpleName();
      }
      if (fromName == null) {
        fromName = jpaEntityTypeName;
      }

      if (navPropName == null) {
        navPropName = toName.concat(NAVIGATION_NAME);
      }
      if (count > 1) {
        navPropName = navPropName + Integer.toString(count - 1);
      }
      navProp.setName(navPropName);

      if (toName.equals(associationEndTypeOne.getName())) {
        navProp.setFromRole(association.getEnd2().getRole());
        navProp.setToRole(association.getEnd1().getRole());
      } else if (toName.equals(associationEndTypeTwo.getName())) {
        navProp.setToRole(association.getEnd2().getRole());
        navProp.setFromRole(association.getEnd1().getRole());
      }

    } catch (Exception e) {
      if (mappingModelAccess != null && mappingModelAccess.isMappingModelExists()) {
        navPropName =
            mappingModelAccess.mapJPARelationship(jpaEntityTypeName, jpaAttribute.getName());
        toName = mappingModelAccess.mapJPAEntityType(jpaAttribute.getJavaType().getSimpleName());
        fromName = mappingModelAccess.mapJPAEntityType(jpaEntityTypeName);
      }
      if (toName == null) {
        toName = jpaAttribute.getJavaType().getSimpleName();
      }
      if (fromName == null) {
        fromName = jpaEntityTypeName;
      }

      if (navPropName == null) {
        navPropName = toName.concat(NAVIGATION_NAME);
      }
      if (count > 1) {
        navPropName = navPropName + Integer.toString(count - 1);
      }
      navProp.setName(navPropName);

      if (toName.equals(associationEndTypeOne.getName())) {
        navProp.setFromRole(association.getEnd2().getRole());
        navProp.setToRole(association.getEnd1().getRole());
      } else if (toName.equals(associationEndTypeTwo.getName())) {

        navProp.setToRole(association.getEnd2().getRole());
        navProp.setFromRole(association.getEnd1().getRole());
      }
    }
  }