/**
   * Gets the form for a given http request.
   *
   * @param request the http request.
   * @return the form.
   */
  private Form getForm(HttpServletRequest request) {
    Form form = null;

    if (Context.isAuthenticated()) {
      FormService fs = Context.getFormService();
      String formId = request.getParameter("formId");
      if (formId != null) {
        try {
          form = fs.getForm(Integer.valueOf(formId));
        } catch (NumberFormatException e) {;
        } // If formId has no readable value defaults to the case where form==null
      }
    }

    if (form == null) {
      form = new Form();
    }

    return form;
  }
  /**
   * The onSubmit function receives the form/command object that was modified by the input form and
   * saves it to the db
   *
   * @see
   *     org.springframework.web.servlet.mvc.SimpleFormController#onSubmit(javax.servlet.http.HttpServletRequest,
   *     javax.servlet.http.HttpServletResponse, java.lang.Object,
   *     org.springframework.validation.BindException)
   */
  @Override
  protected ModelAndView onSubmit(
      HttpServletRequest request, HttpServletResponse response, Object obj, BindException errors)
      throws Exception {

    HttpSession httpSession = request.getSession();
    String view = getFormView();

    if (Context.isAuthenticated()) {
      Form form = (Form) obj;
      MessageSourceAccessor msa = getMessageSourceAccessor();
      String action = request.getParameter("action");
      if (action == null) {
        httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "Form.not.saved");
      } else {
        if (action.equals(msa.getMessage("Form.save"))) {
          try {
            // save form
            form = Context.getFormService().saveForm(form);
            httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "Form.saved");
          } catch (Exception e) {
            log.error("Error while saving form " + form.getFormId(), e);
            errors.reject(e.getMessage());
            httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "Form.not.saved");
            return showForm(request, response, errors);
          }
        } else if (action.equals(msa.getMessage("Form.delete"))) {
          try {
            Context.getFormService().purgeForm(form);
            httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "Form.deleted");
          } catch (DataIntegrityViolationException e) {
            httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "Form.cannot.delete");
            return new ModelAndView(new RedirectView("formEdit.form?formId=" + form.getFormId()));
          } catch (Exception e) {
            log.error("Error while deleting form " + form.getFormId(), e);
            errors.reject(e.getMessage());
            httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "Form.cannot.delete");
            return showForm(request, response, errors);
            // return new ModelAndView(new RedirectView(getSuccessView()));
          }
        } else if (action.equals(msa.getMessage("Form.updateSortOrder"))) {

          FormService fs = Context.getFormService();

          TreeMap<Integer, TreeSet<FormField>> treeMap = FormUtil.getFormStructure(form);
          for (Map.Entry<Integer, TreeSet<FormField>> entry : treeMap.entrySet()) {
            Integer parentFormFieldId = entry.getKey();
            float sortWeight = 0;
            for (FormField formField : entry.getValue()) {
              formField.setSortWeight(sortWeight);
              fs.saveFormField(formField);
              sortWeight += 50;
            }
          }

        } else {
          try {
            Context.getFormService().duplicateForm(form);
            httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "Form.duplicated");
          } catch (Exception e) {
            log.error("Error while duplicating form " + form.getFormId(), e);
            errors.reject(e.getMessage());
            httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "Form.cannot.duplicate");
            return showForm(request, response, errors);
          }
        }

        view = getSuccessView();
      }
    }

    return new ModelAndView(new RedirectView(view));
  }
  /**
   * @see
   *     org.springframework.web.servlet.mvc.SimpleFormController#referenceData(javax.servlet.http.HttpServletRequest,
   *     java.lang.Object, org.springframework.validation.Errors)
   */
  @Override
  protected Map<String, Object> referenceData(HttpServletRequest request, Object obj, Errors error)
      throws Exception {

    Encounter encounter = (Encounter) obj;

    // the generic returned key-value pair mapping
    Map<String, Object> map = new HashMap<String, Object>();

    // obsIds of obs that were edited
    List<Integer> editedObs = new Vector<Integer>();

    // the map returned to the form
    // This is a mapping between the formfield and a list of the Obs/ObsGroup in that field
    // This mapping is sorted according to the comparator in FormField.java
    SortedMap<FormField, List<Obs>> obsMapToReturn = null;
    String sortType =
        Context.getAdministrationService()
            .getGlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_ENCOUNTER_FORM_OBS_SORT_ORDER);
    if ("weight".equals(sortType)) {
      obsMapToReturn = new TreeMap<FormField, List<Obs>>(); // use FormField.compareTo
    } else {
      obsMapToReturn =
          new TreeMap<FormField, List<Obs>>(
              new NumberingFormFieldComparator()); // use custom comparator
    }

    // this maps the obs to form field objects for non top-level obs
    // it is keyed on obs so that when looping over an exploded obsGroup
    // the formfield can be fetched easily (in order to show the field numbers etc)
    Map<Obs, FormField> otherFormFields = new HashMap<Obs, FormField>();

    if (Context.isAuthenticated()) {
      EncounterService es = Context.getEncounterService();
      FormService fs = Context.getFormService();

      // used to restrict the form field lookup
      Form form = encounter.getForm();

      List<EncounterType> encTypes = es.getAllEncounterTypes();
      // Non-retired types first
      Collections.sort(encTypes, new MetadataComparator(Context.getLocale()));
      map.put("encounterTypes", encTypes);

      map.put("encounterRoles", es.getAllEncounterRoles(false));
      map.put("forms", Context.getFormService().getAllForms());
      // loop over the encounter's observations to find the edited obs
      for (Obs o : encounter.getObsAtTopLevel(true)) {

        // only edited obs has previous version
        if (o.hasPreviousVersion()) {
          editedObs.add(o.getObsId());
        }

        // get the formfield for this obs
        FormField ff = fs.getFormField(form, o.getConcept(), obsMapToReturn.keySet(), false);
        if (ff == null) {
          ff = new FormField();
        }

        // we only put the top-level obs in the obsMap.  Those would
        // be the obs that don't have an obs grouper
        if (o.getObsGroup() == null) {
          // populate the obs map with this formfield and obs
          List<Obs> list = obsMapToReturn.get(ff);
          if (list == null) {
            list = new Vector<Obs>();
            obsMapToReturn.put(ff, list);
          }
          list.add(o);
        } else {
          // this is not a top-level obs, just put the formField
          // in a separate list and be done with it
          otherFormFields.put(o, ff);
        }
      }
    }

    if (log.isDebugEnabled()) {
      log.debug("setting obsMap in page context (size: " + obsMapToReturn.size() + ")");
    }
    map.put("obsMap", obsMapToReturn);

    map.put("otherFormFields", otherFormFields);

    map.put("locale", Context.getLocale());
    map.put("editedObs", editedObs);
    if (encounter.getPatient() != null) {
      map.put(
          "patientVisits", Context.getVisitService().getVisitsByPatient(encounter.getPatient()));
    }

    return map;
  }