/** @see {@link DrugOrderValidator#validate(Object,Errors)} */
  @Test
  @Verifies(
      value = "should pass validation if all fields are correct",
      method = "validate(Object,Errors)")
  public void validate_shouldPassValidationIfAllFieldsAreCorrect() throws Exception {
    DrugOrder order = new DrugOrder();
    Encounter encounter = new Encounter();
    Patient patient = Context.getPatientService().getPatient(2);
    order.setConcept(Context.getConceptService().getConcept(88));
    order.setOrderer(Context.getProviderService().getProvider(1));
    order.setDosingType(DrugOrder.DosingType.FREE_TEXT);
    order.setInstructions("Instructions");
    order.setDosingInstructions("Test Instruction");
    order.setPatient(patient);
    encounter.setPatient(patient);
    order.setEncounter(encounter);
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.DAY_OF_MONTH, cal.get(Calendar.DAY_OF_MONTH) - 1);
    order.setStartDate(cal.getTime());
    order.setAutoExpireDate(new Date());
    order.setOrderType(Context.getOrderService().getOrderTypeByName("Drug order"));
    order.setDrug(Context.getConceptService().getDrug(3));
    order.setCareSetting(Context.getOrderService().getCareSetting(1));
    order.setQuantity(2.00);
    order.setQuantityUnits(Context.getConceptService().getConcept(51));
    order.setNumRefills(10);

    Errors errors = new BindException(order, "order");
    new DrugOrderValidator().validate(order, errors);
    Assert.assertFalse(errors.hasErrors());
  }
  @Test
  @Verifies(
      value = "should return encounter with all child objects voided according to schema",
      method = "voidEncounterByHtmlFormSchema")
  public void testVoidEncounterByHtmlFormSchema_shouldHandleDrugOrderCorrectly() throws Exception {
    executeDataSet(
        XML_DATASET_PATH + new TestUtil().getTestDatasetFilename(XML_REGRESSION_TEST_DATASET));
    Encounter e = new Encounter();
    e.setPatient(Context.getPatientService().getPatient(2));
    Date date = Context.getDateFormat().parse("01/02/2003");
    e.setDateCreated(new Date());
    e.setEncounterDatetime(date);
    e.setLocation(Context.getLocationService().getLocation(2));
    e.setProvider(Context.getPersonService().getPerson(502));
    TestUtil.addObs(e, 1, 5000, date); // a matching obs

    DrugOrder dor = new DrugOrder();
    dor.setVoided(false);
    dor.setConcept(Context.getConceptService().getConcept(792));
    dor.setCreator(Context.getUserService().getUser(1));
    dor.setDateCreated(new Date());
    dor.setDiscontinued(false);
    dor.setDrug(Context.getConceptService().getDrug(2));
    dor.setOrderType(Context.getOrderService().getOrderType(1));
    dor.setPatient(Context.getPatientService().getPatient(2));
    dor.setStartDate(new Date());
    e.addOrder(dor);

    Context.getEncounterService().saveEncounter(e);

    Form form = new Form();
    HtmlForm htmlform = new HtmlForm();
    htmlform.setForm(form);
    form.setEncounterType(new EncounterType());
    htmlform.setDateChanged(new Date());
    htmlform.setXmlData(
        new TestUtil()
            .loadXmlFromFile(
                XML_DATASET_PATH + "returnSectionsAndConceptsInSectionsTestFormWithGroups.xml"));

    HtmlFormEntryUtil.voidEncounterByHtmlFormSchema(e, htmlform, "test void reason");

    // this is going to test out the voided state of the obs in the encounter after processing:
    // order was matched, so order was voided, and because that's the only thing in the encounter,
    // encounter was voided too.
    Assert.assertTrue(e.isVoided());
    Assert.assertTrue(e.getVoidReason().equals("test void reason"));
    for (Order o : e.getOrders()) {
      Assert.assertTrue(o.isVoided());
      Assert.assertTrue(o.getVoidReason().equals("test void reason"));
    }
    for (Obs o : e.getAllObs(true)) {
      Assert.assertTrue(o.getVoidReason().equals("test void reason"));
    }
  }
  @Test
  @Verifies(value = "should delete encounter correctly", method = "voidEncounterByHtmlFormSchema")
  public void testVoidEncounterByHtmlFormSchema_shouldDeleteEncounter() throws Exception {
    executeDataSet(
        XML_DATASET_PATH + new TestUtil().getTestDatasetFilename(XML_REGRESSION_TEST_DATASET));
    Encounter e = new Encounter();
    e.setPatient(Context.getPatientService().getPatient(2));
    Date date = Context.getDateFormat().parse("01/02/2003");
    e.setDateCreated(new Date());
    e.setEncounterDatetime(date);
    e.setLocation(Context.getLocationService().getLocation(2));
    e.setProvider(Context.getPersonService().getPerson(502));
    TestUtil.addObs(e, 3, 5000, date); // adding an un-matched, voided Obs
    for (Obs o : e.getAllObs(true)) {
      o.setVoided(true);
      o.setVoidedBy(Context.getUserService().getUser(1));
      o.setVoidReason("blah");
      o.setDateVoided(new Date());
    }

    // and adding a voided drug order
    DrugOrder dor = new DrugOrder();
    dor.setVoided(false);
    dor.setConcept(Context.getConceptService().getConcept(792));
    dor.setCreator(Context.getUserService().getUser(1));
    dor.setDateCreated(new Date());
    dor.setDiscontinued(false);
    dor.setDrug(Context.getConceptService().getDrug(2));
    dor.setOrderType(Context.getOrderService().getOrderType(1));
    dor.setPatient(Context.getPatientService().getPatient(2));
    dor.setVoided(true);
    dor.setVoidedBy(Context.getUserService().getUser(1));
    dor.setVoidReason("blah");
    dor.setDateVoided(new Date());
    dor.setStartDate(new Date());
    e.addOrder(dor);

    Context.getEncounterService().saveEncounter(e);

    Form form = new Form();
    HtmlForm htmlform = new HtmlForm();
    htmlform.setForm(form);
    form.setEncounterType(new EncounterType());
    htmlform.setDateChanged(new Date());
    htmlform.setXmlData(
        new TestUtil()
            .loadXmlFromFile(
                XML_DATASET_PATH + "returnSectionsAndConceptsInSectionsTestFormWithGroups.xml"));

    HtmlFormEntryUtil.voidEncounterByHtmlFormSchema(e, htmlform, null);

    // encounter had no non-voided objects, should be voided
    Assert.assertTrue(e.isVoided());
  }
  @Test
  @Verifies(
      value = "should return encounter with all child objects voided according to schema",
      method = "voidEncounterByHtmlFormSchema")
  public void testVoidEncounterByHtmlFormSchema_shouldHandleDrugOrderAndObsCorrectly()
      throws Exception {
    executeDataSet(
        XML_DATASET_PATH + new TestUtil().getTestDatasetFilename(XML_REGRESSION_TEST_DATASET));
    Encounter e = new Encounter();
    e.setPatient(Context.getPatientService().getPatient(2));
    Date date = Context.getDateFormat().parse("01/02/2003");
    e.setDateCreated(new Date());
    e.setEncounterDatetime(date);
    e.setLocation(Context.getLocationService().getLocation(2));
    e.setProvider(Context.getPersonService().getPerson(502));
    TestUtil.addObs(e, 3, 5000, date); // adding an un-matched Obs

    DrugOrder dor = new DrugOrder();
    dor.setVoided(false);
    dor.setConcept(Context.getConceptService().getConcept(792));
    dor.setCreator(Context.getUserService().getUser(1));
    dor.setDateCreated(new Date());
    dor.setDiscontinued(false);
    dor.setDrug(Context.getConceptService().getDrug(2));
    dor.setOrderType(Context.getOrderService().getOrderType(1));
    dor.setPatient(Context.getPatientService().getPatient(2));
    dor.setStartDate(new Date());
    e.addOrder(dor);

    Context.getEncounterService().saveEncounter(e);

    Form form = new Form();
    HtmlForm htmlform = new HtmlForm();
    htmlform.setForm(form);
    form.setEncounterType(new EncounterType());
    htmlform.setDateChanged(new Date());
    htmlform.setXmlData(
        new TestUtil()
            .loadXmlFromFile(
                XML_DATASET_PATH + "returnSectionsAndConceptsInSectionsTestFormWithGroups.xml"));

    HtmlFormEntryUtil.voidEncounterByHtmlFormSchema(e, htmlform, null);

    // order was matched, obs was not, so order should be voided, obs not, encounter not.
    Assert.assertTrue(!e.isVoided());
    for (Order o : e.getOrders()) {
      Assert.assertTrue(o.isVoided());
    }
    for (Obs o : e.getObs()) {
      Assert.assertTrue(!o.isVoided());
    }
  }
  /* here's the logic for what happens if there is a future regimen:
  *
  *
  *      //1.  if no drug order of a specific DrugOrder, (create the new order).  (OUTCOME1)

         //2.  if DrugOrder, for all DrugOrders:
             //a.  if new start is before old start
                 //NEW ORDER HAS STOP DATE -- create the older as is, and make adjustments:
                     //1.  if new end is before or equal to old start (create the new order)  (OUTCOME2)
                     //2.  if new end is after old start and ( before old end or old end is infinite)
                        //if order is different, adjust the start date of the old order to the end date of the new (create the new order) (OUTCOME3)
                        //if order is same void old order(doesn't matter if old order has infinite stop date or not) (create the new order) (OUTCOME4)
                     //3. if end date is greater than or equal to old end -- void old order   (create the new order)  (OUTCOME5)
                 //NEW ORDER DOESN'T HAVE STOP DATE
                     //4. orders are different
                          //set end date of new to beginning of old and stop iterating over existing drug orders time sequence (create the new order, modified) (OUTCOME6)
                     //5. orders are the same
                         //delete the old order (create the new order) (OUTCOME7)
             //b. if start is the same
                 // void existing (create the new order) (OUTCOME8)

             //c.  if start is after existing start
                 //1. if order is after old drug end  (create the new order) (OUTCOME9)
                 //2. if order is before old drug end or equal to old drug end or old drug end date is infinite
                     //if orders are the same update the old order with the new, taking the new end date value (Do not create new order) (OUTCOME10)
                     //if orders are different adjust the old to end on new start date (create the new order) (OUTCOME11)

  * */
  public static void setRegimen(
      Patient patient,
      Date effectiveDate,
      Collection<DrugOrder> drugOrders,
      Concept reasonForChange,
      Encounter encounterForChange) {
    RegimenHistory history = getRegimenHistory(patient);
    Regimen regOnDate = history.getRegimen(effectiveDate);
    List<Regimen> regAfterDate = history.getRegimensAfter(effectiveDate);
    OrderService os = Context.getOrderService();
    if (encounterForChange != null) {
      Context.getEncounterService().saveEncounter(encounterForChange);
      for (DrugOrder drugOrder : drugOrders) {
        drugOrder.setEncounter(encounterForChange);
      }
    }

    if (!anyRegimens(regAfterDate)) {
      if (regOnDate == null || regOnDate.getComponents().isEmpty()) {
        // case:  there is no existing regimen on the regimen start date, and there are no new
        // regimens after this date
        // go ahead and create the regimen:
        for (DrugOrder drugOrder : drugOrders) {
          Context.getOrderService().saveOrder(drugOrder);
        }
      } else {

        // case: there are still open orders and there are no new regimens after this date
        // first see what existing things we need to stop
        for (RegimenComponent before : regOnDate.getComponents()) {
          // stop the old order only if it isn't exactly identical to a new order (excluding
          // discontinued_date)
          for (DrugOrder newOrder : drugOrders) {
            // but either concept or drug is the same
            if (!before.getDrugOrder().getDiscontinued()
                && drugOrderMatchesDrugConcept(before.getDrugOrder(), newOrder)
                && !regimenComponentIsTheSameAsDrugOrderExcludingDates(
                    before.getDrugOrder(), newOrder)) {
              discontinueOrder(before.getDrugOrder(), effectiveDate, reasonForChange);
            }
          }
        }
        // now see what new things to start (or extend)
        for (DrugOrder newOrder : drugOrders) {

          // create a new order if there isn't already an existing match,
          // or if there is (excluding discontinued date) you need to extend, or null the stop date

          boolean alreadyExists = false;
          for (RegimenComponent before : regOnDate.getComponents()) {

            if (!before.getDrugOrder().getDiscontinued()
                && regimenComponentIsTheSameAsDrugOrderExcludingDates(
                    before.getDrugOrder(), newOrder)) {
              alreadyExists = true;
              before.getDrugOrder().setDiscontinuedDate(newOrder.getDiscontinuedDate());
              before.getDrugOrder().setAutoExpireDate(newOrder.getAutoExpireDate());
              before.getDrugOrder().setPrn(newOrder.getPrn());
              before.getDrugOrder().setInstructions(newOrder.getInstructions());
              os.saveOrder(before.getDrugOrder());
              newOrder.setOrderId(before.getDrugOrder().getOrderId());
              break;
            }
          }
          if (!alreadyExists) {
            os.saveOrder(newOrder);
          }
        }
      }
    } else { // there is a regimen change after the new drug order start date
      for (DrugOrder newOrder : drugOrders) {
        boolean saveOrder = false;
        boolean merged = false;
        history = getRegimenHistory(patient);
        List<DrugOrder> existingDrugOrders = getDrugOrdersInOrderByDrugOrConcept(history, newOrder);
        if (existingDrugOrders.size() == 0) {
          saveOrder = setSaveOrder(merged); // (OUTCOME1)
        } else {
          for (DrugOrder before : existingDrugOrders) {
            if (newOrder.getStartDate().before(before.getStartDate())) {
              if (newOrder.getDiscontinuedDate() != null) {
                if (newOrder.getDiscontinuedDate().before(before.getStartDate())
                    || newOrder.getDiscontinuedDate().equals(before.getStartDate())) {
                  saveOrder = setSaveOrder(merged); // (OUTCOME2)
                } else if (newOrder.getDiscontinuedDate().after(before.getStartDate())
                    && (before.getDiscontinuedDate() == null
                        || newOrder.getDiscontinuedDate().before(before.getDiscontinuedDate()))) {
                  if (!regimenComponentIsTheSameAsDrugOrderExcludingDates(before, newOrder)) {
                    // (OUTCOME3)
                    before.setStartDate(newOrder.getDiscontinuedDate());
                    os.saveOrder(before);
                    saveOrder = setSaveOrder(merged);
                  } else {
                    // (OUTCOME4)
                    os.voidOrder(before, "overwritten");
                    saveOrder = setSaveOrder(merged);
                  }
                } else if (before.getDiscontinuedDate() != null
                    && (newOrder.getDiscontinuedDate().after(before.getDiscontinuedDate())
                        || newOrder.getDiscontinuedDate().equals(before.getDiscontinuedDate()))) {
                  // (OUTCOME5)
                  os.voidOrder(before, "overwritten");
                  saveOrder = setSaveOrder(merged);
                }
              } else { // new order has infinite end date
                if (!regimenComponentIsTheSameAsDrugOrderExcludingDates(before, newOrder)) {
                  // (OUTCOME6)
                  newOrder.setDiscontinuedDate(before.getStartDate());
                  saveOrder = setSaveOrder(merged);
                  break;
                } else {
                  // (OUTCOME7)
                  os.voidOrder(before, "overwritten");
                  saveOrder = setSaveOrder(merged);
                }
              }
            } else if (newOrder.getStartDate().equals(before.getStartDate())) { // b
              // (OUTCOME8)
              os.voidOrder(before, "overwritten");
              saveOrder = setSaveOrder(merged);
            } else { // c -- start date is after or equal to old end date
              if (before.getDiscontinuedDate() != null
                  && newOrder.getStartDate().after(before.getDiscontinuedDate())) // 1
                // (OUTCOME9)
                saveOrder = setSaveOrder(merged);

              if (before.getDiscontinuedDate() == null
                  || newOrder.getStartDate().before(before.getDiscontinuedDate())
                  || newOrder.getStartDate().equals(before.getDiscontinuedDate())) { // 2
                if (regimenComponentIsTheSameAsDrugOrderExcludingDates(before, newOrder)) {
                  // (OUTCOME10)
                  before.setDiscontinuedDate(newOrder.getDiscontinuedDate());
                  before.setAutoExpireDate(newOrder.getAutoExpireDate());
                  before.setPrn(newOrder.getPrn());
                  before.setInstructions(newOrder.getInstructions());
                  os.saveOrder(before);
                  saveOrder = false;
                  newOrder.setOrderId(before.getOrderId());
                  merged = true;
                } else {
                  // (OUTCOME11)
                  before.setDiscontinuedDate(newOrder.getStartDate());
                  os.saveOrder(before);
                  saveOrder = setSaveOrder(merged);
                }
              }
            }
          }
        }
        if (saveOrder) os.saveOrder(newOrder);
      }
    }
  }