/**
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* 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.
*
* The Original Code is OpenELIS code.
*
* Copyright (C) CIRG, University of Washington, Seattle WA. All Rights Reserved.
*
*/
package us.mn.state.health.lims.common.provider.query;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.validator.GenericValidator;
import us.mn.state.health.lims.common.services.PatientService;
import us.mn.state.health.lims.common.services.StatusService;
import us.mn.state.health.lims.common.services.StatusService.ExternalOrderStatus;
import us.mn.state.health.lims.common.util.StringUtil;
import us.mn.state.health.lims.common.util.XMLUtil;
import us.mn.state.health.lims.dataexchange.order.action.HL7OrderInterpreter;
import us.mn.state.health.lims.dataexchange.order.daoimpl.ElectronicOrderDAOImpl;
import us.mn.state.health.lims.dataexchange.order.valueholder.ElectronicOrder;
import us.mn.state.health.lims.panel.dao.PanelDAO;
import us.mn.state.health.lims.panel.daoimpl.PanelDAOImpl;
import us.mn.state.health.lims.panel.valueholder.Panel;
import us.mn.state.health.lims.panelitem.dao.PanelItemDAO;
import us.mn.state.health.lims.panelitem.daoimpl.PanelItemDAOImpl;
import us.mn.state.health.lims.panelitem.valueholder.PanelItem;
import us.mn.state.health.lims.test.dao.TestDAO;
import us.mn.state.health.lims.test.daoimpl.TestDAOImpl;
import us.mn.state.health.lims.test.valueholder.Test;
import us.mn.state.health.lims.typeofsample.dao.TypeOfSampleTestDAO;
import us.mn.state.health.lims.typeofsample.daoimpl.TypeOfSampleTestDAOImpl;
import us.mn.state.health.lims.common.services.TypeOfSampleService;
import us.mn.state.health.lims.typeofsample.valueholder.TypeOfSample;
import us.mn.state.health.lims.typeofsample.valueholder.TypeOfSampleTest;
import ca.uhn.hl7v2.DefaultHapiContext;
import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.HapiContext;
import ca.uhn.hl7v2.model.v251.group.OML_O21_OBSERVATION_REQUEST;
import ca.uhn.hl7v2.model.v251.group.OML_O21_ORDER_PRIOR;
import ca.uhn.hl7v2.model.v251.message.OML_O21;
import ca.uhn.hl7v2.model.v251.segment.OBR;
import ca.uhn.hl7v2.model.v251.segment.OBX;
import ca.uhn.hl7v2.model.v251.segment.ORC;
import ca.uhn.hl7v2.parser.Parser;
public class LabOrderSearchProvider extends BaseQueryProvider{
private TestDAO testDAO = new TestDAOImpl();
private PanelDAO panelDAO = new PanelDAOImpl();
private PanelItemDAO panelItemDAO = new PanelItemDAOImpl();
private TypeOfSampleTestDAO typeOfSampleTest = new TypeOfSampleTestDAOImpl();
private Map<TypeOfSample, PanelTestLists> typeOfSampleMap;
private Map<Panel, List<TypeOfSample>> panelSampleTypesMap;
private Map<String, List<TestSampleType>> testNameTestSampleTypeMap;
private static final String NOT_FOUND = "Not Found";
private static final String CANCELED = "Canceled";
private static final String REALIZED = "Realized";
private static final String PROVIDER_FIRST_NAME = "firstName";
private static final String PROVIDER_LAST_NAME = "lastName";
private static final String PROVIDER_PHONE = "phone";
@Override
public void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String orderNumber = request.getParameter("orderNumber");
StringBuilder xml = new StringBuilder();
String result = createSearchResultXML(orderNumber, xml);
if(!result.equals(VALID)){
if(result.equals(NOT_FOUND)){
result = StringUtil.getMessageForKey("electronic.order.message.orderNotFound");
}else if(result.equals(CANCELED)){
result = StringUtil.getMessageForKey("electronic.order.message.canceled");
}else if(result.equals(REALIZED)){
result = StringUtil.getMessageForKey("electronic.order.message.realized");
}
result += "\n\n" + StringUtil.getMessageForKey("electronic.order.message.suggestion");
xml.append("empty");
}
ajaxServlet.sendData(xml.toString(), result, request, response);
}
private String createSearchResultXML(String orderNumber, StringBuilder xml){
String success = VALID;
List<ElectronicOrder> eOrders = new ElectronicOrderDAOImpl().getElectronicOrdersByExternalId(orderNumber);
if(eOrders.isEmpty()){
return NOT_FOUND;
}
ElectronicOrder eOrder = eOrders.get(eOrders.size() - 1);
ExternalOrderStatus eOrderStatus = StatusService.getInstance().getExternalOrderStatusForID(eOrder.getStatusId());
if(eOrderStatus == ExternalOrderStatus.Cancelled){
return CANCELED;
}else if(eOrderStatus == ExternalOrderStatus.Realized){
return REALIZED;
}
String patientGuid = getPatientGuid(eOrder);
createOrderXML(eOrder.getData(), patientGuid, xml);
return success;
}
private String getPatientGuid(ElectronicOrder eOrder){
PatientService patientService = new PatientService(eOrder.getPatient());
return patientService.getGUID();
}
private void createOrderXML(String orderMessage, String patientGuid, StringBuilder xml){
List<Request> tests = new ArrayList<Request>();
List<Request> panels = new ArrayList<Request>();
Map<String, String> requesterValuesMap = new HashMap<String, String>();
getTestsAndPanels(tests, panels, orderMessage, requesterValuesMap);
createMaps(tests, panels);
xml.append("<order>");
addRequester(xml, requesterValuesMap);
addPatientGuid(xml, patientGuid);
addSampleTypes(xml);
addCrossPanels(xml);
addCrosstests(xml);
addAlerts(xml, patientGuid);
xml.append("</order>");
}
private void addRequester(StringBuilder xml, Map<String, String> requesterValuesMap){
xml.append("<requester>");
XMLUtil.appendKeyValue(PROVIDER_FIRST_NAME, requesterValuesMap.get(PROVIDER_FIRST_NAME), xml);
XMLUtil.appendKeyValue(PROVIDER_LAST_NAME, requesterValuesMap.get(PROVIDER_LAST_NAME), xml);
XMLUtil.appendKeyValue(PROVIDER_PHONE, requesterValuesMap.get(PROVIDER_PHONE), xml);
xml.append("</requester>");
}
private void getTestsAndPanels(List<Request> tests, List<Request> panels, String orderMessage, Map<String, String> requesterValuesMap){
HapiContext context = new DefaultHapiContext();
Parser p = context.getGenericParser();
try{
OML_O21 hapiMsg = (OML_O21)p.parse(orderMessage);
ORC commonOrderSegment = hapiMsg.getORDER().getORC();
requesterValuesMap.put(PROVIDER_PHONE, commonOrderSegment.getCallBackPhoneNumber(0).getXtn12_UnformattedTelephoneNumber().getValue());
requesterValuesMap.put(PROVIDER_LAST_NAME, commonOrderSegment.getOrderingProvider(0).getFamilyName().getSurname().getValue());
requesterValuesMap.put(PROVIDER_FIRST_NAME, commonOrderSegment.getOrderingProvider(0).getGivenName().getValue());
OML_O21_OBSERVATION_REQUEST orderRequest = hapiMsg.getORDER().getOBSERVATION_REQUEST();
addToTestOrPanel(tests, panels, orderRequest.getOBR(), orderRequest.getOBSERVATION().getOBX());
List<OML_O21_ORDER_PRIOR> priorOrders = orderRequest.getPRIOR_RESULT().getORDER_PRIORAll();
for(OML_O21_ORDER_PRIOR priorOrder : priorOrders){
addToTestOrPanel(tests, panels, priorOrder.getOBR(), priorOrder.getOBSERVATION_PRIOR().getOBX());
}
}catch(HL7Exception e){
e.printStackTrace();
}
}
private void addToTestOrPanel(List<Request> tests, List<Request> panels, OBR obr, OBX obx){
if(obr.getUniversalServiceIdentifier().getIdentifier().getValue()
.startsWith(HL7OrderInterpreter.ServiceIdentifier.PANEL.getIdentifier() + "-")){
panels.add(new Request(obr.getUniversalServiceIdentifier().getText().getValue(), obx.getObservationValue(0).getData().toString()));
}else{
tests.add(new Request(obr.getUniversalServiceIdentifier().getText().getValue(), obx.getObservationValue(0).getData().toString()));
}
}
private void createMaps(List<Request> testRequests, List<Request> panelNames){
typeOfSampleMap = new HashMap<TypeOfSample, PanelTestLists>();
panelSampleTypesMap = new HashMap<Panel, List<TypeOfSample>>();
testNameTestSampleTypeMap = new HashMap<String, List<TestSampleType>>();
createMapsForTests(testRequests);
createMapsForPanels(panelNames);
}
private void addPatientGuid(StringBuilder xml, String patientGuid){
xml.append("<patient>");
XMLUtil.appendKeyValue("guid", patientGuid, xml);
xml.append("</patient>");
}
private void createMapsForTests(List<Request> testRequests){
for(Request testRequest : testRequests){
List<Test> tests = testDAO.getActiveTestByName(testRequest.getName());
// If there is only one sample type we don't care what was requested
boolean hasSingleSampleType = tests.size() == 1;
Test singleTest = tests.get(0);
TypeOfSample singleSampleType = TypeOfSampleService.getTypeOfSampleForTest(singleTest.getId());
if(tests.size() > 1){
if(!GenericValidator.isBlankOrNull(testRequest.getSampleType())){
for(Test test : tests){
TypeOfSample typeOfSample = TypeOfSampleService.getTypeOfSampleForTest(test.getId());
if(typeOfSample.getDescription().equals(testRequest.getSampleType())){
hasSingleSampleType = true;
singleSampleType = typeOfSample;
singleTest = test;
break;
}
}
}
if(!hasSingleSampleType){
List<TestSampleType> testSampleTypeList = testNameTestSampleTypeMap.get(testRequest.getName());
if(testSampleTypeList == null){
testSampleTypeList = new ArrayList<TestSampleType>();
testNameTestSampleTypeMap.put(testRequest.getName(), testSampleTypeList);
}
for(Test test : tests){
testSampleTypeList.add(new TestSampleType(test, TypeOfSampleService.getTypeOfSampleForTest(test.getId())));
}
}
}
if(hasSingleSampleType){
PanelTestLists panelTestLists = typeOfSampleMap.get(singleSampleType);
if(panelTestLists == null){
panelTestLists = new PanelTestLists();
typeOfSampleMap.put(singleSampleType, panelTestLists);
}
panelTestLists.addTest(singleTest);
}
}
}
private void createMapsForPanels(List<Request> panelRequests){
for(Request panelRequest : panelRequests){
Panel panel = panelDAO.getPanelByName(panelRequest.getName());
if(panel != null){
List<TypeOfSample> typeOfSamples = TypeOfSampleService.getTypeOfSampleForPanelId(panel.getId());
boolean hasSingleSampleType = typeOfSamples.size() == 1;
TypeOfSample singleTypeOfSample = typeOfSamples.get(0);
if( !GenericValidator.isBlankOrNull(panelRequest.getSampleType())){
if( typeOfSamples.size() > 1){
for( TypeOfSample typeOfSample : typeOfSamples){
if( typeOfSample.getDescription().equals(panelRequest.getSampleType())){
hasSingleSampleType = true;
singleTypeOfSample = typeOfSample;
break;
}
}
}
}
if(hasSingleSampleType){
PanelTestLists panelTestLists = typeOfSampleMap.get(singleTypeOfSample);
if(panelTestLists == null){
panelTestLists = new PanelTestLists();
typeOfSampleMap.put(singleTypeOfSample, panelTestLists);
}
panelTestLists.addPanel(panel);
}else{
panelSampleTypesMap.put(panel, typeOfSamples);
}
}
}
}
private void addSampleTypes(StringBuilder xml){
xml.append("<sampleTypes>");
for(TypeOfSample typeOfSample : typeOfSampleMap.keySet()){
addSampleType(xml, typeOfSample, typeOfSampleMap.get(typeOfSample));
}
xml.append("</sampleTypes>");
}
private void addSampleType(StringBuilder xml, TypeOfSample typeOfSample, PanelTestLists panelTestLists){
xml.append("<sampleType>");
XMLUtil.appendKeyValue("id", typeOfSample.getId(), xml);
XMLUtil.appendKeyValue("name", typeOfSample.getLocalizedName(), xml);
addPanels(xml, panelTestLists.getPanels(), typeOfSample.getId());
addTests(xml, "tests", panelTestLists.getTests());
xml.append("</sampleType>");
}
private void addPanels(StringBuilder xml, List<Panel> panels, String sampleTypeId){
xml.append("<panels>");
for(Panel panel : panels){
xml.append("<panel>");
XMLUtil.appendKeyValue("id", panel.getId(), xml);
XMLUtil.appendKeyValue("name", panel.getLocalizedName(), xml);
addPanelTests(xml, panel.getId(), sampleTypeId);
xml.append("</panel>");
}
xml.append("</panels>");
}
private void addPanelTests(StringBuilder xml, String panelId, String sampleTypeId){
List<Test> panelTests = getTestsForPanelAndType(panelId, sampleTypeId);
addTests( xml, "panelTests", panelTests);
}
private List<Test> getTestsForPanelAndType(String panelId, String sampleTypeId){
List<TypeOfSampleTest> sampleTestList = typeOfSampleTest.getTypeOfSampleTestsForSampleType(sampleTypeId);
List<Integer> testList = new ArrayList<Integer>();
for(TypeOfSampleTest typeTest : sampleTestList){
testList.add(Integer.parseInt(typeTest.getTestId()));
}
List<PanelItem> panelList = panelItemDAO.getPanelItemsForPanelAndItemList(panelId, testList);
List<Test> tests = new ArrayList<Test>();
for(PanelItem item : panelList){
tests.add(item.getTest());
}
return tests;
}
private void addTests(StringBuilder xml, String parent, List<Test> tests){
xml.append("<");
xml.append(parent);
xml.append(">");
for(Test test : tests){
xml.append("<test>");
XMLUtil.appendKeyValue("id", test.getId(), xml);
XMLUtil.appendKeyValue("name", test.getLocalizedName(), xml);
xml.append("</test>");
}
xml.append("</");
xml.append(parent);
xml.append(">");
}
private void addCrossPanels(StringBuilder xml){
xml.append("<crosspanels>");
for(Panel panel : panelSampleTypesMap.keySet()){
addCrosspanel(xml, panel, panelSampleTypesMap.get(panel));
}
xml.append("</crosspanels>");
}
private void addCrosspanel(StringBuilder xml, Panel panel, List<TypeOfSample> typeOfSampleList){
xml.append("<crosspanel>");
XMLUtil.appendKeyValue("name", panel.getLocalizedName(), xml);
XMLUtil.appendKeyValue("id", panel.getId(), xml);
addPanelCrosssampletypes(xml, typeOfSampleList);
xml.append("</crosspanel>");
}
private void addPanelCrosssampletypes(StringBuilder xml, List<TypeOfSample> typeOfSampleList){
xml.append("<crosssampletypes>");
for(TypeOfSample typeOfSample : typeOfSampleList){
addCrosspanelTypeOfSample(xml, typeOfSample);
}
xml.append("</crosssampletypes>");
}
private void addCrosspanelTypeOfSample(StringBuilder xml, TypeOfSample typeOfSample){
xml.append("<crosssampletype>");
XMLUtil.appendKeyValue("id", typeOfSample.getId(), xml);
XMLUtil.appendKeyValue("name", typeOfSample.getLocalizedName(), xml);
xml.append("</crosssampletype>");
}
private void addCrosstests(StringBuilder xml){
xml.append("<crosstests>");
for(String testName : testNameTestSampleTypeMap.keySet()){
addCrosstestForTestName(xml, testName, testNameTestSampleTypeMap.get(testName));
}
xml.append("</crosstests>");
}
private void addCrosstestForTestName(StringBuilder xml, String testName, List<TestSampleType> list){
xml.append("<crosstest>");
XMLUtil.appendKeyValue("name", testName, xml);
xml.append("<crosssampletypes>");
for(TestSampleType testSampleType : list){
addTestCrosssampleType(xml, testSampleType);
}
xml.append("</crosssampletypes>");
xml.append("</crosstest>");
}
private void addTestCrosssampleType(StringBuilder xml, TestSampleType testSampleType){
xml.append("<crosssampletype>");
XMLUtil.appendKeyValue("id", testSampleType.getSampleType().getId(), xml);
XMLUtil.appendKeyValue("name", testSampleType.getSampleType().getLocalizedName(), xml);
XMLUtil.appendKeyValue("testid", testSampleType.getTest().getId(), xml);
xml.append("</crosssampletype>");
}
private void addAlerts(StringBuilder xml, String patientGuid){
PatientService patientService = new PatientService( patientGuid);
if( GenericValidator.isBlankOrNull(patientService.getEnteredDOB()) || GenericValidator.isBlankOrNull(patientService.getGender())){
XMLUtil.appendKeyValue("user_alert", StringUtil.getMessageForKey("electroinic.order.warning.missingPatientInfo"), xml);
}
}
public class PanelTestLists{
private List<Test> tests = new ArrayList<Test>();
private List<Panel> panels = new ArrayList<Panel>();
public List<Test> getTests(){
return tests;
}
public List<Panel> getPanels(){
return panels;
}
public void addPanel(Panel panel){
if(panel != null){
panels.add(panel);
}
}
public void addTest(Test test){
if(test != null){
tests.add(test);
}
}
}
public class TestSampleType{
private Test test;
private TypeOfSample sampleType;
public TestSampleType(Test test, TypeOfSample sampleType){
this.test = test;
this.sampleType = sampleType;
}
public Test getTest(){
return test;
}
public TypeOfSample getSampleType(){
return sampleType;
}
}
private class Request{
private String name;
private String sampleType;
public Request(String name, String sampleType){
this.name = name;
this.sampleType = sampleType;
}
public String getSampleType(){
return sampleType;
}
public String getName(){
return name;
}
}
}