/**
   * Validate budget rates. Applicable rates are mandatory
   *
   * @param budgetDocument
   * @return
   */
  protected boolean processBudgetRatesBusinessRule(BudgetDocument budgetDocument) {
    boolean valid = true;
    final int APPLICABLE_RATE_LENGTH_EXCEEDED = 1;
    final int APPLICABLE_RATE_NEGATIVE = -1;

    ErrorMap errorMap = GlobalVariables.getErrorMap();
    int i = 0;
    for (BudgetRate budgetRate : budgetDocument.getBudget().getBudgetRates()) {
      String rateClassType = budgetRate.getRateClass().getRateClassTypeT().getDescription();
      String errorPath = "budgetProposalRate[" + rateClassType + "][" + i + "]";
      errorMap.addToErrorPath(errorPath);
      /* look for applicable rate */
      if (budgetRate.isApplicableRateNull()) {
        valid = false;
        errorMap.putError("applicableRate", KeyConstants.ERROR_REQUIRED_APPLICABLE_RATE);
      } else if (!BudgetDecimal.isNumeric(budgetRate.getApplicableRate().toString())) {
        valid = false;
        errorMap.putError("applicableRate", KeyConstants.ERROR_APPLICABLE_RATE_NOT_NUMERIC);
      } else {
        switch (verifyApplicableRate(budgetRate.getApplicableRate())) {
          case APPLICABLE_RATE_LENGTH_EXCEEDED:
            valid = false;
            errorMap.putError(
                "applicableRate",
                KeyConstants.ERROR_APPLICABLE_RATE_LIMIT,
                Constants.APPLICABLE_RATE_LIMIT);
            break;
          case APPLICABLE_RATE_NEGATIVE:
            valid = false;
            errorMap.putError("applicableRate", KeyConstants.ERROR_APPLICABLE_RATE_NEGATIVE);
            break;
        }
      }
      errorMap.removeFromErrorPath(errorPath);
      i++;
    }

    i = 0;
    for (BudgetLaRate budgetLaRate : budgetDocument.getBudget().getBudgetLaRates()) {
      String rateClassType = "";
      if (ObjectUtils.isNotNull(budgetLaRate.getRateClass())
          && ObjectUtils.isNotNull(budgetLaRate.getRateClass().getRateClassTypeT())) {
        rateClassType = budgetLaRate.getRateClass().getRateClassTypeT().getDescription();
      }
      String errorPath = "budgetRate[" + rateClassType + "][" + i + "]";
      errorMap.addToErrorPath(errorPath);
      /* look for applicable rate */
      if (budgetLaRate.isApplicableRateNull()) {
        valid = false;
        errorMap.putError("applicableRate", KeyConstants.ERROR_REQUIRED_APPLICABLE_RATE);
      } else if (!BudgetDecimal.isNumeric(budgetLaRate.getApplicableRate().toString())) {
        valid = false;
        errorMap.putError("applicableRate", KeyConstants.ERROR_APPLICABLE_RATE_NOT_NUMERIC);
      } else {
        switch (verifyApplicableRate(budgetLaRate.getApplicableRate())) {
          case APPLICABLE_RATE_LENGTH_EXCEEDED:
            valid = false;
            errorMap.putError(
                "applicableRate",
                KeyConstants.ERROR_APPLICABLE_RATE_LIMIT,
                Constants.APPLICABLE_RATE_LIMIT);
            break;
          case APPLICABLE_RATE_NEGATIVE:
            valid = false;
            errorMap.putError("applicableRate", KeyConstants.ERROR_APPLICABLE_RATE_NEGATIVE);
            break;
        }
      }
      errorMap.removeFromErrorPath(errorPath);
      i++;
    }

    return valid;
  }
  /**
   * Validate budget project income. costshare percentage must be between 0 and 999.99
   *
   * @param budgetDocument
   * @return
   */
  protected boolean processBudgetProjectIncomeBusinessRule(BudgetDocument budgetDocument) {
    boolean valid = true;
    ErrorMap errorMap = GlobalVariables.getErrorMap();
    int i = 0;
    for (BudgetCostShare budgetCostShare : budgetDocument.getBudget().getBudgetCostShares()) {
      String errorPath = "budgetCostShare[" + i + "]";
      errorMap.addToErrorPath(errorPath);
      if (budgetCostShare.getSharePercentage() != null
          && (budgetCostShare.getSharePercentage().isLessThan(new BudgetDecimal(0))
              || budgetCostShare.getSharePercentage().isGreaterThan(new BudgetDecimal(100)))) {
        errorMap.putError("sharePercentage", KeyConstants.ERROR_COST_SHARE_PERCENTAGE);
        valid = false;
      }
      // check for duplicate fiscal year and source accounts on all unchecked cost shares
      if (i < budgetDocument.getBudget().getBudgetCostShareCount()) {
        for (int j = i + 1; j < budgetDocument.getBudget().getBudgetCostShareCount(); j++) {
          BudgetCostShare tmpCostShare = budgetDocument.getBudget().getBudgetCostShare(j);
          int thisFiscalYear =
              budgetCostShare.getProjectPeriod() == null
                  ? Integer.MIN_VALUE
                  : budgetCostShare.getProjectPeriod();
          int otherFiscalYear =
              tmpCostShare.getProjectPeriod() == null
                  ? Integer.MIN_VALUE
                  : tmpCostShare.getProjectPeriod();
          if (thisFiscalYear == otherFiscalYear
              && StringUtils.equalsIgnoreCase(
                  budgetCostShare.getSourceAccount(), tmpCostShare.getSourceAccount())) {
            errorMap.putError(
                "fiscalYear",
                KeyConstants.ERROR_COST_SHARE_DUPLICATE,
                thisFiscalYear == Integer.MIN_VALUE ? "" : thisFiscalYear + "",
                budgetCostShare.getSourceAccount() == null
                    ? "\"\""
                    : budgetCostShare.getSourceAccount());
            valid = false;
          }
        }
      }

      // validate project period stuff
      String currentField = "document.budget.budgetCostShare[" + i + "].projectPeriod";
      int numberOfProjectPeriods = budgetDocument.getBudget().getBudgetPeriods().size();
      boolean validationCheck =
          this.validateProjectPeriod(
              budgetCostShare.getProjectPeriod(), currentField, numberOfProjectPeriods);
      valid &= validationCheck;

      errorMap.removeFromErrorPath(errorPath);
      i++;
    }
    // check project income for values that are not greater than 0
    GlobalVariables.getErrorMap().removeFromErrorPath("budget");
    GlobalVariables.getErrorMap().addToErrorPath("budgets[0]");
    i = 0;
    for (BudgetProjectIncome budgetProjectIncome :
        budgetDocument.getBudget().getBudgetProjectIncomes()) {
      String errorPath = "budgetProjectIncomes[" + i + "]";
      errorMap.addToErrorPath(errorPath);
      if (budgetProjectIncome.getProjectIncome() == null
          || !budgetProjectIncome.getProjectIncome().isGreaterThan(new KualiDecimal(0.00))) {
        errorMap.putError("projectIncome", "error.projectIncome.negativeOrZero");
        valid = false;
      }
      errorMap.removeFromErrorPath(errorPath);
      i++;
    }
    GlobalVariables.getErrorMap().removeFromErrorPath("budgets[0]");
    GlobalVariables.getErrorMap().addToErrorPath("budget");

    return valid;
  }