/* * 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) ITECH, University of Washington, Seattle WA. All Rights Reserved. */ package us.mn.state.health.lims.common.services; import org.apache.commons.validator.GenericValidator; import us.mn.state.health.lims.common.util.DAOImplFactory; import us.mn.state.health.lims.common.util.DateUtil; import us.mn.state.health.lims.common.util.IdValuePair; import us.mn.state.health.lims.common.util.StringUtil; import us.mn.state.health.lims.dictionary.dao.DictionaryDAO; import us.mn.state.health.lims.dictionary.daoimpl.DictionaryDAOImpl; import us.mn.state.health.lims.patient.valueholder.Patient; import us.mn.state.health.lims.resultlimits.dao.ResultLimitDAO; import us.mn.state.health.lims.resultlimits.valueholder.ResultLimit; import us.mn.state.health.lims.siteinformation.daoimpl.SiteInformationDAOImpl; import us.mn.state.health.lims.siteinformation.valueholder.SiteInformation; import us.mn.state.health.lims.test.valueholder.Test; import us.mn.state.health.lims.typeoftestresult.dao.TypeOfTestResultDAO; import us.mn.state.health.lims.typeoftestresult.daoimpl.TypeOfTestResultDAOImpl; import java.util.*; /** */ public class ResultLimitService{ private static final DictionaryDAO dictionaryDAO = new DictionaryDAOImpl(); private static final ResultLimitDAO resultLimitDAO = DAOImplFactory.getInstance().getResultLimitsDAOImpl(); private static final double INVALID_PATIENT_AGE = Double.MIN_VALUE; private static final String NUMERIC_RESULT_TYPE_ID; private static final String SELECT_LIST_RESULT_TYPE_IDS; private double currPatientAge; static{ TypeOfTestResultDAO typeOfTestResultDAO = new TypeOfTestResultDAOImpl(); NUMERIC_RESULT_TYPE_ID = typeOfTestResultDAO.getTypeOfTestResultByType( "N" ).getId(); SELECT_LIST_RESULT_TYPE_IDS = typeOfTestResultDAO.getTypeOfTestResultByType( "D" ).getId() + typeOfTestResultDAO.getTypeOfTestResultByType( "M" ).getId(); } public ResultLimit getResultLimitForTestAndPatient( Test test, Patient patient){ return getResultLimitForTestAndPatient(test.getId(), patient); } public ResultLimit getResultLimitForTestAndPatient( String testId, Patient patient){ currPatientAge = INVALID_PATIENT_AGE; List<ResultLimit> resultLimits = getResultLimits(testId); if (resultLimits.isEmpty()) { return null; } else if (patient == null || patient.getBirthDate() == null && GenericValidator.isBlankOrNull(patient.getGender())) { return defaultResultLimit( resultLimits ); } else if ( GenericValidator.isBlankOrNull( patient.getGender() )) { return ageBasedResultLimit(resultLimits, patient); } else if (patient.getBirthDate() == null) { return genderBasedResultLimit(resultLimits, patient); } else { return ageAndGenderBasedResultLimit(resultLimits, patient); } } private ResultLimit defaultResultLimit(List<ResultLimit> resultLimits) { for (ResultLimit limit : resultLimits) { if (GenericValidator.isBlankOrNull(limit.getGender()) && limit.ageLimitsAreDefault()) { return limit; } } return new ResultLimit(); } private ResultLimit ageBasedResultLimit(List<ResultLimit> resultLimits, Patient patient) { ResultLimit resultLimit = null; // First we look for a limit with no gender for (ResultLimit limit : resultLimits) { if (GenericValidator.isBlankOrNull(limit.getGender()) && !limit.ageLimitsAreDefault() && getCurrPatientAge(patient) >= limit.getMinAge() && getCurrPatientAge(patient) <= limit.getMaxAge()) { resultLimit = limit; break; } } // if none is found then drop the no gender requirement if (resultLimit == null) { for (ResultLimit limit : resultLimits) { if (!limit.ageLimitsAreDefault() && getCurrPatientAge(patient) >= limit.getMinAge() && getCurrPatientAge(patient) <= limit.getMaxAge()) { resultLimit = limit; break; } } } return resultLimit == null ? defaultResultLimit(resultLimits) : resultLimit; } private ResultLimit genderBasedResultLimit(List<ResultLimit> resultLimits, Patient patient) { ResultLimit resultLimit = null; // First we look for a limit with no age for (ResultLimit limit : resultLimits) { if (limit.ageLimitsAreDefault() && patient.getGender().equals(limit.getGender())) { resultLimit = limit; break; } } // drop the age limit if (resultLimit == null) { for (ResultLimit limit : resultLimits) { if (patient.getGender().equals(limit.getGender())) { resultLimit = limit; break; } } } return resultLimit == null ? defaultResultLimit(resultLimits) : resultLimit; } /* * We only get here if patient has age and gender */ private ResultLimit ageAndGenderBasedResultLimit(List<ResultLimit> resultLimits, Patient patient) { ResultLimit resultLimit = null; List<ResultLimit> fullySpecifiedLimits = new ArrayList<ResultLimit>(); // first age and gender matter for (ResultLimit limit : resultLimits) { if (patient.getGender().equals(limit.getGender()) && !limit.ageLimitsAreDefault()) { // if fully qualified don't retest for only part of the // qualification fullySpecifiedLimits.add(limit); if ( patientInAgeRange( patient, limit ) ) { resultLimit = limit; break; } } } resultLimits.removeAll(fullySpecifiedLimits); // second only age matters if (resultLimit == null) { for (ResultLimit limit : resultLimits) { if (!limit.ageLimitsAreDefault() && patientInAgeRange( patient, limit )) { resultLimit = limit; break; } } } // third only gender matters return resultLimit == null ? genderBasedResultLimit(resultLimits, patient) : resultLimit; } private boolean patientInAgeRange( Patient patient, ResultLimit limit ){ return getCurrPatientAge(patient) >= limit.getMinAge() && getCurrPatientAge(patient) <= limit.getMaxAge(); } private double getCurrPatientAge(Patient patient) { if (currPatientAge == INVALID_PATIENT_AGE && patient.getBirthDate() != null) { Calendar dob = Calendar.getInstance(); dob.setTime( patient.getBirthDate() ); currPatientAge = DateUtil.getAgeInMonths( patient.getBirthDate(), new Date() ); } return currPatientAge; } public static String getDisplayNormalRange( double low, double high, String significantDigits, String separator){ if( low == Float.NEGATIVE_INFINITY && high == Float.POSITIVE_INFINITY ){ return StringUtil.getMessageForKey("result.anyValue"); } if( low == high){ return ""; } if( high == Float.POSITIVE_INFINITY){ return "> " + StringUtil.doubleWithSignificantDigits( low, significantDigits ); } if( low == Float.NEGATIVE_INFINITY ){ return "< " + StringUtil.doubleWithSignificantDigits( high, significantDigits ); } return StringUtil.doubleWithSignificantDigits( low, significantDigits ) + separator + StringUtil.doubleWithSignificantDigits( high, significantDigits ); } public static String getDisplayReferenceRange( ResultLimit resultLimit, String significantDigits, String separator){ String range = ""; if( resultLimit != null && !GenericValidator.isBlankOrNull( resultLimit.getResultTypeId() )){ if( NUMERIC_RESULT_TYPE_ID.equals( resultLimit.getResultTypeId() ) ){ range = getDisplayNormalRange( resultLimit.getLowNormal(), resultLimit.getHighNormal(), significantDigits, separator ); }else if( SELECT_LIST_RESULT_TYPE_IDS.contains( resultLimit.getResultTypeId() ) && !GenericValidator.isBlankOrNull( resultLimit.getDictionaryNormalId() ) ){ return dictionaryDAO.getDataForId( resultLimit.getDictionaryNormalId() ).getLocalizedName(); } } return range; } /** * Get the valid range for numeric result limits. For other result types an empty string will be returned * @param resultLimit The limit from which we will get the valid range * @param significantDigits The numbe of significant digit to display * @param separator -- how to separate the numbers * @return The range */ public static String getDisplayValidRange( ResultLimit resultLimit, String significantDigits, String separator){ String range = ""; if( resultLimit != null && !GenericValidator.isBlankOrNull( resultLimit.getResultTypeId() )){ if( NUMERIC_RESULT_TYPE_ID.equals( resultLimit.getResultTypeId() ) ){ range = getDisplayNormalRange( resultLimit.getLowValid(), resultLimit.getHighValid(), significantDigits, separator ); } } return range; } public static String getDisplayAgeRange( ResultLimit resultLimit, String separator){ if( resultLimit.getMinAge() == 0 && resultLimit.getMaxAge() == Float.POSITIVE_INFINITY ){ return StringUtil.getMessageForKey("age.anyAge"); } if( resultLimit.getMaxAge() == Float.POSITIVE_INFINITY ){ return ">" + resultLimit.getMinAge(); } return resultLimit.getMinAge() + separator + resultLimit.getMaxAge(); } public static List<ResultLimit> getResultLimits(Test test){ return getResultLimits(test.getId()); } public static List<ResultLimit> getResultLimits(String testId){ return resultLimitDAO.getAllResultLimitsForTest(testId); } /** * The id in the returned set of IdValuePair refers to the upper end of the age range in months * It will be either a number or "Infinity" * @return A list of pairs */ public static List<IdValuePair> getPredefinedAgeRanges(){ List<IdValuePair> ages = new ArrayList<IdValuePair>(); List<SiteInformation> siteInformationList = new SiteInformationDAOImpl().getSiteInformationByDomainName("resultAgeRange"); for( SiteInformation info : siteInformationList){ String localizedName = null; if("new born".equals(info.getName())){ localizedName = info.getLocalizedName(); }else if( "infant".equals(info.getName())){ localizedName = info.getLocalizedName(); }else if( "young child".equals(info.getName())){ localizedName = info.getLocalizedName(); }else if( "child".equals(info.getName())){ localizedName = info.getLocalizedName(); }else if( "adult".equals(info.getName())){ localizedName = info.getLocalizedName(); } ages.add(new IdValuePair(info.getValue(), localizedName)); } Collections.sort(ages, new Comparator<IdValuePair>() { @Override public int compare(IdValuePair o1, IdValuePair o2) { if( "Infinity".equals(o1.getId())){ return 1; } if( "Infinity".equals(o2.getId())){ return -1; } return Integer.parseInt(o1.getId()) - Integer.parseInt(o2.getId()); } }); return ages; } }