/**
   * This action executes an insert of a SourceAccountingLine into a document only after validating
   * the accounting line and checking any appropriate business rules.
   *
   * @param mapping
   * @param form
   * @param request
   * @param response
   * @return ActionForward
   * @throws Exception
   */
  public ActionForward insertSourceLine(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
    KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;
    SourceAccountingLine line = financialDocumentForm.getNewSourceLine();

    // populate chartOfAccountsCode from account number if accounts cant cross chart and Javascript
    // is turned off
    // SpringContext.getBean(AccountService.class).populateAccountingLineChartIfNeeded(line);

    boolean rulePassed = true;
    // DV acct line amount got error during form populate; should not insert this line.
    // KFSUPGRADE-847
    MessageMap msgMap = GlobalVariables.getMessageMap();
    if (msgMap.hasErrors()
        && msgMap.getErrorMessages().keySet().contains("newSourceLine.amount")
        && financialDocumentForm.getDocument() instanceof DisbursementVoucherDocument) {
      rulePassed = false;
    }
    // before we check the regular rules we need to check the sales tax rules
    // TODO: Refactor rules so we no longer have to call this before a copy of the
    // accountingLine
    rulePassed &=
        checkSalesTax(
            (AccountingDocument) financialDocumentForm.getDocument(), line, true, true, 0);
    // check any business rules
    rulePassed &=
        SpringContext.getBean(KualiRuleService.class)
            .applyRules(
                new AddAccountingLineEvent(
                    KFSConstants.NEW_SOURCE_ACCT_LINE_PROPERTY_NAME,
                    financialDocumentForm.getDocument(),
                    line));

    if (rulePassed) {
      // add accountingLine
      SpringContext.getBean(PersistenceService.class).refreshAllNonUpdatingReferences(line);
      insertAccountingLine(true, financialDocumentForm, line);

      // clear the used newTargetLine
      financialDocumentForm.setNewSourceLine(null);
    }

    return mapping.findForward(KFSConstants.MAPPING_BASIC);
  }
  /**
   * Adds check for accountingLine updates, generates and dispatches any events caused by such
   * updates
   *
   * @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping,
   *     org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest,
   *     javax.servlet.http.HttpServletResponse)
   */
  @Override
  public ActionForward execute(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
    KualiAccountingDocumentFormBase transForm = (KualiAccountingDocumentFormBase) form;

    // handle changes to accountingLines
    if (transForm.hasDocumentId()) {
      AccountingDocument financialDocument = (AccountingDocument) transForm.getDocument();

      processAccountingLines(financialDocument, transForm, KFSConstants.SOURCE);
      processAccountingLines(financialDocument, transForm, KFSConstants.TARGET);
    }

    // This is after a potential handleUpdate(), to display automatically cleared overrides
    // following a route or save.
    processAccountingLineOverrides(transForm);

    // proceed as usual
    ActionForward result = super.execute(mapping, form, request, response);
    return result;
  }
  /**
   * Adds the given accountingLine to the appropriate form-related data structures.
   *
   * @param isSource
   * @param financialDocumentForm
   * @param line
   */
  protected void insertAccountingLine(
      boolean isSource,
      KualiAccountingDocumentFormBase financialDocumentForm,
      AccountingLine line) {
    AccountingDocument tdoc = financialDocumentForm.getFinancialDocument();
    if (isSource) {
      // add it to the document
      tdoc.addSourceAccountingLine((SourceAccountingLine) line);

      // add PK fields to sales tax if needed
      if (line.isSalesTaxRequired()) {
        populateSalesTax(line);
      }

      // Update the doc total
      if (tdoc instanceof AmountTotaling)
        ((FinancialSystemDocumentHeader) financialDocumentForm.getDocument().getDocumentHeader())
            .setFinancialDocumentTotalAmount(((AmountTotaling) tdoc).getTotalDollarAmount());
    } else {
      // add it to the document
      tdoc.addTargetAccountingLine((TargetAccountingLine) line);

      // add PK fields to sales tax if needed
      if (line.isSalesTaxRequired()) {
        populateSalesTax(line);
      }
    }
  }
  /**
   * Deletes the source or target accountingLine with the given index from the given form. Assumes
   * that the rule- and form- validation have already occurred.
   *
   * @param isSource
   * @param financialDocumentForm
   * @param deleteIndex
   */
  protected void deleteAccountingLine(
      boolean isSource, KualiAccountingDocumentFormBase financialDocumentForm, int deleteIndex) {
    if (isSource) {
      // remove from document
      financialDocumentForm.getFinancialDocument().getSourceAccountingLines().remove(deleteIndex);

    } else {
      // remove from document
      financialDocumentForm.getFinancialDocument().getTargetAccountingLines().remove(deleteIndex);
    }
    // update the doc total
    AccountingDocument tdoc = (AccountingDocument) financialDocumentForm.getDocument();
    if (tdoc instanceof AmountTotaling) {
      ((FinancialSystemDocumentHeader) financialDocumentForm.getDocument().getDocumentHeader())
          .setFinancialDocumentTotalAmount(((AmountTotaling) tdoc).getTotalDollarAmount());
    }
  }
  /**
   * This method will add a TargetAccountingLine to a FinancialDocument. This assumes that the user
   * presses the add button for a specific accounting line on the document and that the document is
   * represented by a FinancialDocumentFormBase. It first validates the line for data integrity and
   * then checks appropriate business rules.
   *
   * @param mapping
   * @param form
   * @param request
   * @param response
   * @return ActionForward
   * @throws Exception
   */
  public ActionForward insertTargetLine(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
    KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;
    TargetAccountingLine line = financialDocumentForm.getNewTargetLine();

    // populate chartOfAccountsCode from account number if accounts cant cross chart and Javascript
    // is turned off
    // SpringContext.getBean(AccountService.class).populateAccountingLineChartIfNeeded(line);

    boolean rulePassed = true;
    // before we check the regular rules we need to check the sales tax rules
    // TODO: Refactor rules so we no longer have to call this before a copy of the
    // accountingLine
    rulePassed &=
        checkSalesTax(
            (AccountingDocument) financialDocumentForm.getDocument(), line, false, true, 0);

    // check any business rules
    rulePassed &=
        SpringContext.getBean(KualiRuleService.class)
            .applyRules(
                new AddAccountingLineEvent(
                    KFSConstants.NEW_TARGET_ACCT_LINE_PROPERTY_NAME,
                    financialDocumentForm.getDocument(),
                    line));

    // if the rule evaluation passed, let's add it
    if (rulePassed) {
      // add accountingLine
      SpringContext.getBean(PersistenceService.class).refreshAllNonUpdatingReferences(line);
      insertAccountingLine(false, financialDocumentForm, line);

      // clear the used newTargetLine
      financialDocumentForm.setNewTargetLine(null);
    }

    return mapping.findForward(KFSConstants.MAPPING_BASIC);
  }
  /** @param transForm */
  protected void processAccountingLineOverrides(KualiAccountingDocumentFormBase transForm) {
    processAccountingLineOverrides(transForm.getNewSourceLine());
    processAccountingLineOverrides(transForm.getNewTargetLine());
    if (transForm.hasDocumentId()) {
      AccountingDocument financialDocument = (AccountingDocument) transForm.getDocument();

      processAccountingLineOverrides(
          financialDocument, financialDocument.getSourceAccountingLines());
      processAccountingLineOverrides(
          financialDocument, financialDocument.getTargetAccountingLines());
    }
  }
  /**
   * This method will remove a SourceAccountingLine from a FinancialDocument. This assumes that the
   * user presses the delete button for a specific accounting line on the document and that the
   * document is represented by a FinancialDocumentFormBase.
   *
   * @param mapping
   * @param form
   * @param request
   * @param response
   * @return ActionForward
   * @throws Exception
   */
  public ActionForward deleteSourceLine(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
    KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;

    int deleteIndex = getLineToDelete(request);
    String errorPath =
        KFSConstants.DOCUMENT_PROPERTY_NAME
            + "."
            + KFSConstants.EXISTING_SOURCE_ACCT_LINE_PROPERTY_NAME
            + "["
            + deleteIndex
            + "]";
    boolean rulePassed =
        SpringContext.getBean(KualiRuleService.class)
            .applyRules(
                new DeleteAccountingLineEvent(
                    errorPath,
                    financialDocumentForm.getDocument(),
                    ((AccountingDocument) financialDocumentForm.getDocument())
                        .getSourceAccountingLine(deleteIndex),
                    false));

    // if the rule evaluation passed, let's delete it
    if (rulePassed) {
      deleteAccountingLine(true, financialDocumentForm, deleteIndex);
    } else {
      String[] errorParams = new String[] {"source", Integer.toString(deleteIndex + 1)};
      GlobalVariables.getMessageMap()
          .putError(
              errorPath,
              KFSKeyConstants.ERROR_ACCOUNTINGLINE_DELETERULE_INVALIDACCOUNT,
              errorParams);
    }

    return mapping.findForward(KFSConstants.MAPPING_BASIC);
  }
  /**
   * This method refreshes the sales tax fields on a refresh or tab toggle so that all the
   * information that was there before is still there after a state change
   *
   * @param form
   */
  protected void refreshSalesTaxInfo(ActionForm form) {
    KualiAccountingDocumentFormBase accountingForm = (KualiAccountingDocumentFormBase) form;
    AccountingDocument document = (AccountingDocument) accountingForm.getDocument();
    List sourceLines = document.getSourceAccountingLines();
    List targetLines = document.getTargetAccountingLines();
    handleSalesTaxRequiredAllLines(accountingForm, sourceLines);
    handleSalesTaxRequiredAllLines(accountingForm, targetLines);

    AccountingLine newTargetLine = accountingForm.getNewTargetLine();
    AccountingLine newSourceLine = accountingForm.getNewSourceLine();
    if (newTargetLine != null) {
      handleSalesTaxRequired(document, newTargetLine, false, true, 0);
    }
    if (newSourceLine != null) {
      handleSalesTaxRequired(document, newSourceLine, true, true, 0);
    }
  }