/** @see org.kuali.kfs.module.bc.service.PayrateImportService#importFile(java.io.InputStream) */
  @Transactional
  public boolean importFile(
      InputStream fileImportStream,
      List<ExternalizedMessageWrapper> messageList,
      String principalId) {
    Map payRateHoldingPersonUniversalIdentifierKey = new HashMap();
    payRateHoldingPersonUniversalIdentifierKey.put(
        KFSPropertyConstants.PERSON_UNIVERSAL_IDENTIFIER, principalId);

    this.businessObjectService.deleteMatching(
        BudgetConstructionPayRateHolding.class, payRateHoldingPersonUniversalIdentifierKey);

    BufferedReader fileReader = new BufferedReader(new InputStreamReader(fileImportStream));
    this.importCount = 0;

    try {
      while (fileReader.ready()) {
        BudgetConstructionPayRateHolding budgetConstructionPayRateHolding =
            new BudgetConstructionPayRateHolding();
        String line = fileReader.readLine();
        ObjectUtil.convertLineToBusinessObject(
            budgetConstructionPayRateHolding,
            line,
            DefaultImportFileFormat.fieldLengths,
            Arrays.asList(DefaultImportFileFormat.fieldNames));
        budgetConstructionPayRateHolding.setPrincipalId(principalId);
        budgetConstructionPayRateHolding.setAppointmentRequestedPayRate(
            budgetConstructionPayRateHolding.getAppointmentRequestedPayRate().movePointLeft(2));
        businessObjectService.save(budgetConstructionPayRateHolding);
        this.importCount++;
      }
    } catch (Exception e) {
      this.businessObjectService.deleteMatching(
          BudgetConstructionPayRateHolding.class, payRateHoldingPersonUniversalIdentifierKey);
      messageList.add(new ExternalizedMessageWrapper(BCKeyConstants.ERROR_PAYRATE_IMPORT_ABORTED));

      return false;
    }

    if (importCount == 0)
      messageList.add(
          new ExternalizedMessageWrapper(BCKeyConstants.MSG_PAYRATE_IMPORT_NO_IMPORT_RECORDS));
    else
      messageList.add(
          new ExternalizedMessageWrapper(
              BCKeyConstants.MSG_PAYRATE_IMPORT_COUNT, String.valueOf(importCount)));

    return true;
  }
  /** @see org.kuali.kfs.module.bc.service.PayrateImportService#update() */
  @Transactional
  public void update(
      Integer budgetYear,
      Person user,
      List<ExternalizedMessageWrapper> messageList,
      String principalId) {
    List<PendingBudgetConstructionAppointmentFunding> lockedFundingRecords =
        new ArrayList<PendingBudgetConstructionAppointmentFunding>();
    boolean updateContainsErrors = false;
    this.updateCount = 0;

    Map payRateHoldingPersonUniversalIdentifierKey = new HashMap();
    payRateHoldingPersonUniversalIdentifierKey.put(
        KFSPropertyConstants.PERSON_UNIVERSAL_IDENTIFIER, principalId);
    List<BudgetConstructionPayRateHolding> records =
        (List<BudgetConstructionPayRateHolding>)
            this.businessObjectService.findMatching(
                BudgetConstructionPayRateHolding.class, payRateHoldingPersonUniversalIdentifierKey);

    if (!getPayrateLock(lockedFundingRecords, messageList, budgetYear, user, records)) {
      messageList.add(
          new ExternalizedMessageWrapper(
              BCKeyConstants.ERROR_PAYRATE_UPDATE_ABORTED, String.valueOf(this.updateCount)));
      doRollback();
      return;
    }

    List<String> biweeklyPayObjectCodes = BudgetParameterFinder.getBiweeklyPayObjectCodes();
    for (BudgetConstructionPayRateHolding holdingRecord : records) {
      if (holdingRecord.getAppointmentRequestedPayRate().equals(-1.0)) {
        messageList.add(
            new ExternalizedMessageWrapper(
                BCKeyConstants.ERROR_PAYRATE_IMPORT_NO_PAYROLL_MATCH,
                holdingRecord.getEmplid(),
                holdingRecord.getPositionNumber()));
        updateContainsErrors = true;
        continue;
      }

      List<PendingBudgetConstructionAppointmentFunding> fundingRecords =
          this.payrateImportDao.getFundingRecords(
              holdingRecord, budgetYear, biweeklyPayObjectCodes);
      if (fundingRecords.isEmpty()) {
        messageList.add(
            new ExternalizedMessageWrapper(
                BCKeyConstants.ERROR_PAYRATE_NO_ACTIVE_FUNDING_RECORDS,
                holdingRecord.getEmplid(),
                holdingRecord.getPositionNumber()));
        updateContainsErrors = true;
        continue;
      }

      for (PendingBudgetConstructionAppointmentFunding fundingRecord : fundingRecords) {

        if (!fundingRecord
            .getAppointmentRequestedPayRate()
            .equals(holdingRecord.getAppointmentRequestedPayRate())) {
          if (fundingRecord.getAppointmentRequestedFteQuantity().equals(0)
              || fundingRecord.getAppointmentRequestedFteQuantity() == null) {
            messageList.add(
                new ExternalizedMessageWrapper(
                    BCKeyConstants.ERROR_PAYRATE_NO_UPDATE_FTE_ZERO_OR_BLANK,
                    holdingRecord.getEmplid(),
                    holdingRecord.getPositionNumber(),
                    fundingRecord.getChartOfAccountsCode(),
                    fundingRecord.getAccountNumber(),
                    fundingRecord.getSubAccountNumber()));
            updateContainsErrors = true;
            continue;
          }

          BigDecimal temp1 =
              fundingRecord.getAppointmentRequestedTimePercent().divide(new BigDecimal(100));
          BigDecimal temp2 =
              new BigDecimal(
                  (fundingRecord.getAppointmentFundingMonth()
                          / fundingRecord.getBudgetConstructionPosition().getIuPayMonths())
                      * BudgetParameterFinder.getAnnualWorkingHours());

          KualiInteger annualAmount =
              new KualiInteger(
                  holdingRecord.getAppointmentRequestedPayRate().multiply(temp1.multiply(temp2)));
          KualiInteger updateAmount =
              annualAmount.subtract(fundingRecord.getAppointmentRequestedAmount());

          BudgetConstructionHeader header =
              budgetDocumentService.getBudgetConstructionHeader(fundingRecord);
          if (header == null) {
            messageList.add(
                new ExternalizedMessageWrapper(
                    BCKeyConstants.ERROR_PAYRATE_NO_BUDGET_DOCUMENT,
                    budgetYear.toString(),
                    fundingRecord.getChartOfAccountsCode(),
                    fundingRecord.getAccountNumber(),
                    fundingRecord.getSubAccountNumber()));
            messageList.add(
                new ExternalizedMessageWrapper(
                    BCKeyConstants.ERROR_PAYRATE_OBJECT_LEVEL_ERROR,
                    fundingRecord.getEmplid(),
                    fundingRecord.getPositionNumber(),
                    fundingRecord.getChartOfAccountsCode(),
                    fundingRecord.getAccountNumber(),
                    fundingRecord.getSubAccountNumber()));
            updateContainsErrors = true;
            continue;
          }

          // update or create pending budget GL record and  plug line
          budgetDocumentService.updatePendingBudgetGeneralLedger(fundingRecord, updateAmount);
          if (updateAmount.isNonZero()) {
            budgetDocumentService.updatePendingBudgetGeneralLedgerPlug(
                fundingRecord, updateAmount.negated());
          }

          fundingRecord.setAppointmentRequestedPayRate(
              holdingRecord.getAppointmentRequestedPayRate());
          fundingRecord.setAppointmentRequestedAmount(annualAmount);
          this.businessObjectService.save(fundingRecord);
        }
      }
      this.updateCount++;
    }

    messageList.add(
        new ExternalizedMessageWrapper(
            BCKeyConstants.MSG_PAYRATE_IMPORT_UPDATE_COMPLETE, String.valueOf(updateCount)));

    for (PendingBudgetConstructionAppointmentFunding recordToUnlock : lockedFundingRecords) {
      this.lockService.unlockAccount(
          budgetDocumentService.getBudgetConstructionHeader(recordToUnlock));
    }
  }