public static Set<Set<Obs>> generateObsGroupFromSearchResults() {
    Set<Set<Obs>> obsGroups = new HashSet<Set<Obs>>();

    SearchAPI searchAPI = SearchAPI.getInstance();
    List<ChartListItem> searchResultsList = searchAPI.getResults();
    for (ChartListItem item :
        searchResultsList) { // for each item in results we classify it by its obsGroup, and add all
                             // of the group.
      if (item != null && item instanceof ObsItem && ((ObsItem) item).getObsId() != null) {
        int itemObsId = ((ObsItem) item).getObsId();
        Obs obsGrp = Context.getObsService().getObs(itemObsId).getObsGroup();
        if (obsGrp != null) {
          int groupId = obsGrp.getId();
          Set<Obs> obsGroup = obsGrp.getGroupMembers();
          boolean found = false; // if found == true then we don't need to add the group.
          for (Set<Obs> grp : obsGroups) {
            Obs ob = new Obs(-1);
            if (grp.iterator().hasNext()) {
              ob = grp.iterator().next();
            }
            if (ob.getObsGroup() != null && ob.getObsGroup().getId() != null) {
              if (ob.getObsGroup().getId() == groupId) {
                found = true;
              }
            }
          }
          if (!found) {
            obsGroups.add(obsGroup);
          }
        }
      }
    }
    return obsGroups;
  }
  @SuppressWarnings("unused")
  public static JSONObject createJsonObservation(Obs obs) {
    JSONObject jsonObs = new JSONObject();
    jsonObs.put("observation_id", obs.getObsId());
    jsonObs.put("concept_name", obs.getConcept().getDisplayString());

    Date obsDate = obs.getObsDatetime() == null ? new Date() : obs.getObsDatetime();

    SimpleDateFormat formatDateJava = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
    String dateStr = obsDate.getTime() + "";

    jsonObs.put("date", dateStr);

    if (obs.getConcept().getDatatype().isNumeric()) { // ADD MORE DATATYPES

      ConceptNumeric conceptNumeric =
          Context.getConceptService().getConceptNumeric(obs.getConcept().getId());
      jsonObs.put("units_of_measurement", conceptNumeric.getUnits());
      jsonObs.put("absolute_high", conceptNumeric.getHiAbsolute());
      jsonObs.put("absolute_low", conceptNumeric.getLowAbsolute());
      jsonObs.put("critical_high", conceptNumeric.getHiCritical());
      jsonObs.put("critical_low", conceptNumeric.getLowCritical());
      jsonObs.put("normal_high", conceptNumeric.getHiNormal());
      jsonObs.put("normal_low", conceptNumeric.getLowNormal());
    }
    jsonObs.put("value_type", obs.getConcept().getDatatype().getName());

    jsonObs.put("value", obs.getValueAsString(Context.getLocale()));
    jsonObs.put("location", obs.getLocation().getDisplayString());
    jsonObs.put("creator", obs.getCreator().getDisplayString());
    Set<EncounterProvider> encounterProviders = obs.getEncounter().getEncounterProviders();

    if (encounterProviders != null && encounterProviders.iterator().hasNext()) {
      EncounterProvider provider = encounterProviders.iterator().next();
      if (provider.getProvider() != null) {
        jsonObs.put("provider", provider.getProvider().getName());
      }
    }

    SearchAPI searchAPI = SearchAPI.getInstance();
    if (!searchAPI.getSearchPhrase().getPhrase().equals("")
        && !searchAPI.getSearchPhrase().getPhrase().equals("*")) {
      for (ChartListItem item : searchAPI.getResults()) {
        if (item != null && item instanceof ObsItem && ((ObsItem) item).getObsId() != null) {
          if (((ObsItem) item).getObsId() == obs.getObsId()) {
            jsonObs.put("chosen", "true");
          }
        }
      }
    }

    return jsonObs;
  }
  public static Set<Obs> generateObsSinglesFromSearchResults() {
    SearchAPI searchAPI = SearchAPI.getInstance();
    Set<Obs> obsSingles = new HashSet<Obs>();
    for (ChartListItem item : searchAPI.getResults()) {
      if (item != null && item instanceof ObsItem && ((ObsItem) item).getObsId() != null) {
        int itemObsId = ((ObsItem) item).getObsId();

        Obs obs = Context.getObsService().getObs(itemObsId);
        if (obs != null && obs.getObsGroup() == null && !obs.isObsGrouping()) {
          obsSingles.add(Context.getObsService().getObs(itemObsId));
        }
      }
    }
    return obsSingles;
  }
  public static Set<String> generateDatatypesFromResults() {
    Set<String> res = new HashSet<String>();
    SearchAPI searchAPI = SearchAPI.getInstance();

    for (ChartListItem item : searchAPI.getResults()) {
      if (item != null && item instanceof ObsItem && ((ObsItem) item).getObsId() != null) {
        int itemObsId = ((ObsItem) item).getObsId();

        Obs obs = Context.getObsService().getObs(itemObsId);
        if (obs != null) {
          res.add(obs.getConcept().getDatatype().getName());
        }
      }
    }
    return res;
  }
 private static String[] getAllPossibleSuggestionsAsArray() {
   List<String> allPossibleSuggestions =
       chartSearchService.getAllPossibleSearchSuggestions(SearchAPI.getPatientId());
   String[] searchSuggestions = new String[allPossibleSuggestions.size()];
   searchSuggestions = (String[]) allPossibleSuggestions.toArray(searchSuggestions);
   return searchSuggestions;
 }
  public static Set<Encounter> generateEncountersFromSearchResults() {
    SearchAPI searchAPI = SearchAPI.getInstance();
    Set<Encounter> encounters = new HashSet<Encounter>();
    List<ChartListItem> searchResultsList = searchAPI.getResults();
    for (ChartListItem item : searchResultsList) {
      if (item != null
          && item instanceof EncounterItem
          && ((EncounterItem) item).getEncounterId() != null) {
        int itemEncounterId = ((EncounterItem) item).getEncounterId();

        Encounter encounter = Context.getEncounterService().getEncounter(itemEncounterId);
        if (encounter != null) {
          encounters.add(Context.getEncounterService().getEncounter(itemEncounterId));
        }
      }
    }
    return encounters;
  }
  public static Set<Form> generateFormsFromSearchResults() {
    SearchAPI searchAPI = SearchAPI.getInstance();
    Set<Form> forms = new HashSet<Form>();
    List<ChartListItem> searchResultsList = searchAPI.getResults();

    for (ChartListItem item : searchResultsList) {

      if (item != null && item instanceof FormItem) {

        if (((FormItem) item).getFormId() != null) {
          int itemFormId = ((FormItem) item).getFormId();
          Form form = Context.getFormService().getForm(itemFormId);
          if (form != null) {
            forms.add(Context.getFormService().getForm(itemFormId));
          }
        }
      }
    }
    return forms;
  }
  public static Set<String> generateProvidersFromResults() {
    Set<String> res = new HashSet<String>();
    SearchAPI searchAPI = SearchAPI.getInstance();

    for (ChartListItem item : searchAPI.getResults()) {
      if (item != null && item instanceof ObsItem && ((ObsItem) item).getObsId() != null) {
        int itemObsId = ((ObsItem) item).getObsId();

        Obs obs = Context.getObsService().getObs(itemObsId);
        if (obs != null) {
          Set<EncounterProvider> encounterProviders = obs.getEncounter().getEncounterProviders();

          if (encounterProviders != null && encounterProviders.iterator().hasNext()) {
            EncounterProvider provider = encounterProviders.iterator().next();
            if (provider.getProvider() != null) {
              res.add(provider.getProvider().getName());
            }
          }
        }
      }
    }
    return res;
  }
  public static JSONArray getAllSearchHistoriesToSendToTheUI() {
    JSONArray histories = new JSONArray();
    List<ChartSearchHistory> allHistory = chartSearchService.getAllSearchHistory();

    for (ChartSearchHistory history : allHistory) {
      JSONObject json = null;
      if (Context.getAuthenticatedUser().getUserId().equals(history.getHistoryOwner().getUserId())
          && history.getPatient().getPatientId().equals(SearchAPI.getInstance().getPatientId())) {
        json = generateHistoryJSON(history);
      }
      if (json != null) {
        histories.add(json);
      }
    }

    return histories;
  }
  public static JSONArray getAllSearchBookmarksToReturnToUI() {
    JSONArray bookmarks = new JSONArray();
    List<ChartSearchBookmark> allBookmarks = chartSearchService.getAllSearchBookmarks();

    for (ChartSearchBookmark curBookmark : allBookmarks) {
      JSONObject json = null;

      if (Context.getAuthenticatedUser()
              .getUserId()
              .equals(curBookmark.getBookmarkOwner().getUserId())
          && curBookmark
              .getPatient()
              .getPatientId()
              .equals(SearchAPI.getInstance().getPatientId())) {
        json = generateBookmarksJSON(curBookmark);
      }

      if (json != null) {
        bookmarks.add(json);
      }
    }
    return bookmarks;
  }
  public static String generateJson() {

    JSONObject jsonToReturn = new JSONObject();
    List<ChartListItem> returnedResults = SearchAPI.getInstance().getResults();
    boolean foundNoResults = false;
    JSONObject noResults = new JSONObject();
    String searchPhrase = SearchAPI.getInstance().getSearchPhrase().getPhrase();

    jsonToReturn.put("search_phrase", searchPhrase);

    if (returnedResults == null || returnedResults.isEmpty()) {
      foundNoResults = true;
      noResults.put("foundNoResults", foundNoResults);
      noResults.put(
          "foundNoResultsMessage",
          Context.getMessageSourceService().getMessage("chartsearch.results.foundNoResults"));
    } else {
      JSONArray arr_of_groups = new JSONArray();

      JSONArray arr_of_locations = new JSONArray();
      JSONArray arr_of_providers = new JSONArray();
      JSONArray arr_of_datatypes = new JSONArray();
      JSONObject failedPrivilegeMessages = new JSONObject();

      noResults.put("foundNoResults", foundNoResults);
      addObjectsToJsonToReturnElseAddFailedPrivilegesMessages(
          jsonToReturn,
          arr_of_groups,
          arr_of_locations,
          arr_of_providers,
          arr_of_datatypes,
          failedPrivilegeMessages);

      addFacetsToJSONObjectToReturn(jsonToReturn);

      // add failed privileges to json to be returned to the view
      jsonToReturn.put("failedPrivileges", failedPrivilegeMessages);
    }
    String[] searchSuggestions = getAllPossibleSuggestionsAsArray();
    Integer patientId = SearchAPI.getInstance().getPatientId();

    JSONArray history = getAllSearchHistoriesToSendToTheUI();
    JSONArray bookmarks = getAllSearchBookmarksToReturnToUI();
    List<String> catNms = SearchAPI.getSelectedCategoryNames();
    JSONArray allergies = generateAllergiesJSONFromResults(returnedResults);
    JSONArray appointments = generateAppointmentsJSONFromResults(returnedResults);

    jsonToReturn.put("noResults", noResults);
    jsonToReturn.put("retrievalTime", SearchAPI.getInstance().getRetrievalTime());
    jsonToReturn.put("searchSuggestions", searchSuggestions);
    jsonToReturn.put("searchHistory", history);
    jsonToReturn.put("searchBookmarks", bookmarks);
    jsonToReturn.put("appliedCategories", (String[]) catNms.toArray(new String[catNms.size()]));
    jsonToReturn.put("patientAllergies", allergies);
    jsonToReturn.put("patientAppointments", appointments);
    jsonToReturn.put("allLocations", getChartSearchService().getAllLocationsFromTheDB());
    jsonToReturn.put("allProviders", getChartSearchService().getAllProvidersFromTheDB());
    jsonToReturn.put("categoryFilters", generateAllCategoriesJSON());

    addBothPersonalAndGlobalNotesToJSON(searchPhrase, patientId, jsonToReturn);

    return jsonToReturn.toString();
  }