/**
   * Overridden to guarantee that form of copied document is set to whatever the entry mode of the
   * document is
   *
   * @see org.kuali.rice.kns.web.struts.action.KualiTransactionalDocumentActionBase#copy
   *     (org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm,
   *     javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
   */
  @Override
  public ActionForward copy(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
    ActionForward forward = null;
    String docID = "docId";
    if (request.getParameter(docID) == null) {
      forward = super.copy(mapping, form, request, response);
    } else {
      // this is copy document from Procurement Gateway:
      // use this url to call:
      // http://localhost:8080/kfs-dev/purapRequisition.do?methodToCall=copy&docId=xxxx
      String docId = request.getParameter(docID);
      KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;

      CuRequisitionDocument document = null;
      document = (CuRequisitionDocument) getDocumentService().getByDocumentHeaderId(docId);
      document.toCopyFromGateway();

      kualiDocumentFormBase.setDocument(document);
      WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
      kualiDocumentFormBase.setDocTypeName(workflowDocument.getDocumentTypeName());
      SpringContext.getBean(SessionDocumentService.class)
          .addDocumentToUserSession(GlobalVariables.getUserSession(), workflowDocument);

      forward = mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
    return forward;
  }
  /**
   * Builds and asks questions which require text input by the user for a payment request or a
   * credit memo.
   *
   * @param mapping An ActionMapping
   * @param form An ActionForm
   * @param request The HttpServletRequest
   * @param response The HttpServletResponse
   * @param questionType A String used to distinguish which question is being asked
   * @param notePrefix A String explaining what action was taken, to be prepended to the note
   *     containing the reason, which gets written to the document
   * @param operation A one-word String description of the action to be taken, to be substituted
   *     into the message. (Can be an empty String for some messages.)
   * @param messageKey A (whole) key to the message which will appear on the question screen
   * @param questionsAndCallbacks A TreeMap associating the type of question to be asked and the
   *     type of callback which should happen in that case
   * @param messagePrefix The most general part of a key to a message text to be retrieved from
   *     ConfigurationService, Describes a collection of questions.
   * @param redirect An ActionForward to return to if done with questions
   * @return An ActionForward
   * @throws Exception
   */
  protected ActionForward askQuestionWithInput(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response,
      String questionType,
      String notePrefix,
      String operation,
      String messageKey,
      TreeMap<String, PurQuestionCallback> questionsAndCallbacks,
      String messagePrefix,
      ActionForward redirect)
      throws Exception {
    KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
    AccountsPayableDocumentBase apDocument =
        (AccountsPayableDocumentBase) kualiDocumentFormBase.getDocument();

    String question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
    String reason = request.getParameter(KFSConstants.QUESTION_REASON_ATTRIBUTE_NAME);
    String noteText = "";

    ConfigurationService kualiConfiguration = SpringContext.getBean(ConfigurationService.class);
    String firstQuestion = questionsAndCallbacks.firstKey();
    PurQuestionCallback callback = null;
    Iterator questions = questionsAndCallbacks.keySet().iterator();
    String mapQuestion = null;
    String key = null;

    // Start in logic for confirming the close.
    if (question == null) {
      key = getQuestionProperty(messageKey, messagePrefix, kualiConfiguration, firstQuestion);
      String message = StringUtils.replace(key, "{0}", operation);

      // Ask question if not already asked.
      return this.performQuestionWithInput(
          mapping,
          form,
          request,
          response,
          firstQuestion,
          message,
          KFSConstants.CONFIRMATION_QUESTION,
          questionType,
          "");
    } else {
      // find callback for this question
      while (questions.hasNext()) {
        mapQuestion = (String) questions.next();

        if (StringUtils.equals(mapQuestion, question)) {
          callback = questionsAndCallbacks.get(mapQuestion);
          break;
        }
      }
      key = getQuestionProperty(messageKey, messagePrefix, kualiConfiguration, mapQuestion);

      Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
      if (question.equals(mapQuestion) && buttonClicked.equals(ConfirmationQuestion.NO)) {
        // If 'No' is the button clicked, just reload the doc

        String nextQuestion = null;
        // ask another question if more left
        if (questions.hasNext()) {
          nextQuestion = (String) questions.next();
          key = getQuestionProperty(messageKey, messagePrefix, kualiConfiguration, nextQuestion);

          return this.performQuestionWithInput(
              mapping,
              form,
              request,
              response,
              nextQuestion,
              key,
              KFSConstants.CONFIRMATION_QUESTION,
              questionType,
              "");
        } else {

          return mapping.findForward(KFSConstants.MAPPING_BASIC);
        }
      }
      // Have to check length on value entered.
      String introNoteMessage = notePrefix + KFSConstants.BLANK_SPACE;

      // Build out full message.
      noteText = introNoteMessage + reason;
      int noteTextLength = noteText.length();

      // Get note text max length from DD.
      int noteTextMaxLength =
          SpringContext.getBean(DataDictionaryService.class)
              .getAttributeMaxLength(Note.class, KFSConstants.NOTE_TEXT_PROPERTY_NAME)
              .intValue();
      if (StringUtils.isBlank(reason) || (noteTextLength > noteTextMaxLength)) {
        // Figure out exact number of characters that the user can enter.
        int reasonLimit = noteTextMaxLength - noteTextLength;
        if (reason == null) {
          // Prevent a NPE by setting the reason to a blank string.
          reason = "";
        }

        return this.performQuestionWithInputAgainBecauseOfErrors(
            mapping,
            form,
            request,
            response,
            mapQuestion,
            key,
            KFSConstants.CONFIRMATION_QUESTION,
            questionType,
            "",
            reason,
            PurapKeyConstants.ERROR_PAYMENT_REQUEST_REASON_REQUIRED,
            KFSConstants.QUESTION_REASON_ATTRIBUTE_NAME,
            new Integer(reasonLimit).toString());
      }
    }

    // make callback
    if (ObjectUtils.isNotNull(callback)) {
      AccountsPayableDocument refreshedApDocument = callback.doPostQuestion(apDocument, noteText);
      kualiDocumentFormBase.setDocument(refreshedApDocument);
    }
    String nextQuestion = null;
    // ask another question if more left
    if (questions.hasNext()) {
      nextQuestion = (String) questions.next();
      key = getQuestionProperty(messageKey, messagePrefix, kualiConfiguration, nextQuestion);

      return this.performQuestionWithInput(
          mapping,
          form,
          request,
          response,
          nextQuestion,
          key,
          KFSConstants.CONFIRMATION_QUESTION,
          questionType,
          "");
    }

    return redirect;
  }