class DrugOrderCohortDefinitionEvaluator implements CohortDefinitionEvaluator {

	public EvaluatedCohort evaluate(CohortDefinition cohortDefinition, EvaluationContext context) {
		DrugOrderCohortDefinition drugOrderCohortDefinition = (DrugOrderCohortDefinition) cohortDefinition;
		context = ObjectUtil.nvl(context, new EvaluationContext());

		HqlQueryBuilder query = new HqlQueryBuilder();
		query.select("drugOrder.patient.patientId");
		query.from(DrugOrder.class, "drugOrder");

		query.wherePatientIn("drugOrder.patient.patientId", context);
		
		if (drugOrderCohortDefinition.getWhich() == null) drugOrderCohortDefinition.setWhich(Match.ANY); 
			
	    if (drugOrderCohortDefinition.getDrugSets() != null) {
	    	
	    	if (drugOrderCohortDefinition.getWhich() == Match.ANY) {
		    	query.whereInAny("drugOrder.concept", drugOrderCohortDefinition.getDrugSets().toArray());
	    	} 
	    	else if (drugOrderCohortDefinition.getWhich() == Match.ALL) {
		    	query.whereIn("drugOrder.concept", drugOrderCohortDefinition.getDrugSets());
		    	query.groupBy(
			        		"drugOrder.patient.patientId" + " having count(distinct drugOrder.concept.conceptId) = " + drugOrderCohortDefinition.getDrugSets().size());
	    	} 
	    	else if (drugOrderCohortDefinition.getWhich() == Match.NONE) {
		    	query.whereNotInAny("drugOrder.concept", drugOrderCohortDefinition.getDrugSets());
	    	}
	    }
	
	    if (drugOrderCohortDefinition.getDrugConcepts() != null) {
	    	if (drugOrderCohortDefinition.getWhich() == Match.ANY) {
	    		query.whereInAny("drugOrder.concept", drugOrderCohortDefinition.getDrugConcepts().toArray());
	    	} 
	    	else if (drugOrderCohortDefinition.getWhich() == Match.ALL) {
	    		query.whereIn("drugOrder.concept", drugOrderCohortDefinition.getDrugConcepts());
	    		query.groupBy(
	    				"drugOrder.patient.patientId" + " having count(distinct drugOrder.concept.conceptId) = " + drugOrderCohortDefinition.getDrugSets().size());
	    	} 
	    	else if (drugOrderCohortDefinition.getWhich() == Match.NONE) {
	    		query.whereNotInAny("drugOrder.concept", drugOrderCohortDefinition.getDrugConcepts());
	    	}
	    }
	
	    if (drugOrderCohortDefinition.getDrugs() != null) {
	    	if (drugOrderCohortDefinition.getWhich() == Match.ANY) {
	    		query.whereInAny("drugOrder.drug", drugOrderCohortDefinition.getDrugs().toArray());
	    	} 
	    	else if (drugOrderCohortDefinition.getWhich() == Match.ALL) {
	    		query.whereIn("drugOrder.drug", drugOrderCohortDefinition.getDrugs());
	    		query.groupBy(
	    				"drugOrder.patient.patientId" + " having count(distinct drugOrder.drug.drugId) = " + drugOrderCohortDefinition.getDrugs().size());
	    	} 
	    	else if (drugOrderCohortDefinition.getWhich() == Match.NONE) {
	    		query.whereNotInAny("drugOrder.drug", drugOrderCohortDefinition.getDrugs());
	    	}
	    }
	 
    	query.whereLessOrEqualTo("drugOrder.dateActivated", drugOrderCohortDefinition.getActivatedOnOrBefore());
    	query.whereGreaterOrEqualTo("drugOrder.dateActivated", drugOrderCohortDefinition.getActivatedOnOrAfter());
    	query.whereEqual("drugOrder.careSetting", drugOrderCohortDefinition.getCareSetting());
    	
    	if (drugOrderCohortDefinition.getActiveOnOrBefore() != null) {
	    	query.whereNotNull("drugOrder.dateActivated").and()
	    		 .whereLessOrEqualTo("drugOrder.dateStopped", drugOrderCohortDefinition.getActiveOnOrBefore())
	    		 .or()
	    		 .whereLessOrEqualTo("drugOrder.autoExpireDate", drugOrderCohortDefinition.getActiveOnOrBefore());
    	}
    	
    	query.whereNotNull("drugOrder.dateActivated").and()
    		 .whereGreaterEqualOrNull("drugOrder.dateStopped", drugOrderCohortDefinition.getActiveOnOrAfter())
    		 .and()
    		 .whereGreaterEqualOrNull("drugOrder.autoExpireDate", drugOrderCohortDefinition.getActiveOnOrAfter());
    		 
    	query.whereNotNull("drugOrder.dateActivated").and()
    		 .whereLessOrEqualTo("drugOrder.dateActivated", drugOrderCohortDefinition.getActiveOnDate())    		 
    		 .whereGreaterOrNull("drugOrder.dateStopped", drugOrderCohortDefinition.getActiveOnDate())
    		 .and()
    		 .whereGreaterOrNull("drugOrder.autoExpireDate", drugOrderCohortDefinition.getActiveOnDate());
    		 
	    List<Integer> patientIds = evaluationService.evaluateToList(query, Integer.class, context);
	    Cohort cohort = new Cohort(patientIds);
	
	    return new EvaluatedCohort(cohort, drugOrderCohortDefinition, context);
	}

}

class DrugOrderCohortDefinitionEvaluatorTest  {

  	protected static final String TEST_DATA;
  	private DrugOrderCohortDefinition cohortDefinition;

  	@Test
  	public void evaluateShouldReturnAllPatientsThatHaveTakenAnyDrugByDefault() throws Exception {

  		List drugs = new ArrayList<Drug>();
  		drugs.add(new Drug(11));
  		drugs.add(new Drug(2));
  		cohortDefinition.setDrugs(drugs);
  		Cohort cohort = Context.getService(CohortDefinitionService.class).evaluate(cohortDefinition, null);
  		Assert.assertTrue(cohort.contains(2));
  		Assert.assertTrue(cohort.contains(8));
  		Assert.assertTrue(cohort.contains(21));
  		Assert.assertTrue(cohort.contains(22));
  		Assert.assertEquals(4, cohort.size());
  		
  	}

}