@ModelAttribute("command")
  public FormEntrySession getFormEntrySession(
      HttpServletRequest request,
      // @RequestParam doesn't pick up query parameters (in the url) in a POST, so I'm handling
      // encounterId, modeParam, and which specially
      /*@RequestParam(value="mode", required=false) String modeParam,*/
      /*@RequestParam(value="encounterId", required=false) Integer encounterId,*/
      /*@RequestParam(value="which", required=false) String which,*/
      @RequestParam(value = "patientId", required = false) Integer patientId,
      /*@RequestParam(value="personId", required=false) Integer personId,*/
      @RequestParam(value = "formId", required = false) Integer formId,
      @RequestParam(value = "htmlformId", required = false) Integer htmlFormId,
      @RequestParam(value = "returnUrl", required = false) String returnUrl,
      @RequestParam(value = "formModifiedTimestamp", required = false) Long formModifiedTimestamp,
      @RequestParam(value = "encounterModifiedTimestamp", required = false)
          Long encounterModifiedTimestamp)
      throws Exception {

    long ts = System.currentTimeMillis();

    Mode mode = Mode.VIEW;

    Integer personId = null;

    if (StringUtils.hasText(request.getParameter("personId"))) {
      personId = Integer.valueOf(request.getParameter("personId"));
    }

    String modeParam = request.getParameter("mode");
    if ("enter".equalsIgnoreCase(modeParam)) {
      mode = Mode.ENTER;
    } else if ("edit".equalsIgnoreCase(modeParam)) {
      mode = Mode.EDIT;
    }

    Patient patient = null;
    Encounter encounter = null;
    Form form = null;
    HtmlForm htmlForm = null;

    if (StringUtils.hasText(request.getParameter("encounterId"))) {

      Integer encounterId = Integer.valueOf(request.getParameter("encounterId"));
      encounter = Context.getEncounterService().getEncounter(encounterId);
      if (encounter == null)
        throw new IllegalArgumentException("No encounter with id=" + encounterId);
      patient = encounter.getPatient();
      patientId = patient.getPatientId();
      personId = patient.getPersonId();

      if (formId
          != null) { // I think formId is allowed to differ from encounter.form.id because of
                     // HtmlFormFlowsheet
        form = Context.getFormService().getForm(formId);
        htmlForm = HtmlFormEntryUtil.getService().getHtmlFormByForm(form);
        if (htmlForm == null)
          throw new IllegalArgumentException("No HtmlForm associated with formId " + formId);
      } else {
        form = encounter.getForm();
        htmlForm = HtmlFormEntryUtil.getService().getHtmlFormByForm(encounter.getForm());
        if (htmlForm == null)
          throw new IllegalArgumentException(
              "The form for the specified encounter ("
                  + encounter.getForm()
                  + ") does not have an HtmlForm associated with it");
      }

    } else { // no encounter specified

      // get person from patientId/personId (register module uses patientId, htmlformentry uses
      // personId)
      if (patientId != null) {
        personId = patientId;
      }
      if (personId != null) {
        patient = Context.getPatientService().getPatient(personId);
      }

      // determine form
      if (htmlFormId != null) {
        htmlForm = HtmlFormEntryUtil.getService().getHtmlForm(htmlFormId);
      } else if (formId != null) {
        form = Context.getFormService().getForm(formId);
        htmlForm = HtmlFormEntryUtil.getService().getHtmlFormByForm(form);
      }
      if (htmlForm == null) {
        throw new IllegalArgumentException(
            "You must specify either an htmlFormId or a formId for a valid html form");
      }

      String which = request.getParameter("which");
      if (StringUtils.hasText(which)) {
        if (patient == null)
          throw new IllegalArgumentException(
              "Cannot specify 'which' without specifying a person/patient");
        List<Encounter> encs =
            Context.getEncounterService()
                .getEncounters(
                    patient, null, null, null, Collections.singleton(form), null, null, false);
        if (which.equals("first")) {
          encounter = encs.get(0);
        } else if (which.equals("last")) {
          encounter = encs.get(encs.size() - 1);
        } else {
          throw new IllegalArgumentException("which must be 'first' or 'last'");
        }
      }
    }

    if (mode != Mode.ENTER && patient == null)
      throw new IllegalArgumentException(
          "No patient with id of personId=" + personId + " or patientId=" + patientId);

    FormEntrySession session = null;
    if (mode == Mode.ENTER && patient == null) {
      patient = new Patient();
    }
    if (encounter != null) {
      session = new FormEntrySession(patient, encounter, mode, htmlForm);
    } else {
      session = new FormEntrySession(patient, htmlForm);
    }

    if (StringUtils.hasText(returnUrl)) {
      session.setReturnUrl(returnUrl);
    }

    // Since we're not using a sessionForm, we need to check for the case where the underlying form
    // was modified while a user was filling a form out
    if (formModifiedTimestamp != null) {
      if (!OpenmrsUtil.nullSafeEquals(formModifiedTimestamp, session.getFormModifiedTimestamp())) {
        throw new RuntimeException(
            Context.getMessageSourceService()
                .getMessage("htmlformentry.error.formModifiedBeforeSubmission"));
      }
    }

    // Since we're not using a sessionForm, we need to make sure this encounter hasn't been modified
    // since the user opened it
    if (encounter != null) {
      if (encounterModifiedTimestamp != null
          && !OpenmrsUtil.nullSafeEquals(
              encounterModifiedTimestamp, session.getEncounterModifiedTimestamp())) {
        throw new RuntimeException(
            Context.getMessageSourceService()
                .getMessage("htmlformentry.error.encounterModifiedBeforeSubmission"));
      }
    }

    Context.setVolatileUserData(FORM_IN_PROGRESS_KEY, session);

    log.info("Took " + (System.currentTimeMillis() - ts) + " ms");

    return session;
  }
  @Override
  protected FormEntrySession formBackingObject(HttpServletRequest request) throws Exception {
    long ts = System.currentTimeMillis();

    Integer encounterId = null;
    Encounter encounter = null;
    if (request.getParameter("encounterId") != null
        && !"".equals(request.getParameter("encounterId"))) {
      encounterId = Integer.valueOf(request.getParameter("encounterId"));
      encounter = Context.getEncounterService().getEncounter(encounterId);
    }

    Integer personId = null;
    Patient patient = null;
    if (encounter != null) {
      patient = encounter.getPatient();
      personId = patient.getPersonId();
    } else {
      personId = Integer.valueOf(request.getParameter("personId"));
      patient = Context.getPatientService().getPatient(personId);
      if (patient == null) throw new IllegalArgumentException("No patient with id " + personId);
    }

    HtmlForm htmlForm = null;

    if (encounter != null) {
      htmlForm = HtmlFormEntryUtil.getService().getHtmlFormByForm(encounter.getForm());
      if (htmlForm == null) {
        throw new IllegalArgumentException(
            "The form for the specified encounter ("
                + encounter.getForm()
                + ") does not have an HtmlForm associated with it");
      }
    } else {
      String htmlFormIdParam = request.getParameter("htmlFormId");
      if (StringUtils.hasText(htmlFormIdParam)) {
        htmlForm = HtmlFormEntryUtil.getService().getHtmlForm(Integer.valueOf(htmlFormIdParam));
      }
      String formIdParam = request.getParameter("formId");
      if (StringUtils.hasText(formIdParam)) {
        Form form = Context.getFormService().getForm(Integer.parseInt(formIdParam));
        htmlForm = HtmlFormEntryUtil.getService().getHtmlFormByForm(form);
      }
      if (htmlForm == null) {
        throw new IllegalArgumentException("You must specify either an htmlFormId or a formId");
      }
    }

    FormEntrySession session;
    if (encounter != null) {
      Mode mode = Mode.VIEW;
      if ("EDIT".equals(request.getParameter("mode"))) {
        mode = Mode.EDIT;
      }
      session = new FormEntrySession(patient, encounter, mode, htmlForm);
    } else {
      session = new FormEntrySession(patient, htmlForm);
    }

    String returnUrl = request.getParameter("returnUrl");
    if (StringUtils.hasText(returnUrl)) {
      session.setReturnUrl(returnUrl);
    }

    // In case we're not using a sessionForm, we need to check for the case where the underlying
    // form was modified while a user was filling a form out
    if (StringUtils.hasText(request.getParameter("formModifiedTimestamp"))) {
      long submittedTimestamp = Long.valueOf(request.getParameter("formModifiedTimestamp"));
      if (submittedTimestamp != session.getFormModifiedTimestamp()) {
        throw new RuntimeException(
            Context.getMessageSourceService()
                .getMessage("htmlformentry.error.formModifiedBeforeSubmission"));
      }
    }

    // In case we're not using a sessionForm, we need to make sure this encounter hasn't been
    // modified since the user opened it
    if (encounter != null) {
      try {
        long submittedTimestamp = Long.valueOf(request.getParameter("encounterModifiedTimestamp"));
        if (submittedTimestamp != session.getEncounterModifiedTimestamp()) {
          throw new RuntimeException(
              Context.getMessageSourceService()
                  .getMessage("htmlformentry.error.encounterModifiedBeforeSubmission"));
        }
      } catch (NumberFormatException ex) {
        // this is being opened for the first time, no worries
      }
    }

    Context.setVolatileUserData(FORM_IN_PROGRESS_KEY, session);

    log.warn("Took " + (System.currentTimeMillis() - ts) + " ms");
    return session;
  }
  @RequestMapping(FORM_PATH)
  public ModelAndView handleRequest(HttpServletRequest request) {

    returnUrl = request.getContextPath() + "/module/patientnarratives/patientNarrativesForm.form";

    HtmlFormEntryPortletController htmlFormEntryPortletController;
    FormEntrySession session = null;
    try {
      htmlFormEntryPortletController = new HtmlFormEntryPortletController();
      session = htmlFormEntryPortletController.getFormEntrySession(request);

      List<FormSubmissionError> validationErrors =
          session.getSubmissionController().validateSubmission(session.getContext(), request);
      if (validationErrors != null && validationErrors.size() > 0) {
        // errors.reject("Fix errors");
      }
    } catch (Exception ex) {
      log.error("Exception during form validation", ex);
      // errors.reject("Exception during form validation, see log for more details: " + ex);
    }

    //        if (errors.hasErrors()) {
    //            return new ModelAndView(FORM_PATH, "command", session);
    //        }

    // no form validation errors, proceed with submission

    try {
      session.prepareForSubmit();

      if (session.getContext().getMode() == FormEntryContext.Mode.ENTER
          && session.hasPatientTag()
          && session.getPatient() == null
          && (session.getSubmissionActions().getPersonsToCreate() == null
              || session.getSubmissionActions().getPersonsToCreate().size() == 0))
        throw new IllegalArgumentException("This form is not going to create an Patient");

      if (session.getContext().getMode() == FormEntryContext.Mode.ENTER
          && session.hasEncouterTag()
          && (session.getSubmissionActions().getEncountersToCreate() == null
              || session.getSubmissionActions().getEncountersToCreate().size() == 0))
        throw new IllegalArgumentException("This form is not going to create an encounter");

      session.getSubmissionController().handleFormSubmission(session, request);
      HtmlFormEntryUtil.getService().applyActions(session);
      String successView = session.getReturnUrlWithParameters();

      request
          .getSession()
          .setAttribute(
              WebConstants.OPENMRS_MSG_ATTR, "patientnarratives.module.narrative.save.success");

      if (successView == null)
        successView =
            request.getContextPath() + "/module/patientnarratives/patientNarrativesForm.form";
      if (StringUtils.hasText(request.getParameter("closeAfterSubmission"))) {
        return new ModelAndView(new RedirectView(returnUrl));
        //                return new ModelAndView(closeDialogView, "dialogToClose",
        // request.getParameter("closeAfterSubmission"));
      } else {
        return new ModelAndView(new RedirectView(returnUrl));
        //                return new ModelAndView(new RedirectView(successView));
      }
    } catch (ValidationException ex) {
      log.error("Invalid input:", ex);
      //            errors.reject(ex.getMessage());
    } catch (BadFormDesignException ex) {
      log.error("Bad Form Design:", ex);
      //            errors.reject(ex.getMessage());
    } catch (Exception ex) {
      log.error("Exception trying to submit form", ex);
      StringWriter sw = new StringWriter();
      ex.printStackTrace(new PrintWriter(sw));
      //            errors.reject("Exception! " + ex.getMessage() + "<br/>" + sw.toString());
    }

    //        if ((alert != null) && (alert == true)) {
    //        }
    // if we get here it's because we caught an error trying to submit/apply
    //        return new ModelAndView(returnUrl, "command", session);
    return new ModelAndView(new RedirectView(returnUrl));
  }