/** * The contents of this file are subject to the OpenMRS Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.reporting; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openmrs.Cohort; import org.openmrs.api.PatientSetService.BooleanOperator; import org.openmrs.cohort.CohortSearchHistory; import org.openmrs.report.EvaluationContext; /** * @deprecated see reportingcompatibility module */ @Deprecated public class CohortHistoryCompositionFilter extends AbstractPatientFilter implements PatientFilter { protected final static Log log = LogFactory.getLog(CohortHistoryCompositionFilter.class); public static final long serialVersionUID = 6736677001L; private CohortSearchHistory history; private List<Object> parsedCompositionString; public CohortHistoryCompositionFilter() { } public CohortSearchHistory getHistory() { return history; } public void setHistory(CohortSearchHistory history) { this.history = history; } public List<Object> getParsedCompositionString() { return parsedCompositionString; } public void setParsedCompositionString(List<Object> parsedCompositionString) { this.parsedCompositionString = parsedCompositionString; } public String getName() { return nameHelper(parsedCompositionString); } public void setName(String name) { } @SuppressWarnings("unchecked") private String nameHelper(List list) { StringBuilder ret = new StringBuilder(); for (Object o : list) { if (ret.length() > 0) ret.append(" "); if (o instanceof List) ret.append("(" + nameHelper((List) o) + ")"); else ret.append(o); } return ret.toString(); } /** * Call this to notify this composition filter that the _i_th element of the search history has * been removed, and it potentially needs to renumber its constituent parts * * @return whether or not this filter itself should be removed (because it directly references * the removed history element */ /* public boolean removeFromHistoryNotify(int i) { return removeHelper(parsedCompositionString, i); } private boolean removeHelper(List<Object> list, int i) { boolean ret = false; for (ListIterator<Object> iter = list.listIterator(); iter.hasNext(); ) { Object o = iter.next(); if (o instanceof List) ret |= removeHelper((List) o, i); else if (o instanceof Integer) { Integer ref = (Integer) o; if (ref == i) { ret = true; iter.set("-1"); } else if (ref < i) iter.set(ref - 1); } } return ret; } */ @SuppressWarnings("unchecked") private PatientFilter toPatientFilter(List<Object> phrase) { // Recursive step: // * if anything in this list is a list, then recurse on that // * if anything in this list is a number, replace it with the relevant filter from the history log.debug("Starting with " + phrase); List<Object> use = new ArrayList<Object>(); for (ListIterator<Object> i = phrase.listIterator(); i.hasNext();) { Object o = i.next(); if (o instanceof List) use.add(toPatientFilter((List<Object>) o)); else if (o instanceof Integer) use.add(getHistory().getSearchHistory().get((Integer) o - 1)); else use.add(o); } // base case. All elements are PatientFilter or BooleanOperator. log.debug("Base case with " + use); // first, replace all [..., NOT, PatientFilter, ...] with [ ..., InvertedPatientFilter, ...] boolean invertTheNext = false; for (ListIterator<Object> i = use.listIterator(); i.hasNext();) { Object o = i.next(); if (o instanceof BooleanOperator) { if ((BooleanOperator) o == BooleanOperator.NOT) { i.remove(); invertTheNext = !invertTheNext; } else { if (invertTheNext) throw new RuntimeException("Can't have NOT AND. Test() should have failed"); } } else { if (invertTheNext) { i.set(new InversePatientFilter((PatientFilter) o)); invertTheNext = false; } } } log.debug("Finished with NOTs: " + use); // Now all we have left are PatientFilter, AND, OR // eventually go with left-to-right precedence, and we can combine runs of the same operator into a single one // 1 AND 2 AND 3 -> AND(1, 2, 3) // 1 AND 2 OR 3 -> OR(AND(1, 2), 3) // for now a hack so we take the last operator in the run, and apply that to all filters // for example 1 AND 2 OR 3 -> OR(1, 2, 3) if (use.size() == 1) { return (PatientFilter) use.get(0); } BooleanOperator bo = BooleanOperator.AND; List<PatientFilter> args = new ArrayList<PatientFilter>(); for (Object o : use) if (o instanceof BooleanOperator) bo = (BooleanOperator) o; else args.add((PatientFilter) o); return new CompoundPatientFilter(bo, args); } public PatientFilter toCohortDefinition() { return toPatientFilter(getParsedCompositionString()); } public Cohort filter(Cohort input, EvaluationContext context) { PatientFilter pf = toPatientFilter(getParsedCompositionString()); return pf.filter(input, context); } public Cohort filterInverse(Cohort input, EvaluationContext context) { PatientFilter pf = toPatientFilter(getParsedCompositionString()); return pf.filterInverse(input, context); } public boolean isReadyToRun() { return true; } }