/*
* Copyright (c) 2006-2013 Massachusetts General Hospital
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the i2b2 Software License v1.0
* which accompanies this distribution.
*
* Contributors:
* Christopher Herrick
*/
package edu.harvard.i2b2.crc.dao.setfinder.querybuilder.temporal;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import edu.harvard.i2b2.crc.dao.setfinder.querybuilder.QueryTimingHandler;
import edu.harvard.i2b2.crc.dao.setfinder.querybuilder.temporal.TemporalSubQuery.TemporalQueryReturnColumns;
import edu.harvard.i2b2.crc.datavo.setfinder.query.QueryJoinColumnType;
import edu.harvard.i2b2.crc.datavo.setfinder.query.QueryJoinType;
import edu.harvard.i2b2.crc.datavo.setfinder.query.QueryOperatorType;
import edu.harvard.i2b2.crc.datavo.setfinder.query.QueryAggregateOperatorType;
import edu.harvard.i2b2.crc.datavo.setfinder.query.QueryDefinitionType;
import edu.harvard.i2b2.crc.datavo.setfinder.query.QueryConstraintType;
public class TemporalQueryConstraintMapping {
private HashMap<String, HashMap<String, List<QueryConstraintType>>> constraints = new HashMap<String, HashMap<String, List<QueryConstraintType>>>();
private HashMap<String, EnumSet<TemporalSubQuery.TemporalQueryReturnColumns>> returnColumns = new HashMap<String, EnumSet<TemporalSubQuery.TemporalQueryReturnColumns>>();
private ArrayList<String> orderedSet = new ArrayList<String>();
public TemporalQueryConstraintMapping(QueryDefinitionType queryDef){
parseConstraints(queryDef);
}
public HashMap<String, List<QueryConstraintType>> getConstraintsForQuery(String eventId){
if (eventId==null)
return null;
else
return constraints.get(eventId);
}
public EnumSet<TemporalSubQuery.TemporalQueryReturnColumns> getReturnColumnsForQuery(String eventId){
if (eventId==null)
return null;
else
return returnColumns.get(eventId);
}
public List<String> getOrderedQueryList(){
return orderedSet;
}
private void parseConstraints(QueryDefinitionType queryDef){
if (queryDef.getSubqueryConstraint()!=null&&queryDef.getSubqueryConstraint().size()>0){
//first, preprocess constraints to figure out which queries have the most
HashMap<String, Integer> constraintCounts = new HashMap<String, Integer>();
for (QueryConstraintType constraint : queryDef.getSubqueryConstraint()){
Integer firstCount = constraintCounts.get(constraint.getFirstQuery().getQueryId());
if (firstCount==null)
firstCount = 1;
else
firstCount++;
constraintCounts.put(constraint.getFirstQuery().getQueryId(), firstCount);
Integer secondCount = constraintCounts.get(constraint.getSecondQuery().getQueryId());
if (secondCount==null)
secondCount = 1;
else
secondCount++;
constraintCounts.put(constraint.getSecondQuery().getQueryId(), secondCount);
}
for (QueryConstraintType constraint : queryDef.getSubqueryConstraint()){
//rule one: process first and last prior to an any
//rule two: query with fewer constraints should be processed first
//rule three: first occurring query in constraint should go first
String firstQuery = constraint.getFirstQuery().getQueryId();
String secondQuery = constraint.getSecondQuery().getQueryId();
if ((constraint.getFirstQuery().getAggregateOperator()==QueryAggregateOperatorType.ANY)&&
((constraint.getSecondQuery().getAggregateOperator()==QueryAggregateOperatorType.FIRST)||
(constraint.getSecondQuery().getAggregateOperator()==QueryAggregateOperatorType.LAST))){
firstQuery = constraint.getSecondQuery().getQueryId();
secondQuery = constraint.getFirstQuery().getQueryId();
}
else if ((constraint.getSecondQuery().getAggregateOperator()==QueryAggregateOperatorType.ANY)&&
((constraint.getFirstQuery().getAggregateOperator()==QueryAggregateOperatorType.FIRST)||
(constraint.getFirstQuery().getAggregateOperator()==QueryAggregateOperatorType.LAST))){
firstQuery = constraint.getFirstQuery().getQueryId();
secondQuery = constraint.getSecondQuery().getQueryId();
}
else {
Integer firstConstraints = -1;
Integer secondConstraints = -1;
if (constraintCounts.get(firstQuery)!=null)
firstConstraints = constraintCounts.get(firstQuery);
if (constraintCounts.get(secondQuery)!=null)
secondConstraints = constraintCounts.get(secondQuery);
if (firstConstraints==null)
firstConstraints = -1;
if (secondConstraints==null)
secondConstraints = -1;
if (firstConstraints<secondConstraints){
firstQuery = constraint.getFirstQuery().getQueryId();
secondQuery = constraint.getSecondQuery().getQueryId();
}
else if (secondConstraints<firstConstraints){
firstQuery = constraint.getSecondQuery().getQueryId();
secondQuery = constraint.getFirstQuery().getQueryId();
}
else if (constraint.getOperator()==QueryOperatorType.GREATER||
constraint.getOperator()==QueryOperatorType.GREATEREQUAL){
firstQuery = constraint.getSecondQuery().getQueryId();
secondQuery = constraint.getFirstQuery().getQueryId();
}
}
int firstIndex = orderedSet.indexOf(firstQuery);
int secondIndex = orderedSet.indexOf(secondQuery);
if (firstIndex<0&&secondIndex<0){
orderedSet.add(firstQuery);
orderedSet.add(secondQuery);
}
else if (firstIndex<0){
orderedSet.add(secondIndex, firstQuery);
}
else if (secondIndex<0){
if ((firstIndex+1)>=orderedSet.size())
orderedSet.add(secondQuery);
else
orderedSet.add((firstIndex+1), secondQuery);
}
else if (secondIndex>firstIndex){
orderedSet.remove(secondIndex);
orderedSet.add(firstIndex, secondQuery);
}
//attach constraints to event that came last
HashMap<String, List<QueryConstraintType>> constraintMapping = constraints.get(secondQuery);
if (constraintMapping==null)
constraintMapping = new HashMap<String, List<QueryConstraintType>>();
List<QueryConstraintType> constraintList = constraintMapping.get(firstQuery);
if (constraintList==null)
constraintList = new ArrayList<QueryConstraintType>();
constraintList.add(constraint);
constraintMapping.put(firstQuery, constraintList);
constraints.put(secondQuery, constraintMapping);
parseReturnColumns(constraint.getFirstQuery(), queryDef.getQueryTiming());
parseReturnColumns(constraint.getSecondQuery(), queryDef.getQueryTiming());
}
}
}
private void parseReturnColumns(QueryJoinType eventJoin, String queryTiming){
String eventId = eventJoin.getQueryId();
EnumSet<TemporalSubQuery.TemporalQueryReturnColumns> columns = returnColumns.get(eventId);
QueryJoinColumnType joinColumn = eventJoin.getJoinColumn();
if (joinColumn!=null){
TemporalSubQuery.TemporalQueryReturnColumns value = null;
if (joinColumn.equals(QueryJoinColumnType.ENCOUNTER))
value = TemporalSubQuery.TemporalQueryReturnColumns.ENCOUNTER;
else if (joinColumn.equals(QueryJoinColumnType.PATIENT))
value = TemporalSubQuery.TemporalQueryReturnColumns.PATIENT;
else if (joinColumn.equals(QueryJoinColumnType.INSTANCE))
value = TemporalSubQuery.TemporalQueryReturnColumns.INSTANCE;
else if (joinColumn.equals(QueryJoinColumnType.STARTDATE)){
if (eventJoin.getAggregateOperator().equals(QueryAggregateOperatorType.FIRST))
value = TemporalSubQuery.TemporalQueryReturnColumns.FIRST_START_DATE;
else if (eventJoin.getAggregateOperator().equals(QueryAggregateOperatorType.LAST))
value = TemporalSubQuery.TemporalQueryReturnColumns.LAST_START_DATE;
else
value = TemporalSubQuery.TemporalQueryReturnColumns.START_DATE;
}
else if (joinColumn.equals(QueryJoinColumnType.ENDDATE))
if (eventJoin.getAggregateOperator().equals(QueryAggregateOperatorType.FIRST))
value = TemporalSubQuery.TemporalQueryReturnColumns.FIRST_END_DATE;
else if (eventJoin.getAggregateOperator().equals(QueryAggregateOperatorType.LAST))
value = TemporalSubQuery.TemporalQueryReturnColumns.LAST_END_DATE;
else
value = TemporalSubQuery.TemporalQueryReturnColumns.END_DATE;
else if (joinColumn.equals(QueryJoinColumnType.ENCOUNTER_STARTDATE)){
if (eventJoin.getAggregateOperator().equals(QueryAggregateOperatorType.FIRST))
value = TemporalSubQuery.TemporalQueryReturnColumns.FIRST_ENCOUNTER_START_DATE;
else if (eventJoin.getAggregateOperator().equals(QueryAggregateOperatorType.LAST))
value = TemporalSubQuery.TemporalQueryReturnColumns.LAST_ENCOUNTER_START_DATE;
else
value = TemporalSubQuery.TemporalQueryReturnColumns.ENCOUNTER_START_DATE;
}
else if (joinColumn.equals(QueryJoinColumnType.ENCOUNTER_ENDDATE))
if (eventJoin.getAggregateOperator().equals(QueryAggregateOperatorType.FIRST))
value = TemporalSubQuery.TemporalQueryReturnColumns.FIRST_ENCOUNTER_END_DATE;
else if (eventJoin.getAggregateOperator().equals(QueryAggregateOperatorType.LAST))
value = TemporalSubQuery.TemporalQueryReturnColumns.LAST_ENCOUNTER_END_DATE;
else
value = TemporalSubQuery.TemporalQueryReturnColumns.ENCOUNTER_START_DATE;
else
value = TemporalSubQuery.TemporalQueryReturnColumns.PATIENT;
if (columns==null)
columns = EnumSet.of(value);
else
columns.add(value);
}
else
columns = EnumSet.of(TemporalSubQuery.TemporalQueryReturnColumns.PATIENT);
if (queryTiming!=null&&
(queryTiming.equalsIgnoreCase(QueryTimingHandler.SAME)||
queryTiming.equalsIgnoreCase(QueryTimingHandler.SAMEVISIT))){
columns.add(TemporalSubQuery.TemporalQueryReturnColumns.ENCOUNTER);
}
returnColumns.put(eventId, columns);
}
}