/**
   * Validates that the existance of the building room number is consistent with the asset type
   * requirements.
   *
   * @param roomNumber
   * @param detail
   * @prarm asset
   * @return boolean
   * @deprecated this method is replaced by
   *     validateBuildingCodeAndRoomNumber(BarcodeInventoryErrorDetail, Asset)
   */
  @Deprecated
  protected boolean validateBuildingRoomNumber(
      String roomNumber, BarcodeInventoryErrorDetail detail, Asset asset) {
    boolean result = true;
    String label =
        SpringContext.getBean(DataDictionaryService.class)
            .getDataDictionary()
            .getBusinessObjectEntry(BarcodeInventoryErrorDetail.class.getName())
            .getAttributeDefinition(CamsPropertyConstants.BarcodeInventory.BUILDING_ROOM_NUMBER)
            .getLabel();
    // String description = asset.getCapitalAssetType().getCapitalAssetTypeDescription();
    String description = asset.getCapitalAssetTypeCode();

    // if the asset has empty building room number, then the BCIE should too
    if (StringUtils.isBlank(asset.getBuildingRoomNumber())) {
      if (StringUtils.isNotBlank(roomNumber)) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_ROOM_NUMBER,
                CamsKeyConstants.BarcodeInventory.ERROR_NOT_ALLOWED_FIELD,
                label,
                description);
        result &= false;
      }
    }
    // otherwise the BCIE should have a non-empty and existing active building room number
    else {
      HashMap<String, Object> fields = new HashMap<String, Object>();
      fields.put(KFSPropertyConstants.CAMPUS_CODE, detail.getCampusCode());
      fields.put(KFSPropertyConstants.BUILDING_CODE, detail.getBuildingCode());
      fields.put(KFSPropertyConstants.BUILDING_ROOM_NUMBER, detail.getBuildingRoomNumber());
      Room room = getBusinessObjectService().findByPrimaryKey(Room.class, fields);

      if (StringUtils.isBlank(roomNumber)) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_ROOM_NUMBER,
                CamsKeyConstants.BarcodeInventory.ERROR_REQUIRED_FIELD,
                label,
                description);
        result &= false;
      } else if (ObjectUtils.isNull(room)) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_ROOM_NUMBER,
                CamsKeyConstants.BarcodeInventory.ERROR_INVALID_FIELD,
                label);
        result = false;
      } else if (!room.isActive()) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_ROOM_NUMBER,
                CamsKeyConstants.BarcodeInventory.ERROR_INACTIVE_FIELD,
                label);
        result &= false;
      }
    }

    return result;
  }
  protected HtmlData getViewAssetUrl(Asset asset) {
    Properties parameters = new Properties();
    parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.START_METHOD);
    parameters.put(
        CamsPropertyConstants.Asset.CAPITAL_ASSET_NUMBER, asset.getCapitalAssetNumber().toString());
    parameters.put(
        KFSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, CapitalAssetManagementAsset.class.getName());

    String href = UrlFactory.parameterizeUrl(CamsConstants.INQUIRY_URL, parameters);

    AnchorHtmlData anchorHtmlData =
        new AnchorHtmlData(href, KFSConstants.START_METHOD, CamsConstants.AssetActions.VIEW);
    anchorHtmlData.setTarget("blank");
    return anchorHtmlData;
  }
  /**
   * @see
   *     org.kuali.kfs.module.cam.document.service.AssetPaymentService#validateAssets(java.lang.String,
   *     org.kuali.kfs.module.cam.businessobject.Asset)
   */
  public boolean validateAssets(String errorPath, Asset asset) {
    boolean valid = true;

    // Validating the asset is a capital asset
    if (!this.getAssetService().isCapitalAsset(asset)) {
      GlobalVariables.getMessageMap()
          .putError(
              errorPath,
              CamsKeyConstants.Payment.ERROR_NON_CAPITAL_ASSET,
              asset.getCapitalAssetNumber().toString());
      valid &= false;
    }

    // Validating the asset hasn't been retired
    if (this.getAssetService().isAssetRetired(asset)) {
      GlobalVariables.getMessageMap()
          .putError(
              errorPath,
              CamsKeyConstants.Retirement.ERROR_NON_ACTIVE_ASSET_RETIREMENT,
              asset.getCapitalAssetNumber().toString());
      valid &= false;
    }
    return valid;
  }
  protected Properties getSeparateParameters(Asset asset) {
    Properties parameters = new Properties();
    parameters.put(
        KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.MAINTENANCE_NEW_METHOD_TO_CALL);
    parameters.put(KFSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, AssetGlobal.class.getName());
    parameters.put(
        CamsPropertyConstants.AssetGlobal.SEPARATE_SOURCE_CAPITAL_ASSET_NUMBER,
        asset.getCapitalAssetNumber().toString());
    // parameter that tells us this is a separate action. We read this in
    // AssetMaintenanbleImpl.processAfterNew
    parameters.put(
        KFSPropertyConstants.FINANCIAL_DOCUMENT_TYPE_CODE,
        CamsConstants.PaymentDocumentTypeCodes.ASSET_GLOBAL_SEPARATE);

    return parameters;
  }
  protected HtmlData getMergeUrl(Asset asset) {
    FinancialSystemMaintenanceDocumentAuthorizerBase documentAuthorizer =
        (FinancialSystemMaintenanceDocumentAuthorizerBase)
            SpringContext.getBean(DocumentDictionaryService.class)
                .getDocumentAuthorizer(CamsConstants.DocumentTypeName.ASSET_RETIREMENT_GLOBAL);
    boolean isAuthorized =
        documentAuthorizer.isAuthorized(
            asset,
            CamsConstants.CAM_MODULE_CODE,
            CamsConstants.PermissionNames.MERGE,
            GlobalVariables.getUserSession().getPerson().getPrincipalId());

    if (isAuthorized) {
      Properties parameters = new Properties();
      parameters.put(
          KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.MAINTENANCE_NEWWITHEXISTING_ACTION);
      parameters.put(
          KFSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, AssetRetirementGlobal.class.getName());
      parameters.put(
          CamsPropertyConstants.AssetRetirementGlobal.MERGED_TARGET_CAPITAL_ASSET_NUMBER,
          asset.getCapitalAssetNumber().toString());
      parameters.put(
          KFSConstants.OVERRIDE_KEYS,
          CamsPropertyConstants.AssetRetirementGlobal.RETIREMENT_REASON_CODE
              + KFSConstants.FIELD_CONVERSIONS_SEPERATOR
              + CamsPropertyConstants.AssetRetirementGlobal.MERGED_TARGET_CAPITAL_ASSET_NUMBER);
      parameters.put(
          CamsPropertyConstants.AssetRetirementGlobal.RETIREMENT_REASON_CODE,
          CamsConstants.AssetRetirementReasonCode.MERGED);
      parameters.put(
          KFSConstants.REFRESH_CALLER,
          CamsPropertyConstants.AssetRetirementGlobal.RETIREMENT_REASON_CODE
              + "::"
              + CamsConstants.AssetRetirementReasonCode.MERGED);

      String href = UrlFactory.parameterizeUrl(KFSConstants.MAINTENANCE_ACTION, parameters);

      return new AnchorHtmlData(
          href, CamsConstants.AssetActions.MERGE, CamsConstants.AssetActions.MERGE);
    } else {
      return new AnchorHtmlData("", "", "");
    }
  }
  protected HtmlData getTransferUrl(Asset asset) {
    boolean isAuthorized = true;
    boolean assetMovable = false;
    try {
      assetMovable = getAssetService().isAssetMovableCheckByPayment(asset);
    } catch (ValidationException ve) {
      isAuthorized = false;
    }
    if (!assetMovable) {
      FinancialSystemTransactionalDocumentAuthorizerBase documentAuthorizer =
          (FinancialSystemTransactionalDocumentAuthorizerBase)
              SpringContext.getBean(DocumentDictionaryService.class)
                  .getDocumentAuthorizer(CamsConstants.DocumentTypeName.ASSET_TRANSFER);
      isAuthorized =
          documentAuthorizer.isAuthorized(
              asset,
              CamsConstants.CAM_MODULE_CODE,
              CamsConstants.PermissionNames.SEPARATE,
              GlobalVariables.getUserSession().getPerson().getPrincipalId());
    }

    if (isAuthorized) {
      Properties parameters = new Properties();
      parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KRADConstants.DOC_HANDLER_METHOD);
      parameters.put(
          CamsPropertyConstants.AssetTransferDocument.CAPITAL_ASSET_NUMBER,
          asset.getCapitalAssetNumber().toString());
      parameters.put(KFSConstants.PARAMETER_COMMAND, "initiate");
      parameters.put(
          KFSConstants.DOCUMENT_TYPE_NAME, CamsConstants.DocumentTypeName.ASSET_TRANSFER);

      String href =
          UrlFactory.parameterizeUrl(
              CamsConstants.StrutsActions.ONE_UP + CamsConstants.StrutsActions.TRANSFER,
              parameters);

      return new AnchorHtmlData(
          href, KRADConstants.DOC_HANDLER_METHOD, CamsConstants.AssetActions.TRANSFER);
    } else {
      return new AnchorHtmlData("", "", "");
    }
  }
  protected HtmlData getLoanUrl(Asset asset) {
    AnchorHtmlData anchorHtmlData = null;
    List<HtmlData> childURLDataList = new ArrayList<HtmlData>();

    Properties parameters = new Properties();
    parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KRADConstants.DOC_HANDLER_METHOD);
    parameters.put(
        CamsPropertyConstants.AssetTransferDocument.CAPITAL_ASSET_NUMBER,
        asset.getCapitalAssetNumber().toString());
    parameters.put(KFSConstants.PARAMETER_COMMAND, "initiate");
    parameters.put(
        KFSConstants.DOCUMENT_TYPE_NAME,
        CamsConstants.DocumentTypeName.ASSET_EQUIPMENT_LOAN_OR_RETURN);

    if (getAssetService().isAssetLoaned(asset)) {
      anchorHtmlData = new AnchorHtmlData("", "", "");

      AnchorHtmlData childURLData = new AnchorHtmlData("", "", CamsConstants.AssetActions.LOAN);
      childURLDataList.add(childURLData);

      parameters.put(CamsConstants.AssetActions.LOAN_TYPE, CamsConstants.AssetActions.LOAN_RENEW);
      String childHref =
          UrlFactory.parameterizeUrl(
              CamsConstants.StrutsActions.ONE_UP
                  + CamsConstants.StrutsActions.EQUIPMENT_LOAN_OR_RETURN,
              parameters);
      childURLData =
          new AnchorHtmlData(
              childHref, KRADConstants.DOC_HANDLER_METHOD, CamsConstants.AssetActions.LOAN_RENEW);
      childURLDataList.add(childURLData);

      parameters.remove(CamsConstants.AssetActions.LOAN_TYPE);
      parameters.put(CamsConstants.AssetActions.LOAN_TYPE, CamsConstants.AssetActions.LOAN_RETURN);
      childHref =
          UrlFactory.parameterizeUrl(
              CamsConstants.StrutsActions.ONE_UP
                  + CamsConstants.StrutsActions.EQUIPMENT_LOAN_OR_RETURN,
              parameters);
      childURLData =
          new AnchorHtmlData(
              childHref, KRADConstants.DOC_HANDLER_METHOD, CamsConstants.AssetActions.LOAN_RETURN);
      childURLDataList.add(childURLData);

      anchorHtmlData.setChildUrlDataList(childURLDataList);
    } else {
      anchorHtmlData = new AnchorHtmlData("", "", "");
      //
      AnchorHtmlData childURLData = new AnchorHtmlData("", "", "");
      if (asset.getCampusTagNumber() == null) {
        childURLData = new AnchorHtmlData("", "", CamsConstants.AssetActions.LOAN);
        childURLDataList.add(childURLData);
      } else {
        parameters.put(CamsConstants.AssetActions.LOAN_TYPE, CamsConstants.AssetActions.LOAN);
        String childHref =
            UrlFactory.parameterizeUrl(
                CamsConstants.StrutsActions.ONE_UP
                    + CamsConstants.StrutsActions.EQUIPMENT_LOAN_OR_RETURN,
                parameters);
        childURLData =
            new AnchorHtmlData(
                childHref, KRADConstants.DOC_HANDLER_METHOD, CamsConstants.AssetActions.LOAN);
        childURLDataList.add(childURLData);
      }

      childURLData = new AnchorHtmlData("", "", CamsConstants.AssetActions.LOAN_RENEW);
      childURLDataList.add(childURLData);

      childURLData = new AnchorHtmlData("", "", CamsConstants.AssetActions.LOAN_RETURN);
      childURLDataList.add(childURLData);

      anchorHtmlData.setChildUrlDataList(childURLDataList);
    }

    return anchorHtmlData;
  }
  /**
   * 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);
  }
  /**
   * Validates that the existance of the building code and room number is consistent with the asset
   * type requirements.
   *
   * @param detail
   * @prarm asset
   * @return boolean
   */
  protected boolean validateBuildingCodeAndRoomNumber(
      BarcodeInventoryErrorDetail detail, Asset asset) {
    boolean result = true;

    String campusCode = detail.getCampusCode();
    String buildingCode = detail.getBuildingCode();
    String roomNumber = detail.getBuildingRoomNumber();
    String labelBuilding =
        SpringContext.getBean(DataDictionaryService.class)
            .getDataDictionary()
            .getBusinessObjectEntry(BarcodeInventoryErrorDetail.class.getName())
            .getAttributeDefinition(CamsPropertyConstants.BarcodeInventory.BUILDING_CODE)
            .getLabel();
    String labelRoom =
        SpringContext.getBean(DataDictionaryService.class)
            .getDataDictionary()
            .getBusinessObjectEntry(BarcodeInventoryErrorDetail.class.getName())
            .getAttributeDefinition(CamsPropertyConstants.BarcodeInventory.BUILDING_ROOM_NUMBER)
            .getLabel();

    String assetTypeCode = asset.getCapitalAssetTypeCode();
    AssetType assetType = asset.getCapitalAssetType();

    // retrieve building
    HashMap<String, Object> fields = new HashMap<String, Object>();
    fields.put(KFSPropertyConstants.CAMPUS_CODE, campusCode);
    fields.put(KFSPropertyConstants.BUILDING_CODE, buildingCode);
    Building building = getBusinessObjectService().findByPrimaryKey(Building.class, fields);

    // retrieve room
    fields.put(KFSPropertyConstants.BUILDING_ROOM_NUMBER, roomNumber);
    Room room = getBusinessObjectService().findByPrimaryKey(Room.class, fields);

    // if movingIndicator is true and requiredBuildingIndicator is false, then both building and
    // room are required
    if (assetType.isMovingIndicator() && !assetType.isRequiredBuildingIndicator()) {
      // check building
      if (StringUtils.isBlank(buildingCode)) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_CODE,
                CamsKeyConstants.BarcodeInventory.ERROR_REQUIRED_FIELD,
                labelBuilding,
                assetTypeCode);
        result &= false;
      } else if (ObjectUtils.isNull(building)) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_CODE,
                CamsKeyConstants.BarcodeInventory.ERROR_INVALID_FIELD,
                labelBuilding);
        result &= false;
      } else if (!building.isActive()) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_CODE,
                CamsKeyConstants.BarcodeInventory.ERROR_INACTIVE_FIELD,
                labelBuilding);
        result &= false;
      }

      // check room
      if (StringUtils.isBlank(roomNumber)) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_ROOM_NUMBER,
                CamsKeyConstants.BarcodeInventory.ERROR_REQUIRED_FIELD,
                labelRoom,
                assetTypeCode);
        result &= false;
      } else if (ObjectUtils.isNull(room)) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_ROOM_NUMBER,
                CamsKeyConstants.BarcodeInventory.ERROR_INVALID_FIELD,
                labelRoom);
        result = false;
      } else if (!room.isActive()) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_ROOM_NUMBER,
                CamsKeyConstants.BarcodeInventory.ERROR_INACTIVE_FIELD,
                labelRoom);
        result &= false;
      }
    }

    // if movingIndicator is false and requiredBuildingIndicator is true, then building is required
    // while room is not allowed
    else if (!assetType.isMovingIndicator() && assetType.isRequiredBuildingIndicator()) {
      // check building
      if (StringUtils.isBlank(buildingCode)) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_CODE,
                CamsKeyConstants.BarcodeInventory.ERROR_REQUIRED_FIELD,
                labelBuilding,
                assetTypeCode);
        result &= false;
      } else if (ObjectUtils.isNull(building)) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_CODE,
                CamsKeyConstants.BarcodeInventory.ERROR_INVALID_FIELD,
                labelBuilding);
        result &= false;
      } else if (!building.isActive()) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_CODE,
                CamsKeyConstants.BarcodeInventory.ERROR_INACTIVE_FIELD,
                labelBuilding);
        result &= false;
      }

      // check room
      if (StringUtils.isNotBlank(roomNumber)) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_ROOM_NUMBER,
                CamsKeyConstants.BarcodeInventory.ERROR_NOT_ALLOWED_FIELD,
                labelRoom,
                assetTypeCode);
        result &= false;
      }
    }

    // if both movingIndicator and requiredBuildingIndicator are false, then neither building nor
    // room is allowed
    else if (!assetType.isMovingIndicator() && !assetType.isRequiredBuildingIndicator()) {
      // check building
      if (StringUtils.isNotBlank(buildingCode)) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_CODE,
                CamsKeyConstants.BarcodeInventory.ERROR_NOT_ALLOWED_FIELD,
                labelBuilding,
                assetTypeCode);
        result &= false;
      }

      // check room
      if (StringUtils.isNotBlank(roomNumber)) {
        GlobalVariables.getMessageMap()
            .putError(
                CamsPropertyConstants.BarcodeInventory.BUILDING_ROOM_NUMBER,
                CamsKeyConstants.BarcodeInventory.ERROR_NOT_ALLOWED_FIELD,
                labelRoom,
                assetTypeCode);
        result &= false;
      }
    }

    return result;
  }