/** This method changes account to suspenseAccount */
  protected Message useSuspenseAccount(LaborOriginEntry workingEntry) {
    String suspenseAccountNumber =
        parameterService.getParameterValueAsString(
            LaborScrubberStep.class, LaborConstants.Scrubber.SUSPENSE_ACCOUNT);
    String suspenseCOAcode =
        parameterService.getParameterValueAsString(
            LaborScrubberStep.class, LaborConstants.Scrubber.SUSPENSE_CHART);
    String suspenseSubAccountNumber =
        parameterService.getParameterValueAsString(
            LaborScrubberStep.class, LaborConstants.Scrubber.SUSPENSE_SUB_ACCOUNT);

    Account account = accountService.getByPrimaryId(suspenseCOAcode, suspenseAccountNumber);

    if (ObjectUtils.isNull(account)) {
      return MessageBuilder.buildMessage(
          LaborKeyConstants.ERROR_INVALID_SUSPENSE_ACCOUNT, Message.TYPE_FATAL);
    }

    workingEntry.setAccount(account);
    workingEntry.setAccountNumber(suspenseAccountNumber);
    workingEntry.setChartOfAccountsCode(suspenseCOAcode);
    workingEntry.setSubAccountNumber(suspenseSubAccountNumber);

    return MessageBuilder.buildMessageWithPlaceHolder(
        LaborKeyConstants.MESSAGE_SUSPENSE_ACCOUNT_APPLIED,
        Message.TYPE_WARNING,
        new Object[] {suspenseCOAcode, suspenseAccountNumber, suspenseSubAccountNumber});
  }
  /**
   * Validates the sub account of the origin entry
   *
   * @param originEntry the origin entry being scrubbed
   * @param workingEntry the scrubbed version of the origin entry
   * @return a Message if an error was encountered, otherwise null
   */
  protected Message validateSubAccount(
      LaborOriginEntry originEntry,
      LaborOriginEntry workingEntry,
      LaborAccountingCycleCachingService laborAccountingCycleCachingService) {
    LOG.debug("validateSubAccount() started");

    // when continuationAccount used, the subAccountNumber should be changed to dashes and skip
    // validation subAccount process
    if (continuationAccountIndicator) {
      workingEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber());
      return null;
    }

    // If the sub account number is empty, set it to dashes.
    // Otherwise set the workingEntry sub account number to the
    // sub account number of the input origin entry.
    if (org.springframework.util.StringUtils.hasText(originEntry.getSubAccountNumber())) {
      // sub account IS specified
      if (!KFSConstants.getDashSubAccountNumber().equals(originEntry.getSubAccountNumber())) {
        SubAccount originEntrySubAccount =
            laborAccountingCycleCachingService.getSubAccount(
                originEntry.getChartOfAccountsCode(),
                originEntry.getAccountNumber(),
                originEntry.getSubAccountNumber());
        // SubAccount originEntrySubAccount = getSubAccount(originEntry);
        if (originEntrySubAccount == null) {
          // sub account is not valid
          return MessageBuilder.buildMessage(
              KFSKeyConstants.ERROR_SUB_ACCOUNT_NOT_FOUND,
              originEntry.getChartOfAccountsCode()
                  + "-"
                  + originEntry.getAccountNumber()
                  + "-"
                  + originEntry.getSubAccountNumber(),
              Message.TYPE_FATAL);
        } else {
          // sub account IS valid
          if (originEntrySubAccount.isActive()) {
            // sub account IS active
            workingEntry.setSubAccountNumber(originEntry.getSubAccountNumber());
          } else {
            // sub account IS NOT active
            if (parameterService
                .getParameterValueAsString(
                    KfsParameterConstants.GENERAL_LEDGER_BATCH.class,
                    KFSConstants.SystemGroupParameterNames.GL_ANNUAL_CLOSING_DOC_TYPE)
                .equals(originEntry.getFinancialDocumentTypeCode())) {
              // document IS annual closing
              workingEntry.setSubAccountNumber(originEntry.getSubAccountNumber());
            } else {
              // document is NOT annual closing
              return MessageBuilder.buildMessage(
                  KFSKeyConstants.ERROR_SUB_ACCOUNT_NOT_ACTIVE,
                  originEntry.getChartOfAccountsCode()
                      + "-"
                      + originEntry.getAccountNumber()
                      + "-"
                      + originEntry.getSubAccountNumber(),
                  Message.TYPE_FATAL);
            }
          }
        }
      } else {
        // the sub account is dashes
        workingEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber());
      }
    } else {
      // No sub account is specified.
      workingEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber());
    }

    return null;
  }
  /**
   * Loops through continuation accounts for 10 tries or until it finds an account that is not
   * expired.
   */
  protected Message continuationAccountLogic(
      Account expiredClosedAccount,
      LaborOriginEntry laborOriginEntry,
      LaborOriginEntry laborWorkingEntry,
      UniversityDate universityRunDate) {
    String chartCode = expiredClosedAccount.getContinuationFinChrtOfAcctCd();
    String accountNumber = expiredClosedAccount.getContinuationAccountNumber();

    List<String> checkedAccountNumbers = new ArrayList<String>();
    for (int i = 0; i < 10; ++i) {
      if (checkedAccountNumbers.contains(chartCode + accountNumber)) {
        // Something is really wrong with the data because this account has already been evaluated.
        return MessageBuilder.buildMessage(
            KFSKeyConstants.ERROR_CIRCULAR_DEPENDENCY_IN_CONTINUATION_ACCOUNT_LOGIC,
            Message.TYPE_FATAL);
      }

      checkedAccountNumbers.add(chartCode + accountNumber);

      if (chartCode == null || accountNumber == null) {
        return MessageBuilder.buildMessage(
            KFSKeyConstants.ERROR_CONTINUATION_ACCOUNT_NOT_FOUND, Message.TYPE_FATAL);
      }

      // Lookup the account
      Account account = accountService.getByPrimaryId(chartCode, accountNumber);
      if (ObjectUtils.isNull(account)) {
        return MessageBuilder.buildMessage(
            KFSKeyConstants.ERROR_CONTINUATION_ACCOUNT_NOT_FOUND, Message.TYPE_FATAL);
      }

      // check account expiration
      long offsetAccountExpirationTime = getAdjustedAccountExpirationDate(account);
      if (ObjectUtils.isNotNull(account.getAccountExpirationDate())
          && isAccountExpired(account, universityRunDate)) {
        chartCode = account.getContinuationFinChrtOfAcctCd();
        accountNumber = account.getContinuationAccountNumber();
      } else {

        // set continuationAccountLogicIndi
        continuationAccountIndicator = true;

        laborWorkingEntry.setAccount(account);
        laborWorkingEntry.setAccountNumber(accountNumber);
        laborWorkingEntry.setChartOfAccountsCode(chartCode);
        laborWorkingEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber());
        laborWorkingEntry.setTransactionLedgerEntryDescription(
            kualiConfigurationService.getPropertyValueAsString(KFSKeyConstants.MSG_AUTO_FORWARD)
                + " "
                + expiredClosedAccount.getChartOfAccountsCode()
                + expiredClosedAccount.getAccountNumber()
                + laborOriginEntry.getTransactionLedgerEntryDescription());

        return MessageBuilder.buildMessage(
            KFSKeyConstants.MSG_ACCOUNT_CLOSED_TO,
            laborWorkingEntry.getChartOfAccountsCode() + "-" + laborWorkingEntry.getAccountNumber(),
            Message.TYPE_WARNING);
      }
    }

    // We failed to find a valid continuation account.
    boolean suspenseAccountLogicInd =
        parameterService.getParameterValueAsBoolean(
            LaborScrubberStep.class, LaborConstants.Scrubber.SUSPENSE_ACCOUNT_LOGIC_PARAMETER);
    if (suspenseAccountLogicInd) {
      return useSuspenseAccount(laborWorkingEntry);
    } else {
      return MessageBuilder.buildMessage(
          KFSKeyConstants.ERROR_CONTINUATION_ACCOUNT_LIMIT_REACHED, Message.TYPE_FATAL);
    }
  }