/**
   * Refresh the local cache of Flags by loading all enabled Flags from the database Also refresh
   * the privilege cache Note that flags and tags must be eagerly loaded for this to work
   */
  private void refreshCache() {
    // get the enabled flags and all tags for the flag and tag caches
    flagCache = dao.getAllEnabledFlags();
    tagCache = getAllTags();

    // alphabetize the flags, and sort by by priority ranking so that result sets are returned that
    // way
    Collections.sort(flagCache, new FlagAlphaComparator());
    Collections.sort(flagCache, new FlagPriorityComparator());

    // get the privileges associate with the patient flags default user for the privileges cache
    try {
      Context.addProxyPrivilege("View Users");
      String username =
          Context.getAdministrationService().getGlobalProperty("patientflags.username");
      User user = Context.getUserService().getUserByUsername(username);

      if (user != null) {
        if (user.isSuperUser()) { // need to explicitly get all privileges if user is a super user
          privilegeCache = Context.getUserService().getAllPrivileges();
        } else {
          privilegeCache = user.getPrivileges();
        }
      } else {
        privilegeCache = null;
      }
    } finally {
      Context.removeProxyPrivilege("View Users");
    }

    // set the initialized flag to true
    isInitialized = true;
  }
  public final void run() {

    EncounterService es = null;
    UserService us = null;
    try {
      while (es == null || us == null) {
        Thread.sleep(30000);
        if (RwandaPrimaryCareContextAware.getApplicationContext() != null) {
          try {
            log.warn("RwandaPrimaryCare still waiting for app context and services to load...");
            es = Context.getEncounterService();
            us = Context.getUserService();
          } catch (APIException apiEx) {
            apiEx.printStackTrace();
          }
        }
      }
    } catch (InterruptedException ex) {
      ex.printStackTrace();
    }
    try {
      Thread.sleep(10000);
      // Start new OpenMRS session on this thread
      Context.openSession();
      Context.addProxyPrivilege(OpenmrsConstants.PRIV_VIEW_ENCOUNTER_TYPES);
      Context.addProxyPrivilege(OpenmrsConstants.PRIV_MANAGE_ENCOUNTER_TYPES);
      Context.addProxyPrivilege(OpenmrsConstants.PRIV_MANAGE_PRIVILEGES);
      Context.addProxyPrivilege(OpenmrsConstants.PRIV_VIEW_PRIVILEGES);
      Context.addProxyPrivilege("Manage Encounter Roles");
      Context.addProxyPrivilege("View Visit Types");
      Context.addProxyPrivilege("Manage Visit Types");
      addMetadata();
    } catch (Exception ex) {
      ex.printStackTrace();
      throw new RuntimeException(
          "Could not pre-load rwanda primary care encounter types and privileges " + ex);
    } finally {
      Context.removeProxyPrivilege(OpenmrsConstants.PRIV_VIEW_ENCOUNTER_TYPES);
      Context.removeProxyPrivilege(OpenmrsConstants.PRIV_MANAGE_ENCOUNTER_TYPES);
      Context.removeProxyPrivilege(OpenmrsConstants.PRIV_MANAGE_PRIVILEGES);
      Context.removeProxyPrivilege(OpenmrsConstants.PRIV_VIEW_PRIVILEGES);
      Context.removeProxyPrivilege("Manage Encounter Roles");
      Context.removeProxyPrivilege("View Visit Types");
      Context.removeProxyPrivilege("Manage Visit Types");
      es = null;
      us = null;
      Context.closeSession();
      log.info("RwandaPrimaryCare loaded  metadata successfully.");
    }
  }
  /** @see org.aopalliance.intercept.MethodInterceptor#invoke(MethodInvocation) */
  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable {
    WithSession annotation = invocation.getMethod().getAnnotation(WithSession.class);

    if (annotation != null) {
      // Create new OpenMRS session
      Context.openSession();

      // Add requested privileges as proxy privileges
      for (String privilege : annotation.value()) Context.addProxyPrivilege(privilege);
    }

    // Invoke method...
    Object result = invocation.proceed();

    // Close session
    if (annotation != null) Context.closeSession();

    return result;
  }
  /**
   * @see
   *     org.springframework.web.servlet.mvc.SimpleFormController#processFormSubmission(javax.servlet.http.HttpServletRequest,
   *     javax.servlet.http.HttpServletResponse, java.lang.Object,
   *     org.springframework.validation.BindException)
   */
  protected ModelAndView processFormSubmission(
      HttpServletRequest request, HttpServletResponse reponse, Object obj, BindException errors)
      throws Exception {

    Alert alert = (Alert) obj;
    new AlertValidator().validate(obj, errors);

    try {
      // check that the user has the right privileges here because
      // we are giving them a proxy privilege in the line following this
      if (Context.hasPrivilege(PrivilegeConstants.MANAGE_ALERTS) == false)
        throw new APIAuthenticationException("Must be logged in as user with alerts privileges");

      Context.addProxyPrivilege(PrivilegeConstants.VIEW_USERS);

      UserService us = Context.getUserService();

      if (Context.isAuthenticated()) {
        String[] userIdValues = request.getParameter("userIds").split(" ");
        List<Integer> userIds = new Vector<Integer>();
        String[] roleValues = request.getParameter("newRoles").split(",");
        List<String> roles = new Vector<String>();

        // create user list
        if (userIdValues != null)
          for (String userId : userIdValues) {
            if (!userId.trim().equals("")) userIds.add(Integer.valueOf(userId.trim()));
          }

        // create role list
        if (roleValues != null)
          for (String role : roleValues) {
            if (!role.trim().equals("")) roles.add(role.trim());
          }

        // remove all recipients not in the userIds list
        List<AlertRecipient> recipientsToRemove = new Vector<AlertRecipient>();
        if (alert.getRecipients() != null) {
          for (AlertRecipient recipient : alert.getRecipients()) {
            Integer userId = recipient.getRecipient().getUserId();
            if (!userIds.contains(userId)) recipientsToRemove.add(recipient);
          }
        }
        for (AlertRecipient ar : recipientsToRemove) alert.removeRecipient(ar);

        // add all new users
        if (userIds != null) {
          for (Integer userId : userIds) {
            alert.addRecipient(new User(userId));
          }
        }

        // add all new users according to the role(s) selected
        if (roles != null) {
          for (String roleStr : roles) {
            List<User> users = us.getUsersByRole(new Role(roleStr));
            for (User user : users) alert.addRecipient(user);
          }
        }
      }

      if ((alert.getRecipients() == null || alert.getRecipients().size() == 0)) {
        errors.rejectValue("recipients", "Alert.recipientRequired");
      }

    } catch (Exception e) {
      log.error("Error while processing alert form", e);
      errors.reject(e.getMessage());
    } finally {
      Context.removeProxyPrivilege(PrivilegeConstants.VIEW_USERS);
    }

    return super.processFormSubmission(request, reponse, alert, errors);
  }
  @Override
  protected Boolean formBackingObject(HttpServletRequest request) throws Exception {

    /* To check wheather or not the subject , severity and feedback is empty or not */
    Boolean feedbackMessage = false;
    String text = "";
    String subject = request.getParameter("subject");
    String severity = request.getParameter("severity");
    String feedback = request.getParameter("feedback");
    String receiver = request.getParameter("fdbk_receiver");
    String pageinfo = request.getParameter("pageInfoPass");

    log.error(
        "\n\n\n\n\n********** "
            + subject
            + severity
            + feedback
            + receiver
            + ">"
            + request.getParameter("pagecontext")
            + "\n\n\n\n\n**********");

    if (StringUtils.hasLength(subject)
        && StringUtils.hasLength(severity)
        && StringUtils.hasLength(severity)) {
      Object o = Context.getService(FeedbackService.class);
      FeedbackService service = (FeedbackService) o;
      Feedback s = new Feedback();

      s.setSubject(request.getParameter("subject"));
      s.setSeverity(request.getParameter("severity"));
      s.setPageinfo(pageinfo);

      /* To get the Stacktrace of the page from which the feedback is submitted */
      StackTraceElement[] c = Thread.currentThread().getStackTrace();

      if ("on".equals(request.getParameter("pagecontext"))) {

        String manualStack = request.getParameter("stack");
        if (manualStack != null) {
          feedback =
              "Feedback: "
                  + feedback
                  + " | User Generated Stacktrace: "
                  + manualStack
                  + " | Automatic System Generated Stacktrace: ";

          for (int i = 0; i < c.length; i++) {
            feedback =
                feedback
                    + System.getProperty("line.separator")
                    + c[i].getFileName()
                    + c[i].getMethodName()
                    + c[i].getClass()
                    + c[i].getLineNumber();
          }
        }
      }

      s.setContent(feedback);

      /* file upload in multiplerequest */
      if (request instanceof MultipartHttpServletRequest) {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        MultipartFile file = (MultipartFile) multipartRequest.getFile("file");

        if (!file.isEmpty()) {
          if (file.getSize() <= 5242880) {
            if (file.getOriginalFilename().endsWith(".jpeg")
                || file.getOriginalFilename().endsWith(".jpg")
                || file.getOriginalFilename().endsWith(".gif")
                || file.getOriginalFilename().endsWith(".png")) {
              s.setMessage(file.getBytes());
            } else {
              request
                  .getSession()
                  .setAttribute(
                      WebConstants.OPENMRS_ERROR_ATTR, "feedback.notification.feedback.error");

              return false;
            }
          } else {
            request
                .getSession()
                .setAttribute(
                    WebConstants.OPENMRS_ERROR_ATTR, "feedback.notification.feedback.error");

            return false;
          }
        }
      }

      String screenshotURL = request.getParameter("screenshotFile");

      if (screenshotURL != null) {
        try {
          String parts[] = screenshotURL.split(",");
          BASE64Decoder decoder = new BASE64Decoder();
          byte[] decodedBytes = decoder.decodeBuffer(parts[1]);
          s.setScreenshot(decodedBytes);

        } catch (Exception e) {
          e.printStackTrace();
        }
      }

      /* Save the Feedback */
      service.saveFeedback(s);

      try {
        FeedbackUser feedbackUser = new FeedbackUser();
        feedbackUser.setFeedback(s);

        Context.addProxyPrivilege("View Users");
        feedbackUser.setUser(Context.getUserService().getUserByUsername(receiver));
        Context.removeProxyPrivilege("View Users");

        service.saveFeedbackUser(feedbackUser);
      } catch (Exception e) {
        log.error(e);
      }

      request
          .getSession()
          .setAttribute(
              WebConstants.OPENMRS_MSG_ATTR,
              Context.getAdministrationService().getGlobalProperty("feedback.ui.notification"));

      if ("Yes"
          .equals(
              Context.getUserContext()
                  .getAuthenticatedUser()
                  .getUserProperty("feedback_notificationReceipt"))) {
        try {

          // Create Message
          Message message = new Message();

          message.setSender(
              Context.getAdministrationService().getGlobalProperty("feedback.notification.email"));
          message.setRecipients(
              Context.getUserContext().getAuthenticatedUser().getUserProperty("feedback_email"));
          message.setSubject("Feedback submission confirmation mail");
          message.setContent(
              Context.getAdministrationService().getGlobalProperty("feedback.notification")
                  + "Ticket Number: "
                  + s.getFeedbackId()
                  + " Subject :"
                  + s.getSubject());
          message.setSentDate(new Date());

          // Send message
          Context.getMessageService().send(message);
        } catch (Exception e) {
          log.error(
              "Unable to sent the email to the Email : "
                  + Context.getUserContext()
                      .getAuthenticatedUser()
                      .getUserProperty("feedback_email"));
        }
      }

      try {
        // Create Message
        Message message = new Message();

        message.setSender(
            Context.getAdministrationService().getGlobalProperty("feedback.notification.email"));
        message.setRecipients(
            Context.getAdministrationService()
                .getGlobalProperty("feedback.admin.notification.email"));
        message.setSubject("New feedback submitted");
        message.setContent(
            Context.getAdministrationService().getGlobalProperty("feedback.admin.notification")
                + "Ticket Number: "
                + s.getFeedbackId()
                + " Subject : "
                + s.getSubject()
                + " Take Action :"
                + request.getScheme()
                + "://"
                + request.getServerName()
                + ":"
                + request.getServerPort()
                + request.getContextPath()
                + "/module/feedback/feedback.form?feedbackId="
                + s.getFeedbackId()
                + "#command");
        message.setSentDate(new Date());

        // Send message
        Context.getMessageService().send(message);
      } catch (Exception e) {
        log.error(
            "Unable to sent the email to the Email : "
                + Context.getUserContext()
                    .getAuthenticatedUser()
                    .getUserProperty("feedback.admin.notification.email"));
      }

      feedbackMessage = true;
    }

    /* Reserved for future use for showing that the data is saved and the feedback is submitted */
    log.debug("Returning hello world text: " + text);

    return feedbackMessage;
  }
 public void addProxyPrivilege(String privilege) {
   Context.addProxyPrivilege(privilege);
 }
  /**
   * 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)
   * @should transfer encounter to another patient when encounter patient was changed
   */
  @Override
  protected ModelAndView onSubmit(
      HttpServletRequest request, HttpServletResponse response, Object obj, BindException errors)
      throws Exception {

    HttpSession httpSession = request.getSession();

    String view = getFormView();

    try {
      Context.addProxyPrivilege(PrivilegeConstants.VIEW_USERS);
      Context.addProxyPrivilege(PrivilegeConstants.VIEW_PATIENTS);

      if (Context.isAuthenticated()) {
        Encounter encounter = (Encounter) obj;

        Integer patientId = null;

        if (request.getParameter("patientId") != null) {
          patientId = Integer.valueOf(request.getParameter("patientId"));
        }

        if (encounter.getEncounterId() == null) {
          // if this is a new encounter, they can specify a patient.  add it
          if (patientId != null) {
            encounter.setPatient(Context.getPatientService().getPatient(patientId));
          }
        } else {
          Patient oldPatient = encounter.getPatient();
          Patient newPatient = Context.getPatientService().getPatient(patientId);
          if (newPatient != null && oldPatient != null && !newPatient.equals(oldPatient)) {
            encounter = Context.getEncounterService().transferEncounter(encounter, newPatient);
          }
        }

        if (encounter.isVoided() && encounter.getVoidedBy() == null) {
          // if this is a "new" voiding, call voidEncounter to set appropriate attributes
          Context.getEncounterService().voidEncounter(encounter, encounter.getVoidReason());
        } else if (!encounter.isVoided() && encounter.getVoidedBy() != null) {
          // if this was just unvoided, call unvoidEncounter to unset appropriate attributes
          Context.getEncounterService().unvoidEncounter(encounter);
        } else {
          Context.getEncounterService().saveEncounter(encounter);
        }

        view = getSuccessView();
        view = view + "?encounterId=" + encounter.getEncounterId();

        httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "Encounter.saved");
      }
    } catch (APIException e) {
      log.error("Error while trying to save the encounter", e);
      httpSession.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "Encounter.cannot.save");
      errors.reject("encounter", "Encounter.cannot.save");
      // return to the form because an exception was thrown
      return showForm(request, response, errors);
    } finally {
      Context.removeProxyPrivilege(PrivilegeConstants.VIEW_USERS);
      Context.removeProxyPrivilege(PrivilegeConstants.VIEW_PATIENTS);
    }

    return new ModelAndView(new RedirectView(view));
  }
  /**
   * @see
   *     org.springframework.web.servlet.mvc.SimpleFormController#processFormSubmission(javax.servlet.http.HttpServletRequest,
   *     javax.servlet.http.HttpServletResponse, java.lang.Object,
   *     org.springframework.validation.BindException)
   */
  @Override
  protected ModelAndView processFormSubmission(
      HttpServletRequest request, HttpServletResponse reponse, Object obj, BindException errors)
      throws Exception {

    Encounter encounter = (Encounter) obj;

    try {
      if (Context.isAuthenticated()) {
        Context.addProxyPrivilege(PrivilegeConstants.VIEW_USERS);
        Context.addProxyPrivilege(PrivilegeConstants.VIEW_PATIENTS);

        if (encounter.getEncounterId() == null
            && StringUtils.hasText(request.getParameter("patientId"))) {
          encounter.setPatient(
              Context.getPatientService()
                  .getPatient(Integer.valueOf(request.getParameter("patientId"))));
        }
        if (encounter.isVoided()) {
          ValidationUtils.rejectIfEmptyOrWhitespace(errors, "voidReason", "error.null");
        }

        String[] providerIdsArray = ServletRequestUtils.getStringParameters(request, "providerIds");
        if (ArrayUtils.isEmpty(providerIdsArray)) {
          errors.reject("Encounter.provider.atleastOneProviderRequired");
        }

        String[] roleIdsArray =
            ServletRequestUtils.getStringParameters(request, "encounterRoleIds");

        ProviderService ps = Context.getProviderService();
        EncounterService es = Context.getEncounterService();
        if (providerIdsArray != null && roleIdsArray != null) {
          // list to store role provider mappings to be used below to detect removed providers
          List<String> unremovedRoleAndProviders = new ArrayList<String>();
          for (int i = 0; i < providerIdsArray.length; i++) {
            if (StringUtils.hasText(providerIdsArray[i]) && StringUtils.hasText(roleIdsArray[i])) {
              unremovedRoleAndProviders.add(roleIdsArray[i] + "-" + providerIdsArray[i]);
              Provider provider = ps.getProvider(Integer.valueOf(providerIdsArray[i]));
              EncounterRole encounterRole = es.getEncounterRole(Integer.valueOf(roleIdsArray[i]));
              // if this is an existing provider, don't create a new one to avoid losing existing
              // details like dateCreated, creator, uuid etc in the encounter_provider table
              if (encounter.getProvidersByRole(encounterRole).contains(provider)) {
                continue;
              }

              // this is a new provider
              encounter.addProvider(encounterRole, provider);
            }
          }
          // Get rid of the removed ones
          for (Map.Entry<EncounterRole, Set<Provider>> entry :
              encounter.getProvidersByRoles().entrySet()) {
            for (Provider p : entry.getValue()) {
              if (!unremovedRoleAndProviders.contains(
                  entry.getKey().getEncounterRoleId() + "-" + p.getProviderId())) {
                encounter.removeProvider(entry.getKey(), p);
              }
            }
          }
        }

        ValidationUtils.invokeValidator(new EncounterValidator(), encounter, errors);
      }
    } finally {
      Context.removeProxyPrivilege(PrivilegeConstants.VIEW_USERS);
      Context.removeProxyPrivilege(PrivilegeConstants.VIEW_PATIENTS);
    }

    return super.processFormSubmission(request, reponse, encounter, errors);
  }