/**
   * Validates credit splits of all investigators in a <code>{@link ProposalDevelopmentDocument}
   * </code>. Takes a <code>{@link Collection}</code> of investigators for a given credit type, and
   * validates credit splits for each investigator as well as iterating and validating credit splits
   * for each unit belonging to an investigator.
   *
   * @param investigators
   * @param creditTypeCode
   * @return true if the investigator collection is valid for the credit type, and false if it's
   *     invalid
   */
  public boolean validate(
      Collection<ProposalPerson> investigators, InvestigatorCreditType creditType) {
    boolean retval = true;

    DecimalHolder investigatorCreditTotal = new DecimalHolder(KualiDecimal.ZERO);

    if (!validateCreditSplitable(investigators.iterator(), creditType, investigatorCreditTotal)) {
      addAuditError(ERROR_TOTAL_CREDIT_SPLIT_UPBOUND, creditType.getDescription());
      retval = false;
    }

    info(INV_VALIDATION_MESSAGE, retval);

    for (ProposalPerson investigator : investigators) {
      DecimalHolder unitCreditTotal = new DecimalHolder(KualiDecimal.ZERO);

      if (!validateCreditSplitable(
          investigator.getUnits().iterator(), creditType, unitCreditTotal)) {
        addAuditError(
            ERROR_CREDIT_SPLIT_UPBOUND,
            creditType.getDescription(),
            getCreditSplitableName(investigator));
        retval = false;
      }

      info(UNIT_VALIDATION_MESSAGE, retval);
    }

    return retval;
  }
  /**
   * Validates the credit splits of an entire document by traversing it. If the Investigator is
   * instead a Principal Investigator, the units should all add up to 100.0.
   *
   * @param document The document to validate the credit splits of
   * @return boolean
   */
  public boolean validate(ProposalDevelopmentDocument document) {
    Collection<InvestigatorCreditType> creditTypes =
        getKeyPersonnelService().getInvestigatorCreditTypes();
    boolean retval = true;

    for (InvestigatorCreditType creditType : creditTypes) {
      info(VALIDATING_CT_MESSAGE, creditType.getDescription());
      if (creditType.addsToHundred()) {
        retval &= validate(document.getDevelopmentProposal().getInvestigators(), creditType);
      }
    }

    return retval;
  }
  public boolean checkAwardPersonUnitCreditSplitTotals(AwardPersonUnitCreditSplitRuleEvent event) {
    int errorCount = 0;
    AwardPerson person = event.getProjectPerson();
    for (InvestigatorCreditType creditType : loadInvestigatorCreditTypes()) {
      if (creditType.addsToHundred()) {
        KualiDecimal value =
            event.getTotalsByCreditSplitType().get(creditType.getInvCreditTypeCode());
        if (value == null) {
          break; // value may not have been initialized yet, so we don't want to block save
        }
        if (!MAX_TOTAL_VALUE.subtract(value).isZero()) {
          reportError(
              AWARD_CREDIT_SPLIT_LIST_ERROR_KEY,
              AWARD_PERSON_UNIT_CREDIT_SPLIT_ERROR_MSG_KEY,
              creditType.getDescription(),
              person.getFullName());
          errorCount++;
        }
      }
    }

    return errorCount == 0;
  }
  /**
   * Validates a collection of anything splits. Negative values and values exceeding 100.00 are not
   * permissible.
   *
   * @param creditSplit_it
   * @param creditType
   * @param lesserCummulative
   * @return boolean <code>true</code> if it is a valid percentage (falls between 0.00 and 100.00)
   */
  public boolean validateCreditSplit(
      Iterator<? extends CreditSplit> creditSplit_it,
      InvestigatorCreditType creditType,
      DecimalHolder lesserCummulative) {
    if (!creditSplit_it.hasNext()) {
      return false;
    }

    CreditSplit creditSplit = creditSplit_it.next();
    if (creditType.getInvCreditTypeCode().equals(creditSplit.getInvCreditTypeCode())) {
      lesserCummulative.add(creditSplit.getCredit());
      info("Credit split is %s", creditSplit.getCredit());
      return isCreditSplitValid(creditSplit.getCredit());
    }

    return validateCreditSplit(creditSplit_it, creditType, lesserCummulative);
  }