/**
   * This method determines whether or not an asset has different object sub type codes in its
   * documents.
   *
   * @return true when the asset has payments with object codes that point to different object sub
   *     type codes
   */
  public boolean hasDifferentObjectSubTypes(AssetPaymentDocument document) {
    List<String> subTypes = new ArrayList<String>();
    subTypes =
        new ArrayList<String>(
            SpringContext.getBean(ParameterService.class)
                .getParameterValuesAsString(
                    Asset.class, CamsConstants.Parameters.OBJECT_SUB_TYPE_GROUPS));

    List<AssetPaymentDetail> assetPaymentDetails = document.getSourceAccountingLines();
    List<String> validObjectSubTypes = new ArrayList<String>();

    String objectSubTypeCode = null;

    /*
     * Expected system parameter elements (object sub types). [BD,BF] [CM,CF,CO] [UC,UF,UO] [LI,LF]
     */

    // Getting the list of object sub type codes from the asset payments on the jsp.
    List<String> objectSubTypeList = new ArrayList<String>();
    for (AssetPaymentDetail assetPaymentDetail : assetPaymentDetails) {
      assetPaymentDetail.refreshReferenceObject(
          CamsPropertyConstants.AssetPaymentDetail.OBJECT_CODE);
      if (ObjectUtils.isNull(assetPaymentDetail.getObjectCode())) {
        return false;
      }
      objectSubTypeList.add(assetPaymentDetail.getObjectCode().getFinancialObjectSubTypeCode());
    }

    if (!SpringContext.getBean(AssetService.class).isObjectSubTypeCompatible(objectSubTypeList)) {
      return true;
    }

    List<AssetPaymentAssetDetail> assetPaymentAssetDetails = document.getAssetPaymentAssetDetail();
    for (AssetPaymentAssetDetail assetPaymentAssetDetail : assetPaymentAssetDetails) {
      assetPaymentAssetDetail
          .getAsset()
          .refreshReferenceObject(CamsPropertyConstants.Asset.ASSET_PAYMENTS);
      List<AssetPayment> assetPayments = assetPaymentAssetDetail.getAsset().getAssetPayments();

      // Comparing against the already approved asset payments
      if (!assetPayments.isEmpty()) {
        for (AssetPayment assetPayment : assetPayments) {
          String paymentSubObjectType =
              assetPayment.getFinancialObject().getFinancialObjectSubTypeCode();

          validObjectSubTypes = new ArrayList<String>();
          for (String subType : subTypes) {
            validObjectSubTypes = Arrays.asList(StringUtils.split(subType, ","));
            if (validObjectSubTypes.contains(paymentSubObjectType)) {
              break;
            }
            validObjectSubTypes = new ArrayList<String>();
          }
          if (validObjectSubTypes.isEmpty()) validObjectSubTypes.add(paymentSubObjectType);

          // Comparing the same asset payment document
          for (AssetPaymentDetail assetPaymentDetail : assetPaymentDetails) {
            if (!validObjectSubTypes.contains(
                assetPaymentDetail.getObjectCode().getFinancialObjectSubTypeCode())) {
              // Differences where found.
              return true;
            }
          }
        }
      }
    }
    // If none object sub types are different...
    return false;
  }
  /**
   * Creates a new asset payment record for each new asset payment detail record and then save them
   *
   * @param document
   */
  protected void processPayments(AssetPaymentDocument document) {
    List<AssetPaymentDetail> assetPaymentDetailLines = document.getSourceAccountingLines();
    List<AssetPaymentAssetDetail> assetPaymentAssetDetails = document.getAssetPaymentAssetDetail();
    List<PersistableBusinessObject> assetPayments = new ArrayList<PersistableBusinessObject>();
    Integer maxSequenceNo = new Integer(0);

    // instantiate asset payment distributor
    AssetDistribution paymentDistributor = document.getAssetPaymentDistributor();

    // Calculating the asset payments distributions for each individual asset on the list
    Map<String, Map<AssetPaymentAssetDetail, KualiDecimal>> assetPaymentDistributionMap =
        paymentDistributor.getAssetPaymentDistributions();

    try {
      // Creating a new payment record for each asset that has payments.
      for (AssetPaymentAssetDetail assetPaymentAssetDetail : assetPaymentAssetDetails) {

        maxSequenceNo = getMaxSequenceNumber(assetPaymentAssetDetail.getCapitalAssetNumber());

        KualiDecimal totalAmount = KualiDecimal.ZERO;
        for (AssetPaymentDetail assetPaymentDetail : assetPaymentDetailLines) {

          // Retrieve the asset payment from the distribution map
          KualiDecimal amount =
              assetPaymentDistributionMap
                  .get(assetPaymentDetail.getAssetPaymentDetailKey())
                  .get(assetPaymentAssetDetail);
          totalAmount = totalAmount.add(amount);

          AssetPayment assetPayment = new AssetPayment(assetPaymentDetail);
          assetPayment.setCapitalAssetNumber(assetPaymentAssetDetail.getCapitalAssetNumber());
          assetPayment.setTransferPaymentCode(CamsConstants.AssetPayment.TRANSFER_PAYMENT_CODE_N);
          assetPayment.setPaymentSequenceNumber(++maxSequenceNo);
          if (StringUtils.isBlank(assetPayment.getDocumentNumber())) {
            assetPayment.setDocumentNumber(document.getDocumentNumber());
          }
          assetPayment.setAccountChargeAmount(amount);

          KualiDecimal baseAmount = KualiDecimal.ZERO;

          // If the object sub type is not in the list of federally owned object sub types, then...
          ObjectCode objectCode =
              this.getObjectCodeService()
                  .getByPrimaryId(
                      assetPaymentDetail.getPostingYear(),
                      assetPaymentDetail.getChartOfAccountsCode(),
                      assetPaymentDetail.getFinancialObjectCode());

          // Depreciation Base Amount will be assigned to each payment only when the object code's
          // sub type code is not a
          // federally owned one
          if (!this.isNonDepreciableFederallyOwnedObjSubType(
              objectCode.getFinancialObjectSubTypeCode())) {
            baseAmount = baseAmount.add(amount);
          }
          assetPayment.setPrimaryDepreciationBaseAmount(baseAmount);

          // Resetting each period field its value with nulls
          this.adjustPaymentAmounts(assetPayment, false, true);

          // add new payment
          assetPayments.add(assetPayment);
        }
        // *********************BEGIN - Updating Asset
        // ***********************************************************
        // Retrieving the asset that will have its cost updated
        HashMap<String, Long> keys = new HashMap<String, Long>();
        keys.put(
            CamsPropertyConstants.Asset.CAPITAL_ASSET_NUMBER,
            assetPaymentAssetDetail.getCapitalAssetNumber());
        Asset asset = (Asset) getBusinessObjectService().findByPrimaryKey(Asset.class, keys);

        // Set previous total cost
        if (assetPaymentAssetDetail.getPreviousTotalCostAmount() == null) {
          assetPaymentAssetDetail.setPreviousTotalCostAmount(new KualiDecimal(0));
        }

        // Setting the asset's new cost.
        asset.setTotalCostAmount(
            assetPaymentAssetDetail.getPreviousTotalCostAmount().add(totalAmount));

        // Setting the asset's financial object sub-type Code. Only when the asset doesn't have one.
        if (asset.getFinancialObjectSubTypeCode() == null
            || asset.getFinancialObjectSubTypeCode().trim().equals("")) {
          asset.setFinancialObjectSubTypeCode(
              assetPaymentDetailLines.get(0).getObjectCode().getFinancialObjectSubTypeCode());
        }
        // Saving changes
        getBusinessObjectService().save(asset);
        // *********************END - Updating Asset
        // ***********************************************************
      }
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    // Finally, saving all the asset payment records.
    this.getBusinessObjectService().save(assetPayments);
  }