/**
     *
     * Generates all of the data rows
     *
     * @param form
     * @param extraCols
     * @param sb
     * @return
     * @throws Exception
     */
    public static String generateColumnDataFromHtmlForm(List<Encounter> encounters, HtmlForm form, List<String> extraCols, StringBuffer sb, Locale locale,List<PatientIdentifierType> pitList) throws Exception {
        for (Encounter e: encounters){

            sb.append(DEFAULT_QUOTE).append(e.getEncounterId()).append(DEFAULT_QUOTE).append(DEFAULT_COLUMN_SEPARATOR);
            sb.append(DEFAULT_QUOTE).append(DATE_FORMATTER.format(e.getEncounterDatetime())).append(DEFAULT_QUOTE).append(DEFAULT_COLUMN_SEPARATOR);
            sb.append(DEFAULT_QUOTE).append(e.getLocation().getName()).append(DEFAULT_QUOTE).append(DEFAULT_COLUMN_SEPARATOR);
            sb.append(DEFAULT_QUOTE).append(EncounterCompatibility.getProvider(e).getGivenName()+ " " + EncounterCompatibility.getProvider(e).getFamilyName()).append(DEFAULT_QUOTE).append(DEFAULT_COLUMN_SEPARATOR);
            sb.append(DEFAULT_QUOTE).append((e.getPatient() != null ? e.getPatient().getPatientId() : EMPTY)).append(DEFAULT_QUOTE).append(DEFAULT_COLUMN_SEPARATOR);       
            int index = 1;
            for (PatientIdentifierType pit :  pitList){
                sb.append(DEFAULT_QUOTE).append(e.getPatient().getPatientIdentifier(pit)).append(DEFAULT_QUOTE);
                if (index < pitList.size())
                    sb.append(DEFAULT_COLUMN_SEPARATOR);
                index ++;
            }

            FormEntrySession session = new FormEntrySession(e.getPatient(), e, Mode.VIEW, form, null); // session doesn't get HttpSession
            session.getHtmlToDisplay();
            FormSubmissionController  fsa = session.getSubmissionController();
            List<FormSubmissionControllerAction> actions = fsa.getActions();
            for (FormSubmissionControllerAction fsca : actions){
                if (fsca instanceof ObsSubmissionElement){
                    ObsSubmissionElement ose = (ObsSubmissionElement) fsca;
                    sb = appendObsToRow(ose, sb, extraCols, locale);
                } else {
                    //TODO: add programs, orders, logic, etc...
                    // just make sure these are in the headers too...
                }
            }
            session = null;
            sb.append(DEFAULT_LINE_SEPARATOR);
        }
        return sb.toString();
    }
    /**
     *
     * Generate the header row for the csv file.
     *
     * @param form
     * @param extraCols
     * @return
     * @throws Exception
     */
    public static String generateColumnHeadersFromHtmlForm(HtmlForm form, List<String> extraCols, StringBuffer sb, List<PatientIdentifierType> pitList) throws Exception {
        FormEntrySession session = new FormEntrySession(HtmlFormEntryUtil.getFakePerson(), form, null); // session gets a null HttpSession
        session.getHtmlToDisplay();
        HtmlFormSchema hfs = session.getContext().getSchema();

        sb.append(DEFAULT_QUOTE).append("ENCOUNTER_ID").append(DEFAULT_QUOTE).append(DEFAULT_COLUMN_SEPARATOR)
        .append(DEFAULT_QUOTE).append("ENCOUNTER_DATE").append(DEFAULT_QUOTE).append(DEFAULT_COLUMN_SEPARATOR)
        .append(DEFAULT_QUOTE).append("ENCOUNTER_LOCATION").append(DEFAULT_QUOTE).append(DEFAULT_COLUMN_SEPARATOR)
        .append(DEFAULT_QUOTE).append("ENCOUNTER_PROVIDER").append(DEFAULT_QUOTE).append(DEFAULT_COLUMN_SEPARATOR)
        .append(DEFAULT_QUOTE).append("INTERNAL_PATIENT_ID").append(DEFAULT_QUOTE).append(DEFAULT_COLUMN_SEPARATOR);
        int index = 1;
        for (PatientIdentifierType pit :  pitList){
            sb.append(DEFAULT_QUOTE).append(pit.getName()).append(DEFAULT_QUOTE);
            if (index < pitList.size())
                sb.append(DEFAULT_COLUMN_SEPARATOR);
            index ++;
        }

        Set<HtmlFormField> fields = hfs.getAllFields();

        for (HtmlFormField hfsec : fields) {
            sb = generateColumnHeadersFromHtmlFormHelper(hfsec, extraCols, sb);
        }

        session = null;
        sb.append(DEFAULT_LINE_SEPARATOR);
        return sb.toString();
    }
 /**
  * @see
  *     org.openmrs.module.htmlformentry.handler.SubstitutionTagHandler#getSubstitution(org.openmrs.module.htmlformentry.FormEntrySession,
  *     org.openmrs.module.htmlformentry.FormSubmissionController, java.util.Map)
  * @throws BadFormDesignException
  */
 @Override
 protected String getSubstitution(
     FormEntrySession session,
     FormSubmissionController controllerActions,
     Map<String, String> parameters)
     throws BadFormDesignException {
   ProviderAndRoleElement element = new ProviderAndRoleElement(session.getContext(), parameters);
   session.getSubmissionController().addAction(element);
   return element.generateHtml(session.getContext());
 }
 @Override
 protected void onBindAndValidate(
     HttpServletRequest request, Object commandObject, BindException errors) throws Exception {
   FormEntrySession session = (FormEntrySession) commandObject;
   try {
     List<FormSubmissionError> validationErrors =
         session.getSubmissionController().validateSubmission(session.getContext(), request);
     if (validationErrors == null || validationErrors.size() == 0) {
       return;
     } else {
       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);
   }
 }
  @Override
  public boolean doStartTag(FormEntrySession session, PrintWriter out, Node parent, Node node) {
    Map<String, String> attributes = new HashMap<String, String>();
    NamedNodeMap map = node.getAttributes();
    for (int i = 0; i < map.getLength(); ++i) {
      Node attribute = map.item(i);
      attributes.put(attribute.getNodeName(), attribute.getNodeValue());
    }

    String replacement = getSubstitution(session, session.getSubmissionController(), attributes);
    out.print(replacement);
    return false; // skip contents/children
  }
 /**
  * returns a Map<Integer, String> of all form sections, in order,
  * where the String value is either the specified name, or an arbitrary one if none was given.
  * and the integer is the numeric index of the sections, starting with 0.
  *
  * @param HtmlForm htmlForm
  * @return
  */
 public static Map<Integer, String> getSectionIndex(HtmlForm htmlForm) throws Exception{
     Document doc = HtmlFormEntryUtil.stringToDocument(htmlForm.getXmlData());
     FormEntrySession session = new FormEntrySession(HtmlFormEntryUtil.getFakePerson(), htmlForm, null); // session gets a null HttpSession
     NodeList nl = doc.getElementsByTagName("section");
     Map<Integer, String> ret = new LinkedHashMap<Integer, String>();
     for (int i = 0; i < nl.getLength(); i++){
         Node sectionNode = nl.item(i);
         NamedNodeMap map = sectionNode.getAttributes();
         String headerLabel = "no name specified";
         for (int j = 0; j < map.getLength(); ++j) {
             Node attribute = map.item(j);
             if (attribute.getNodeName().equals("headerLabel")) {
                 headerLabel = attribute.getNodeValue();
             }
             if (attribute.getNodeName().equals("headerCode")) {
                 Translator trans = session.getContext().getTranslator();
                 headerLabel = trans.translate(Context.getLocale().toString(), attribute.getNodeValue());
             }
         }
         ret.put(i, headerLabel);
     }
     return ret;
 }
 @Override
 protected ModelAndView onSubmit(
     HttpServletRequest request,
     HttpServletResponse response,
     Object commandObject,
     BindException errors)
     throws Exception {
   FormEntrySession session = (FormEntrySession) commandObject;
   try {
     session.prepareForSubmit();
     session.getSubmissionController().handleFormSubmission(session, request);
     if (session.getContext().getMode() == Mode.ENTER
         && (session.getSubmissionActions().getEncountersToCreate() == null
             || session.getSubmissionActions().getEncountersToCreate().size() == 0))
       throw new IllegalArgumentException("This form is not going to create an encounter");
     session.applyActions();
     String successView = session.getReturnUrlWithParameters();
     if (successView == null)
       successView = getSuccessView() + "?patientId=" + session.getPatient().getPersonId();
     if (StringUtils.hasText(request.getParameter("closeAfterSubmission"))) {
       return new ModelAndView(
           closeDialogView, "dialogToClose", request.getParameter("closeAfterSubmission"));
     } else {
       return new ModelAndView(new RedirectView(successView));
     }
   } catch (BadFormDesignException ex) {
     log.error("Bad Form Design:", ex);
     errors.reject(ex.getMessage());
     return showForm(request, response, errors);
   } 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());
     return showForm(request, response, errors);
   }
 }
    /**
     *
     * Returns the encounter with the obs that aren't used when populating form are removed.
     * This *doesn't* save the encounter.
     * TODO: handle Orders?
     *
     * @param e
     * @param htmlform
     * @return
     * @throws Exception
     */
    public static Encounter trimEncounterToMatchForm(Encounter e, HtmlForm htmlform) throws Exception {

       //this should move existing obs from session to tag handlers.
        FormEntrySession session = new FormEntrySession(e.getPatient(), e, FormEntryContext.Mode.VIEW, htmlform, null); // session gets a null HttpSession
        session.getHtmlToDisplay();

        if (log.isDebugEnabled()){
            Map<Concept, List<Obs>>  map = session.getContext().getExistingObs();
            if (map != null){
                for (Map.Entry<Concept, List<Obs>> existingObs : map.entrySet()){
                    List<Obs> oList = existingObs.getValue();
                    for (Obs oInner : oList)
                        log.debug("Obs in existingObs " + existingObs.getKey() + " " + oInner.getConcept());
                }
            }
            Map<Obs, Set<Obs>> map2 = session.getContext().getExistingObsInGroups();
            if (map2 != null){
                for (Map.Entry<Obs, Set<Obs>> existingObsInGroups : map2.entrySet()){
                    Set<Obs> oList = existingObsInGroups.getValue();
                    for (Obs oInner : oList)
                        log.debug("Obs in existingObsInGroups " + existingObsInGroups.getKey().getConcept() + " " + oInner.getConcept());
                }
            }
        }
        Encounter ret = new Encounter();
        ret.setCreator(e.getCreator());
        ret.setEncounterDatetime(e.getEncounterDatetime());
        EncounterCompatibility.setProvider(ret, EncounterCompatibility.getProvider(e));
        ret.setLocation(e.getLocation());
        ret.setDateCreated(e.getDateCreated());
        ret.setPatient(e.getPatient());
        //renders new encounter unsave-able:
        ret.setEncounterId(e.getEncounterId());

        for (Obs oTest : e.getAllObs()){
            boolean found = false;
            if (session.getContext().getExistingObs() != null && !oTest.isObsGrouping()){
                List<Obs> obsList = session.getContext().getExistingObs().get(oTest.getConcept());
                if (obsList != null && obsList.size() > 0){
                    for (Obs o : obsList){
                        if (o.getObsId().equals(oTest.getObsId())){
                            found = true;
                            continue;
                        }
                    }
                }
            }
            if (!found && session.getContext().getExistingObsInGroups() != null){
                for (Map.Entry<Obs, Set<Obs>> mapEntry : session.getContext().getExistingObsInGroups().entrySet()){
                    if (mapEntry.getKey().equals(oTest)){
                        found = true;
                        continue;
                    } else {
                        Set<Obs> oSet = mapEntry.getValue();
                        //note: oSet.contains fails for some reason
                        for (Obs o:oSet){
                              if (o.getObsId().equals(oTest.getObsId())){
                                  found = true;
                                  continue;
                              }
                        }
                    }
                }
            }
            if (!found)
                ret.addObs(oTest);
        }
        session = null;
        return ret;
    }
  @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;
  }
  @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;
  }
 protected String getQueryPrameters(
     HttpServletRequest request, FormEntrySession formEntrySession) {
   return "?patientId=" + formEntrySession.getPatient().getPersonId();
 }
  /*
   * I'm using a return type of ModelAndView so I can use RedirectView rather than "redirect:" and preserve the fact that
   * returnUrl values from the pre-annotated-controller days will have the context path already
   */
  @RequestMapping(method = RequestMethod.POST, value = FORM_PATH)
  public ModelAndView handleSubmit(
      @ModelAttribute("command") FormEntrySession session,
      Errors errors,
      HttpServletRequest request,
      Model model)
      throws Exception {
    try {
      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

    session.prepareForSubmit();

    if (session.getContext().getMode() == 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() == 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");

    try {
      session.getSubmissionController().handleFormSubmission(session, request);
      session.applyActions();
      String successView = session.getReturnUrlWithParameters();
      if (successView == null)
        successView =
            request.getContextPath()
                + "/patientDashboard.form"
                + getQueryPrameters(request, session);
      if (StringUtils.hasText(request.getParameter("closeAfterSubmission"))) {
        return new ModelAndView(
            closeDialogView, "dialogToClose", request.getParameter("closeAfterSubmission"));
      } else {
        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 we get here it's because we caught an error trying to submit/apply
    return new ModelAndView(FORM_PATH, "command", 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));
  }
 /** @see FormSubmissionControllerAction#handleSubmission(FormEntrySession, HttpServletRequest) */
 @Override
 public void handleSubmission(FormEntrySession session, HttpServletRequest submission) {
   if (dateWidget != null) {
     Date date = (Date) dateWidget.getValue(session.getContext(), submission);
     if (session.getSubmissionActions().getCurrentEncounter().getEncounterDatetime() != null
         && !session
             .getSubmissionActions()
             .getCurrentEncounter()
             .getEncounterDatetime()
             .equals(date)) {
       session
           .getContext()
           .setPreviousEncounterDate(
               new Date(
                   session
                       .getSubmissionActions()
                       .getCurrentEncounter()
                       .getEncounterDatetime()
                       .getTime()));
     }
     session.getSubmissionActions().getCurrentEncounter().setEncounterDatetime(date);
   }
   if (timeWidget != null) {
     Date time = (Date) timeWidget.getValue(session.getContext(), submission);
     Encounter e = session.getSubmissionActions().getCurrentEncounter();
     Date dateAndTime = HtmlFormEntryUtil.combineDateAndTime(e.getEncounterDatetime(), time);
     e.setEncounterDatetime(dateAndTime);
   }
   if (providerWidget != null) {
     Object value = providerWidget.getValue(session.getContext(), submission);
     Person person = (Person) convertValueToProvider(value);
     session.getSubmissionActions().getCurrentEncounter().setProvider(person);
   }
   if (locationWidget != null) {
     Object value = locationWidget.getValue(session.getContext(), submission);
     Location location =
         (Location) HtmlFormEntryUtil.convertToType(value.toString().trim(), Location.class);
     session.getSubmissionActions().getCurrentEncounter().setLocation(location);
   }
   if (encounterTypeWidget != null) {
     EncounterType encounterType =
         (EncounterType) encounterTypeWidget.getValue(session.getContext(), submission);
     session.getSubmissionActions().getCurrentEncounter().setEncounterType(encounterType);
   }
   if (voidWidget != null) {
     if ("true".equals(voidWidget.getValue(session.getContext(), submission))) {
       session.setVoidEncounter(true);
     } else if ("false".equals(voidWidget.getValue(session.getContext(), submission))) {
       // nothing..  the session.voidEncounter property will be false, and the encounter will be
       // un-voided if already voided
       // otherwise, nothing will happen.  99% of the time the encounter won't be voided to begin
       // with.
     }
   }
 }
  @Override
  public boolean doStartTag(FormEntrySession session, PrintWriter out, Node parent, Node node)
      throws BadFormDesignException {

    List<Disposition> dispositions = null;

    VisitDomainWrapper visitDomainWrapper =
        session.getContext().getVisit() != null
            ? adtService.wrap((Visit) session.getContext().getVisit())
            : null;

    // TODO remove this feature toggle once awaiting admission is toggled one
    if (featureToggles.isFeatureEnabled("awaitingAdmission")) {
      if (visitDomainWrapper == null) {
        dispositions = dispositionService.getDispositions();
      } else {
        dispositions = dispositionService.getValidDispositions(visitDomainWrapper);
      }
    } else {
      dispositions = dispositionService.getDispositions();
    }

    Element dispositionObsGroup = node.getOwnerDocument().createElement("obsgroup");
    dispositionObsGroup.setAttribute(
        "groupingConceptId",
        emrApiProperties.getEmrApiConceptSource().getName()
            + ":"
            + EmrApiConstants.CONCEPT_CODE_DISPOSITION_CONCEPT_SET);

    // TODO: allow the label text to be overwritten, move the message code  to the coreapps module
    Element label = node.getOwnerDocument().createElement("label");
    Element uimessageLabel = node.getOwnerDocument().createElement("uimessage");
    uimessageLabel.setAttribute("code", "emr.consult.disposition");
    label.appendChild(uimessageLabel);
    dispositionObsGroup.appendChild(label);

    // TODO: allow the id to be passed in from the form?
    Element dispositionObs = node.getOwnerDocument().createElement("obs");
    dispositionObs.setAttribute("id", "disposition-" + UUID.randomUUID().toString());
    dispositionObs.setAttribute("style", "dropdown");
    dispositionObs.setAttribute(
        "conceptId",
        emrApiProperties.getEmrApiConceptSource().getName()
            + ":"
            + EmrApiConstants.CONCEPT_CODE_DISPOSITION);
    if (((Element) node).hasAttribute("required")
        && ((Element) node).getAttribute("required").equalsIgnoreCase("true")) {
      dispositionObs.setAttribute("required", "true");
    }

    // add the possible dispositions from the configured disposition retrieved from disposition
    // factory
    List<Control> controls = new ArrayList<Control>();

    String answerConceptIds = "";
    String answerCodes = "";
    Iterator<Disposition> i = dispositions.iterator();

    while (i.hasNext()) {
      Disposition disposition = i.next();

      answerConceptIds = answerConceptIds + disposition.getConceptCode() + (i.hasNext() ? "," : "");
      answerCodes = answerCodes + disposition.getName() + (i.hasNext() ? "," : "");

      // determine if there are any additional observations we need to collect for this disposition
      if (disposition.getAdditionalObs() != null && disposition.getAdditionalObs().size() > 0) {
        controls.add(buildNewControl(disposition, disposition.getAdditionalObs()));
      }
    }

    dispositionObs.setAttribute("answerConceptIds", answerConceptIds);
    dispositionObs.setAttribute("answerCodes", answerCodes);

    if (controls != null && controls.size() > 0) {
      generateControlsElement(dispositionObs, controls);
    }

    dispositionObsGroup.appendChild(dispositionObs);

    if (controls != null && controls.size() > 0) {
      generateAdditionalObsElements(dispositionObsGroup, controls);
    }

    node.appendChild(dispositionObsGroup);

    return true;
  }