/**
  * Part of a complete breakfast, it has everything you need to populate Key Personnel into a
  * <code>{@link ProposalDevelopmentDocument}</code>
  *
  * @param document
  */
 public void populateDocument(ProposalDevelopmentDocument document) {
   if (hasBeenRoutedOrCanceled(document)) {
     Collection<InvestigatorCreditType> availableCreditTypes = getAllInvestigatorCreditTypes();
     Set<InvestigatorCreditType> usedCreditTypes = new HashSet<InvestigatorCreditType>();
     for (ProposalPerson person : document.getDevelopmentProposal().getInvestigators()) {
       for (ProposalPersonCreditSplit creditSplit : person.getCreditSplits()) {
         for (InvestigatorCreditType currentCreditType : availableCreditTypes) {
           if (currentCreditType.getCode().equals(creditSplit.getInvCreditTypeCode())) {
             usedCreditTypes.add(currentCreditType);
           }
         }
       }
     }
     document.getDevelopmentProposal().setInvestigatorCreditTypes(usedCreditTypes);
   } else {
     document.getDevelopmentProposal().setInvestigatorCreditTypes(getInvestigatorCreditTypes());
   }
   if (document.getDevelopmentProposal().getInvestigators().isEmpty()
       && !document.getDevelopmentProposal().getProposalPersons().isEmpty()) {
     LOG.info("Need to repopulate investigator list");
     populateInvestigators(document);
     if (!(document.getDocumentHeader().getWorkflowDocument().getStatus().getCode().equals("R"))) {
       populateActiveCredittypesPerson(document);
     }
   }
   /* check for new certification questions */
   for (ProposalPerson person : document.getDevelopmentProposal().getProposalPersons()) {
     getYnqService().getPersonYNQ(person, document);
   }
 }
  /**
   * 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;
  }
  /** Assigns the lead unit of the proposal to the given principal investigator */
  public void assignLeadUnit(ProposalPerson person, String unitNumber) {
    if (person.containsUnit(unitNumber)) {
      person.getUnit(unitNumber).setLeadUnit(true);
      return;
    }

    ProposalPersonUnit unit = createProposalPersonUnit(unitNumber, person);
    unit.setLeadUnit(true);
    addUnitToPerson(person, unit);
  }
  @Override
  public void addUnitToPerson(ProposalPerson person, ProposalPersonUnit unit) {
    if (unit == null) {
      throw new IllegalArgumentException("Cannot add null units to a ProposalPerson instance");
    }

    if (!person.containsUnit(unit.getUnitNumber())) {
      unit.setProposalPerson(person);

      person.addUnit(unit);
      unit.refreshReferenceObject("unit");
    }
  }
  /**
   * Initializes credit splits for new investigators
   *
   * @param person
   */
  protected void populateCreditTypes(ProposalPerson person) {
    if (!person.getCreditSplits().isEmpty()) {
      return;
    }

    for (InvestigatorCreditType creditType :
        (Collection<InvestigatorCreditType>) getInvestigatorCreditTypes()) {
      ProposalPersonCreditSplit creditSplit = new ProposalPersonCreditSplit();
      creditSplit.setProposalPerson(person);
      creditSplit.setInvCreditTypeCode(creditType.getCode());
      creditSplit.setCredit(new ScaleTwoDecimal(0));
      person.getCreditSplits().add(creditSplit);
    }
  }
  /**
   * Populate investigators
   *
   * @param document The <code>{@link ProposalDevelopmentDocument}</code> to populate investigators
   *     on
   */
  public void populateInvestigators(ProposalDevelopmentDocument document) {
    // Populate Investigators from a proposal document's persons
    LOG.debug("Populating Investigators");
    LOG.debug("Clearing investigator list");
    document.getDevelopmentProposal().getInvestigators().clear();

    for (ProposalPerson person : document.getDevelopmentProposal().getProposalPersons()) {
      LOG.debug(person.getFullName() + " is " + person.isInvestigator());

      if (person.isInvestigator()) {
        LOG.info("Adding investigator " + person.getFullName());
        document.getDevelopmentProposal().getInvestigators().add(person);
      }
    }
  }
  @Override
  public void populateProposalPerson(ProposalPerson person, ProposalDevelopmentDocument document) {
    /* populate certification questions for new person */
    person = getYnqService().getPersonYNQ(person, document);

    if (person.isInvestigator()) {
      if (!document.getDevelopmentProposal().getInvestigators().contains(person)) {
        document.getDevelopmentProposal().getInvestigators().add(person);
      }
      populateCreditTypes(person);
    }

    person.setRoleChanged(false);

    try {
      if (person.getPersonId() != null && person.getPerson().getExtendedAttributes() != null) {
        KcPerson origPerson = person.getPerson();
        for (PersonDegree degree : origPerson.getExtendedAttributes().getPersonDegrees()) {
          ProposalPersonDegree newDegree = new ProposalPersonDegree();
          newDegree.setDegree(degree.getDegree());
          newDegree.setDegreeCode(degree.getDegreeCode());
          newDegree.setFieldOfStudy(degree.getFieldOfStudy());
          newDegree.setGraduationYear(degree.getGraduationYear());
          newDegree.setSchool(degree.getSchool());
          newDegree.setSchoolId(degree.getSchoolId());
          newDegree.setSchoolIdCode(degree.getSchoolIdCode());
          newDegree.setDegreeSequenceNumber(
              document.getDocumentNextValue(Constants.PROPOSAL_PERSON_DEGREE_SEQUENCE_NUMBER));
          person.addDegree(newDegree);
        }
        if (origPerson.getExtendedAttributes().getAttachments() != null) {
          for (PersonBiosketch attachment : origPerson.getExtendedAttributes().getAttachments()) {
            ProposalPersonBiography bio = new ProposalPersonBiography();
            bio.setProposalPersonNumber(person.getProposalPersonNumber());
            bio.setDocumentTypeCode(getDefaultPersonAttachmentDocType());
            bio.setDescription(attachment.getDescription());
            bio.setName(attachment.getFileName());
            bio.setType(attachment.getContentType());

            ProposalPersonBiographyAttachment personnelAttachment =
                new ProposalPersonBiographyAttachment();
            personnelAttachment.setName(attachment.getFileName());
            personnelAttachment.setProposalNumber(
                document.getDevelopmentProposal().getProposalNumber());
            personnelAttachment.setProposalPersonNumber(person.getProposalPersonNumber());
            personnelAttachment.setData(attachment.getAttachmentContent());
            personnelAttachment.setType(attachment.getContentType());
            bio.setPersonnelAttachment(personnelAttachment);

            document.getDevelopmentProposal().addProposalPersonBiography(bio);
          }
        }
      }
    } catch (IllegalArgumentException e) {
      // catching the possibility that person.getPerson can not
      // find a EntityContract for this person id.
    }
  }
 /**
  * It populates the Active credit type in the proposalpersoncreditsplit and unitcreditsplit
  *
  * @param document
  * @return true or false
  */
 public void populateActiveCredittypesPerson(ProposalDevelopmentDocument document) {
   Collection<InvestigatorCreditType> invcrdttype = getInvestigatorCreditTypes();
   for (ProposalPerson person : document.getDevelopmentProposal().getInvestigators()) {
     for (InvestigatorCreditType invcredtype : invcrdttype) {
       boolean creditTypeFound = false;
       for (ProposalPersonCreditSplit proposalpersoncrdt : person.getCreditSplits()) {
         if ((invcredtype.getCode().equals(proposalpersoncrdt.getInvCreditTypeCode()))) {
           creditTypeFound = true;
           break;
         }
       }
       if (!creditTypeFound) {
         ProposalPersonCreditSplit creditSplit = new ProposalPersonCreditSplit();
         creditSplit.setProposalPerson(person);
         creditSplit.setInvCreditTypeCode(invcredtype.getCode());
         creditSplit.setCredit(new ScaleTwoDecimal(0));
         person.getCreditSplits().add(creditSplit);
       }
     }
     for (ProposalPersonUnit unitsplit : person.getUnits()) {
       for (InvestigatorCreditType invcrdtype : invcrdttype) {
         boolean creditTypeFound = false;
         for (ProposalUnitCreditSplit unitcreditsplit : unitsplit.getCreditSplits()) {
           if ((invcrdtype.getCode().equals(unitcreditsplit.getInvCreditTypeCode()))) {
             creditTypeFound = true;
             break;
           }
         }
         if (!creditTypeFound) {
           ProposalUnitCreditSplit creditSplit = new ProposalUnitCreditSplit();
           creditSplit.setProposalPersonUnit(unitsplit);
           creditSplit.setInvCreditTypeCode(invcrdtype.getCode());
           creditSplit.setCredit(new ScaleTwoDecimal(0));
           unitsplit.getCreditSplits().add(creditSplit);
         }
       }
     }
   }
 }
  @Override
  public List<ProposalCreditSplitListDto> createCreditSplitListItems(
      List<ProposalPerson> investigators) {
    List<ProposalCreditSplitListDto> creditSplitListItems =
        new ArrayList<ProposalCreditSplitListDto>();
    Map<String, ProposalPersonCreditSplit> totalInvestigatorSplits =
        new HashMap<String, ProposalPersonCreditSplit>();
    for (ProposalPerson investigator : investigators) {
      ProposalCreditSplitListDto investigatorLine = new ProposalCreditSplitListDto();
      investigatorLine.setDescription(investigator.getFullName());
      investigatorLine.setLineType("investigator");
      investigatorLine.getCreditSplits().addAll(investigator.getCreditSplits());
      creditSplitListItems.add(investigatorLine);
      for (ProposalPersonCreditSplit invesitgatorCreditSplit : investigator.getCreditSplits()) {
        if (totalInvestigatorSplits.containsKey(invesitgatorCreditSplit.getInvCreditTypeCode())) {
          ProposalPersonCreditSplit creditSplit =
              totalInvestigatorSplits.get(invesitgatorCreditSplit.getInvCreditTypeCode());
          creditSplit.setCredit(creditSplit.getCredit().add(invesitgatorCreditSplit.getCredit()));
        } else {
          ProposalPersonCreditSplit creditSplit = new ProposalPersonCreditSplit();
          creditSplit.setCredit(invesitgatorCreditSplit.getCredit());
          totalInvestigatorSplits.put(invesitgatorCreditSplit.getInvCreditTypeCode(), creditSplit);
        }
      }

      Map<String, ProposalUnitCreditSplit> totalUnitSplits =
          new HashMap<String, ProposalUnitCreditSplit>();
      for (ProposalPersonUnit unit : investigator.getUnits()) {
        ProposalCreditSplitListDto unitLine = new ProposalCreditSplitListDto();
        unitLine.setDescription(unit.getUnitNumber() + " - " + unit.getUnit().getUnitName());
        unitLine.getCreditSplits().addAll(unit.getCreditSplits());
        unitLine.setLineType("unit");
        creditSplitListItems.add(unitLine);
        for (ProposalUnitCreditSplit unitCreditSplit : unit.getCreditSplits()) {
          if (totalUnitSplits.containsKey(unitCreditSplit.getInvCreditTypeCode())) {
            ProposalUnitCreditSplit creditSplit =
                totalUnitSplits.get(unitCreditSplit.getInvCreditTypeCode());
            creditSplit.setCredit(creditSplit.getCredit().add(unitCreditSplit.getCredit()));
          } else {
            ProposalUnitCreditSplit creditSplit = new ProposalUnitCreditSplit();
            creditSplit.setCredit(unitCreditSplit.getCredit());
            totalUnitSplits.put(unitCreditSplit.getInvCreditTypeCode(), creditSplit);
          }
        }
      }

      ProposalCreditSplitListDto unitTotalLine = new ProposalCreditSplitListDto();
      unitTotalLine.setDescription("Unit Total:");
      unitTotalLine.setLineType("unit-total");
      for (Map.Entry<String, ProposalUnitCreditSplit> entry : totalUnitSplits.entrySet()) {
        unitTotalLine.getCreditSplits().add(0, entry.getValue());
      }
      creditSplitListItems.add(unitTotalLine);
    }

    ProposalCreditSplitListDto investigatorTotalLine = new ProposalCreditSplitListDto();
    investigatorTotalLine.setDescription("Investigator Total:");
    investigatorTotalLine.setLineType("investigator-total");
    for (Map.Entry<String, ProposalPersonCreditSplit> entry : totalInvestigatorSplits.entrySet()) {
      investigatorTotalLine.getCreditSplits().add(0, entry.getValue());
    }
    creditSplitListItems.add(investigatorTotalLine);

    return creditSplitListItems;
  }
  /**
   * Everytime something changes that will effect credit split values, this gets called to generate
   * a graph of the new data.
   *
   * @param document
   * @return Map
   */
  public Map calculateCreditSplitTotals(ProposalDevelopmentDocument document) {
    Map<String, Map<String, ScaleTwoDecimal>> retval =
        new HashMap<String, Map<String, ScaleTwoDecimal>>();

    // Initialize investigator credit types if there aren't any
    if (document.getDevelopmentProposal().getInvestigatorCreditTypes() == null
        || document.getDevelopmentProposal().getInvestigatorCreditTypes().size() == 0) {
      document.getDevelopmentProposal().setInvestigatorCreditTypes(getInvestigatorCreditTypes());
    }

    Collection<InvestigatorCreditType> creditTypes =
        document.getDevelopmentProposal().getInvestigatorCreditTypes();

    for (ProposalPerson investigator : document.getDevelopmentProposal().getInvestigators()) {
      Map<String, ScaleTwoDecimal> creditTypeTotals =
          retval.get(investigator.getProposalPersonNumber().toString());
      Map<String, ScaleTwoDecimal> investigatorCreditTypeTotals =
          retval.get(PROPOSAL_PERSON_INVESTIGATOR);

      if (creditTypeTotals == null) {
        creditTypeTotals = new HashMap<String, ScaleTwoDecimal>();
        retval.put(investigator.getProposalPersonNumber().toString(), creditTypeTotals);
      }
      if (investigatorCreditTypeTotals == null) {
        investigatorCreditTypeTotals = new HashMap<String, ScaleTwoDecimal>();
        retval.put(PROPOSAL_PERSON_INVESTIGATOR, investigatorCreditTypeTotals);
      }

      // Initialize everything to zero
      for (InvestigatorCreditType creditType : creditTypes) {
        ScaleTwoDecimal totalCredit = creditTypeTotals.get(creditType.getCode());

        if (totalCredit == null) {
          totalCredit = new ScaleTwoDecimal(0);
          creditTypeTotals.put(creditType.getCode(), totalCredit);
        }
        ScaleTwoDecimal investigatorTotalCredit =
            investigatorCreditTypeTotals.get(creditType.getCode());

        if (investigatorTotalCredit == null) {
          investigatorTotalCredit = new ScaleTwoDecimal(0);
          investigatorCreditTypeTotals.put(creditType.getCode(), investigatorTotalCredit);
        }
        // set investigator credit total
        for (CreditSplit creditSplit : investigator.getCreditSplits()) {
          if (creditSplit.getInvCreditTypeCode().equals(creditType.getCode())) {
            investigatorCreditTypeTotals.put(
                creditType.getCode(), investigatorTotalCredit.add(creditSplit.getCredit()));
          }
        }
      }

      for (ProposalPersonUnit unit : investigator.getUnits()) {
        for (CreditSplit creditSplit : unit.getCreditSplits()) {
          ScaleTwoDecimal totalCredit = creditTypeTotals.get(creditSplit.getInvCreditTypeCode());

          if (totalCredit == null) {
            totalCredit = new ScaleTwoDecimal(0);
            creditTypeTotals.put(creditSplit.getInvCreditTypeCode(), totalCredit);
          }
          creditTypeTotals.put(
              creditSplit.getInvCreditTypeCode(), totalCredit.add(creditSplit.getCredit()));
        }
      }
    }

    return retval;
  }
  public void addProposalPerson(
      ProposalPerson proposalPerson, ProposalDevelopmentDocument document) {
    getPersonEditableService().populateContactFields(proposalPerson);
    document.getDevelopmentProposal().addProposalPerson(proposalPerson);

    LOG.info(
        "Added Proposal Person with proposalNumber = "
            + document.getDevelopmentProposal().getProposalNumber()
            + " and proposalPersonNumber = "
            + proposalPerson.getProposalPersonNumber());
    // handle lead unit for investigators respective to coi or pi
    if (proposalPerson.isPrincipalInvestigator()) {
      assignLeadUnit(proposalPerson, document.getDevelopmentProposal().getOwnedByUnitNumber());
    } else {
      // Lead Unit information needs to be removed in case the person used to be a PI
      ProposalPersonUnit unit =
          proposalPerson.getUnit(document.getDevelopmentProposal().getOwnedByUnitNumber());
      if (unit != null) {
        unit.setLeadUnit(false);
      }
    }
    if (proposalPerson.getHomeUnit() != null) {
      proposalPerson.refreshReferenceObject("homeUnitRef");
      String divisionName =
          getProposalPersonService().getProposalPersonDivisionName(proposalPerson);
      proposalPerson.setDivision(divisionName);
    } else {
      proposalPerson.setDivision(ROLODEX_PERSON);
    }
    if (proposalPerson.getProposalPersonRoleId().equals(PRINCIPAL_INVESTIGATOR_ROLE)
        || proposalPerson.getProposalPersonRoleId().equals(CO_INVESTIGATOR_ROLE)) {
      if (isNotBlank(proposalPerson.getHomeUnit())
          && isValidHomeUnit(proposalPerson, proposalPerson.getHomeUnit())) {
        addUnitToPerson(
            proposalPerson, createProposalPersonUnit(proposalPerson.getHomeUnit(), proposalPerson));
      }
    }

    populateProposalPerson(proposalPerson, document);
  }