private Control buildNewControl(Disposition disposition, List<DispositionObs> additionalObs) {
    Control control = new Control();
    control.setWhenValue(disposition.getConceptCode());

    for (DispositionObs obs : additionalObs) {
      control.getThenDisplay().add(UUID.randomUUID().toString());
      control.getLabel().add(obs.getLabel());
      control.getConceptId().add(obs.getConceptCode());
      control.getParams().add(obs.getParams());
    }

    return control;
  }
  private boolean shouldBeClosed(Visit visit) {

    if (visit.getStopDatetime() != null) {
      return false; // already closed
    }

    VisitDomainWrapper visitDomainWrapper = domainWrapperFactory.newVisitDomainWrapper(visit);

    if (visitDomainWrapper.isAdmitted() || visitDomainWrapper.isAwaitingAdmission()) {
      return false; // don't close the visit if patient is admitted or waiting admission
    }

    Disposition mostRecentDisposition = visitDomainWrapper.getMostRecentDisposition();
    if (mostRecentDisposition != null
        && mostRecentDisposition.getKeepsVisitOpen() != null
        && mostRecentDisposition.getKeepsVisitOpen()) {
      return false; // don't close the visit if the most recent disposition is one that keeps visit
                    // opens
    }

    Date now = new Date();
    Date mustHaveSomethingAfter = DateUtils.addHours(now, -emrApiProperties.getVisitExpireHours());

    if (OpenmrsUtil.compare(visit.getStartDatetime(), mustHaveSomethingAfter) >= 0) {
      return false;
    }

    if (visit.getEncounters() != null) {
      for (Encounter candidate : visit.getEncounters()) {
        if (OpenmrsUtil.compare(candidate.getEncounterDatetime(), mustHaveSomethingAfter) >= 0) {
          return false;
        }
      }
    }

    return true;
  }
  @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;
  }