us.mn.state.health.lims.reports.action.implementation.PatientReport.java Source code

Java tutorial

Introduction

Here is the source code for us.mn.state.health.lims.reports.action.implementation.PatientReport.java

Source

/**
 * 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.reports.action.implementation;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.validator.GenericValidator;
import org.hibernate.Transaction;
import us.mn.state.health.lims.address.dao.PersonAddressDAO;
import us.mn.state.health.lims.address.daoimpl.AddressPartDAOImpl;
import us.mn.state.health.lims.address.daoimpl.PersonAddressDAOImpl;
import us.mn.state.health.lims.address.valueholder.AddressPart;
import us.mn.state.health.lims.address.valueholder.PersonAddress;
import us.mn.state.health.lims.analysis.dao.AnalysisDAO;
import us.mn.state.health.lims.analysis.daoimpl.AnalysisDAOImpl;
import us.mn.state.health.lims.analysis.valueholder.Analysis;
import us.mn.state.health.lims.common.action.BaseActionForm;
import us.mn.state.health.lims.common.exception.LIMSRuntimeException;
import us.mn.state.health.lims.common.formfields.FormFields;
import us.mn.state.health.lims.common.formfields.FormFields.Field;
import us.mn.state.health.lims.common.provider.validation.IAccessionNumberValidator;
import us.mn.state.health.lims.common.services.*;
import us.mn.state.health.lims.common.services.NoteService.NoteType;
import us.mn.state.health.lims.common.services.ObservationHistoryService.ObservationType;
import us.mn.state.health.lims.common.services.StatusService.AnalysisStatus;
import us.mn.state.health.lims.common.util.ConfigurationProperties;
import us.mn.state.health.lims.common.util.ConfigurationProperties.Property;
import us.mn.state.health.lims.common.util.DateUtil;
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.dictionary.valueholder.Dictionary;
import us.mn.state.health.lims.hibernate.HibernateUtil;
import us.mn.state.health.lims.laborder.dao.LabOrderTypeDAO;
import us.mn.state.health.lims.laborder.daoimpl.LabOrderTypeDAOImpl;
import us.mn.state.health.lims.laborder.valueholder.LabOrderType;
import us.mn.state.health.lims.note.dao.NoteDAO;
import us.mn.state.health.lims.note.daoimpl.NoteDAOImpl;
import us.mn.state.health.lims.observationhistory.dao.ObservationHistoryDAO;
import us.mn.state.health.lims.observationhistory.daoimpl.ObservationHistoryDAOImpl;
import us.mn.state.health.lims.observationhistory.valueholder.ObservationHistory;
import us.mn.state.health.lims.observationhistorytype.daoImpl.ObservationHistoryTypeDAOImpl;
import us.mn.state.health.lims.observationhistorytype.valueholder.ObservationHistoryType;
import us.mn.state.health.lims.organization.dao.OrganizationDAO;
import us.mn.state.health.lims.organization.daoimpl.OrganizationDAOImpl;
import us.mn.state.health.lims.organization.valueholder.Organization;
import us.mn.state.health.lims.patient.dao.PatientDAO;
import us.mn.state.health.lims.patient.daoimpl.PatientDAOImpl;
import us.mn.state.health.lims.patient.valueholder.Patient;
import us.mn.state.health.lims.patientidentity.dao.PatientIdentityDAO;
import us.mn.state.health.lims.patientidentity.daoimpl.PatientIdentityDAOImpl;
import us.mn.state.health.lims.patientidentity.valueholder.PatientIdentity;
import us.mn.state.health.lims.patientidentitytype.dao.PatientIdentityTypeDAO;
import us.mn.state.health.lims.patientidentitytype.daoimpl.PatientIdentityTypeDAOImpl;
import us.mn.state.health.lims.patientidentitytype.valueholder.PatientIdentityType;
import us.mn.state.health.lims.person.dao.PersonDAO;
import us.mn.state.health.lims.person.daoimpl.PersonDAOImpl;
import us.mn.state.health.lims.person.valueholder.Person;
import us.mn.state.health.lims.provider.dao.ProviderDAO;
import us.mn.state.health.lims.provider.daoimpl.ProviderDAOImpl;
import us.mn.state.health.lims.provider.valueholder.Provider;
import us.mn.state.health.lims.referral.dao.ReferralDAO;
import us.mn.state.health.lims.referral.dao.ReferralReasonDAO;
import us.mn.state.health.lims.referral.dao.ReferralResultDAO;
import us.mn.state.health.lims.referral.daoimpl.ReferralDAOImpl;
import us.mn.state.health.lims.referral.daoimpl.ReferralReasonDAOImpl;
import us.mn.state.health.lims.referral.daoimpl.ReferralResultDAOImpl;
import us.mn.state.health.lims.referral.valueholder.ReferralResult;
import us.mn.state.health.lims.reports.action.implementation.reportBeans.ClinicalPatientData;
import us.mn.state.health.lims.requester.dao.RequesterTypeDAO;
import us.mn.state.health.lims.requester.dao.SampleRequesterDAO;
import us.mn.state.health.lims.requester.daoimpl.RequesterTypeDAOImpl;
import us.mn.state.health.lims.requester.daoimpl.SampleRequesterDAOImpl;
import us.mn.state.health.lims.requester.valueholder.RequesterType;
import us.mn.state.health.lims.requester.valueholder.SampleRequester;
import us.mn.state.health.lims.result.dao.ResultDAO;
import us.mn.state.health.lims.result.daoimpl.ResultDAOImpl;
import us.mn.state.health.lims.result.valueholder.Result;
import us.mn.state.health.lims.sample.dao.SampleDAO;
import us.mn.state.health.lims.sample.daoimpl.SampleDAOImpl;
import us.mn.state.health.lims.sample.util.AccessionNumberUtil;
import us.mn.state.health.lims.sample.valueholder.Sample;
import us.mn.state.health.lims.samplehuman.dao.SampleHumanDAO;
import us.mn.state.health.lims.samplehuman.daoimpl.SampleHumanDAOImpl;
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.typeoftestresult.valueholder.TypeOfTestResult.ResultType;

import java.lang.reflect.InvocationTargetException;
import java.sql.Date;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.util.*;

public abstract class PatientReport extends Report {

    private static final DecimalFormat twoDecimalFormat = new DecimalFormat("#.##");
    private static String ADDRESS_DEPT_ID;
    private static String ADDRESS_COMMUNE_ID;
    protected String currentContactInfo = "";
    protected String currentSiteInfo = "";

    protected SampleHumanDAO sampleHumanDAO = new SampleHumanDAOImpl();
    protected DictionaryDAO dictionaryDAO = new DictionaryDAOImpl();
    private ResultDAO resultDAO = new ResultDAOImpl();
    protected SampleDAO sampleDAO = new SampleDAOImpl();
    protected PatientDAO patientDAO = new PatientDAOImpl();
    protected PersonDAO personDAO = new PersonDAOImpl();
    protected ProviderDAO providerDAO = new ProviderDAOImpl();
    protected SampleRequesterDAO requesterDAO = new SampleRequesterDAOImpl();
    protected TestDAO testDAO = new TestDAOImpl();
    protected ReferralReasonDAO referralReasonDAO = new ReferralReasonDAOImpl();
    protected ReferralDAO referralDao = new ReferralDAOImpl();
    protected ReferralResultDAO referralResultDAO = new ReferralResultDAOImpl();
    protected ObservationHistoryDAO observationDAO = new ObservationHistoryDAOImpl();
    protected AnalysisDAO analysisDAO = new AnalysisDAOImpl();
    protected NoteDAO noteDAO = new NoteDAOImpl();
    protected PersonAddressDAO addressDAO = new PersonAddressDAOImpl();
    private LabOrderTypeDAO labOrderTypeDAO = new LabOrderTypeDAOImpl();
    private List<String> handledOrders;
    private List<Analysis> updatedAnalysis = new ArrayList<Analysis>();

    private String lowerNumber;
    private String upperNumber;
    protected String STNumber = null;
    protected String subjectNumber = null;
    protected String healthRegion = null;
    protected String healthDistrict = null;
    protected String patientName = null;
    protected String patientDOB = null;
    protected String currentConclusion = null;

    protected String patientDept = null;
    protected String patientCommune = null;

    protected IPatientService patientService;
    protected Provider currentProvider;
    protected Analysis reportAnalysis;
    protected String reportReferralResultValue;
    protected List<ClinicalPatientData> reportItems;
    protected String completionDate;
    protected SampleService currentSampleService;

    protected static String ST_NUMBER_IDENTITY_TYPE_ID = "0";
    protected static String SUBJECT_NUMBER_IDENTITY_TYPE_ID = "0";
    protected static String HEALTH_REGION_IDENTITY_TYPE_ID = "0";
    protected static String HEALTH_DISTRICT_IDENTITY_TYPE_ID = "0";
    protected static String LAB_TYPE_OBSERVATION_ID = "0";
    protected static String LAB_SUBTYPE_OBSERVATION_ID = "0";
    protected static Long PERSON_REQUESTER_TYPE_ID;
    protected static Long ORGANIZATION_REQUESTER_TYPE_ID;
    protected static final NoteType[] FILTER = { NoteType.EXTERNAL, NoteType.REJECTION_REASON,
            NoteType.NON_CONFORMITY };
    protected Map<String, Boolean> sampleCompleteMap;
    protected Map<String, Boolean> sampleCorrectedMap;

    static {
        PatientIdentityTypeDAO identityTypeDAO = new PatientIdentityTypeDAOImpl();
        List<PatientIdentityType> typeList = identityTypeDAO.getAllPatientIdenityTypes();

        for (PatientIdentityType identityType : typeList) {
            if ("ST".equals(identityType.getIdentityType())) {
                ST_NUMBER_IDENTITY_TYPE_ID = identityType.getId();
            } else if ("SUBJECT".equals(identityType.getIdentityType())) {
                SUBJECT_NUMBER_IDENTITY_TYPE_ID = identityType.getId();
            } else if ("HEALTH REGION".equals(identityType.getIdentityType())) {
                HEALTH_REGION_IDENTITY_TYPE_ID = identityType.getId();
            } else if ("HEALTH DISTRICT".equals(identityType.getIdentityType())) {
                HEALTH_DISTRICT_IDENTITY_TYPE_ID = identityType.getId();
            }
        }

        RequesterTypeDAO requesterTypeDAO = new RequesterTypeDAOImpl();
        RequesterType type = requesterTypeDAO.getRequesterTypeByName("provider");
        if (type != null) {
            PERSON_REQUESTER_TYPE_ID = Long.parseLong(type.getId());
        }

        type = requesterTypeDAO.getRequesterTypeByName("organization");
        if (type != null) {
            ORGANIZATION_REQUESTER_TYPE_ID = Long.parseLong(type.getId());
        }

        List<AddressPart> partList = new AddressPartDAOImpl().getAll();
        for (AddressPart part : partList) {
            if ("department".equals(part.getPartName())) {
                ADDRESS_DEPT_ID = part.getId();
            } else if ("commune".equals(part.getPartName())) {
                ADDRESS_COMMUNE_ID = part.getId();
            }
        }

        ObservationHistoryType ohType = new ObservationHistoryTypeDAOImpl().getByName("primaryOrderType");
        LAB_TYPE_OBSERVATION_ID = ohType == null ? null : ohType.getId();

        ohType = new ObservationHistoryTypeDAOImpl().getByName("secondaryOrderType");
        LAB_SUBTYPE_OBSERVATION_ID = ohType == null ? null : ohType.getId();

    }

    abstract protected String getReportNameForParameterPage();

    abstract protected String getSiteLogo();

    abstract protected void postSampleBuild();

    abstract protected void createReportItems();

    abstract protected void setReferredResult(ClinicalPatientData data, Result result);

    protected boolean appendUOMToRange() {
        return true;
    }

    protected boolean augmentResultWithFlag() {
        return true;
    }

    protected boolean useReportingDescription() {
        return true;
    }

    @Override
    protected String errorReportFileName() {
        return HAITI_ERROR_REPORT;
    }

    public void setRequestParameters(BaseActionForm dynaForm) {
        try {
            PropertyUtils.setProperty(dynaForm, "reportName", getReportNameForParameterPage());

            PropertyUtils.setProperty(dynaForm, "useAccessionDirect", Boolean.TRUE);
            PropertyUtils.setProperty(dynaForm, "useHighAccessionDirect", Boolean.TRUE);
            PropertyUtils.setProperty(dynaForm, "usePatientNumberDirect", Boolean.TRUE);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    public void initializeReport(BaseActionForm dynaForm) {
        super.initializeReport();
        errorFound = false;
        lowerNumber = dynaForm.getString("accessionDirect");
        upperNumber = dynaForm.getString("highAccessionDirect");
        String patientNumber = dynaForm.getString("patientNumberDirect");

        handledOrders = new ArrayList<String>();

        createReportParameters();

        boolean valid;
        List<Sample> reportSampleList = new ArrayList<Sample>();

        if (GenericValidator.isBlankOrNull(lowerNumber) && GenericValidator.isBlankOrNull(upperNumber)) {
            List<Patient> patientList = new ArrayList<Patient>();
            valid = findPatientByPatientNumber(patientNumber, patientList);

            if (valid) {
                reportSampleList = findReportSamplesForReportPatient(patientList);
            }
        } else {
            valid = validateAccessionNumbers();

            if (valid) {
                reportSampleList = findReportSamples(lowerNumber, upperNumber);
            }
        }

        sampleCompleteMap = new HashMap<String, Boolean>();
        sampleCorrectedMap = new HashMap<String, Boolean>();
        initializeReportItems();

        if (reportSampleList.isEmpty()) {
            add1LineErrorMessage("report.error.message.noPrintableItems");
        } else {

            for (Sample sample : reportSampleList) {
                currentSampleService = new SampleService(sample);
                handledOrders.add(sample.getId());
                sampleCompleteMap.put(sample.getAccessionNumber(), Boolean.TRUE);
                findCompletionDate();
                findPatientFromSample();
                findContactInfo();
                findPatientInfo();
                createReportItems();
            }

            postSampleBuild();
        }

        if (!updatedAnalysis.isEmpty()) {
            Transaction tx = HibernateUtil.getSession().beginTransaction();

            try {
                for (Analysis analysis : updatedAnalysis) {
                    analysisDAO.updateData(analysis, true);
                }
                tx.commit();

            } catch (LIMSRuntimeException lre) {
                tx.rollback();

            }
        }
    }

    private void findCompletionDate() {
        Date date = currentSampleService.getCompletedDate();
        completionDate = date == null ? null : DateUtil.convertSqlDateToStringDate(date);
    }

    private void findPatientInfo() {
        if (patientService.getPerson() == null) {
            return;
        }

        patientDept = "";
        patientCommune = "";
        if (ADDRESS_DEPT_ID != null) {
            PersonAddress deptAddress = addressDAO.getByPersonIdAndPartId(patientService.getPerson().getId(),
                    ADDRESS_DEPT_ID);

            if (deptAddress != null && !GenericValidator.isBlankOrNull(deptAddress.getValue())) {
                patientDept = dictionaryDAO.getDictionaryById(deptAddress.getValue()).getDictEntry();
            }
        }

        if (ADDRESS_COMMUNE_ID != null) {
            PersonAddress deptAddress = addressDAO.getByPersonIdAndPartId(patientService.getPerson().getId(),
                    ADDRESS_COMMUNE_ID);

            if (deptAddress != null) {
                patientCommune = deptAddress.getValue();
            }
        }

    }

    private void findContactInfo() {
        List<SampleRequester> requesters = requesterDAO.getRequestersForSampleId(currentSampleService.getId());
        currentContactInfo = "";
        currentSiteInfo = "";
        currentProvider = null;

        for (SampleRequester requester : requesters) {
            if (ORGANIZATION_REQUESTER_TYPE_ID == requester.getRequesterTypeId()) {
                OrganizationDAO organizationDAO = new OrganizationDAOImpl();
                Organization org = organizationDAO.getOrganizationById(String.valueOf(requester.getRequesterId()));
                if (org != null) {
                    currentSiteInfo = org.getOrganizationName();
                }
            }

            if (PERSON_REQUESTER_TYPE_ID == requester.getRequesterTypeId()) {
                StringBuilder buffer = new StringBuilder();
                Person person = new Person();
                person.setId(String.valueOf(requester.getRequesterId()));
                personDAO.getData(person);
                if (person.getId() != null) {
                    buffer.append(person.getLastName());
                    if (!GenericValidator.isBlankOrNull(person.getLastName())
                            && !GenericValidator.isBlankOrNull(person.getFirstName())) {
                        buffer.append(", ");
                    }
                    buffer.append(person.getFirstName());

                    currentProvider = providerDAO.getProviderByPerson(person);
                }

                currentContactInfo = buffer.toString();
            }
        }
    }

    private boolean findPatientByPatientNumber(String patientNumber, List<Patient> patientList) {
        patientService = null;
        PatientIdentityDAO patientIdentityDAO = new PatientIdentityDAOImpl();
        patientList.addAll(patientDAO.getPatientsByNationalId(patientNumber));

        if (patientList.isEmpty()) {
            List<PatientIdentity> identities = patientIdentityDAO.getPatientIdentitiesByValueAndType(patientNumber,
                    ST_NUMBER_IDENTITY_TYPE_ID);

            if (identities.isEmpty()) {
                identities = patientIdentityDAO.getPatientIdentitiesByValueAndType(patientNumber,
                        SUBJECT_NUMBER_IDENTITY_TYPE_ID);
            }

            if (!identities.isEmpty()) {

                for (PatientIdentity patientIdentity : identities) {
                    String reportPatientId = patientIdentity.getPatientId();
                    Patient patient = new Patient();
                    patient.setId(reportPatientId);
                    patientDAO.getData(patient);
                    patientList.add(patient);
                }
            }
        }

        return !patientList.isEmpty();
    }

    private List<Sample> findReportSamplesForReportPatient(List<Patient> patientList) {
        List<Sample> sampleList = new ArrayList<Sample>();
        for (Patient searchPatient : patientList) {
            sampleList.addAll(sampleHumanDAO.getSamplesForPatient(searchPatient.getId()));
        }

        return sampleList;
    }

    private boolean validateAccessionNumbers() {

        if (GenericValidator.isBlankOrNull(lowerNumber) && GenericValidator.isBlankOrNull(upperNumber)) {
            add1LineErrorMessage("report.error.message.noParameters");
            return false;
        }

        if (GenericValidator.isBlankOrNull(lowerNumber)) {
            lowerNumber = upperNumber;
        } else if (GenericValidator.isBlankOrNull(upperNumber)) {
            upperNumber = lowerNumber;
        }

        if (lowerNumber.length() != upperNumber.length()
                || AccessionNumberUtil.correctFormat(lowerNumber,
                        false) != IAccessionNumberValidator.ValidationResults.SUCCESS
                || AccessionNumberUtil.correctFormat(lowerNumber,
                        false) != IAccessionNumberValidator.ValidationResults.SUCCESS) {
            add1LineErrorMessage("report.error.message.accession.not.valid");
            return false;
        }

        if (lowerNumber.compareToIgnoreCase(upperNumber) > 0) {
            String temp = upperNumber;
            upperNumber = lowerNumber;
            lowerNumber = temp;
        }

        return true;
    }

    private List<Sample> findReportSamples(String lowerNumber, String upperNumber) {
        List<Sample> sampleList = sampleDAO.getSamplesByAccessionRange(lowerNumber, upperNumber);
        return sampleList == null ? new ArrayList<Sample>() : sampleList;
    }

    protected void findPatientFromSample() {
        Patient patient = sampleHumanDAO.getPatientForSample(currentSampleService.getSample());

        if (patientService == null || !patient.getId().equals(patientService.getPatientId())) {
            STNumber = null;
            patientDOB = null;
            patientService = new PatientService(patient);
        }
    }

    @Override
    protected void createReportParameters() {
        super.createReportParameters();
        reportParameters.put("siteId", ConfigurationProperties.getInstance().getPropertyValue(Property.SiteCode));
        reportParameters.put("siteLogo", useLogo ? getSiteLogo() : null);
        if (ConfigurationProperties.getInstance().isPropertyValueEqual(Property.configurationName, "CI LNSP")) {
            reportParameters.put("headerName", "CILNSPHeader.jasper");
            reportParameters.put("printLNSPLabPersons", Boolean.TRUE);
        } else if (ConfigurationProperties.getInstance().isPropertyValueEqual(Property.configurationName,
                "Haiti LNSP")) {
            reportParameters.put("useSTNumber", Boolean.FALSE);
        } else {
            reportParameters.put("useSTNumber", Boolean.TRUE);
        }

        reportParameters.put("leftImage", getLeftImage());
    }

    protected String getLeftImage() {
        if (ConfigurationProperties.getInstance().isPropertyValueEqual(Property.configurationName, "CI IPCI")) {
            return "IPCI_Logo.png";
        } else if (ConfigurationProperties.getInstance().isPropertyValueEqual(Property.configurationName,
                "CI_REGIONAL")) {
            return "LNSPLogo.jpg";
        } else {
            return "HaitiFlag.gif";
        }
    }

    protected String getPatientDOB() {
        if (patientDOB == null) {
            patientDOB = patientService.getBirthdayForDisplay();
        }

        return patientDOB;
    }

    protected String getLazyPatientIdentity(String identity, String id) {
        if (identity == null) {
            identity = " ";
            List<PatientIdentity> identities = patientService.getIdentityList();
            for (PatientIdentity patientIdentity : identities) {
                if (patientIdentity.getIdentityTypeId().equals(id)) {
                    identity = patientIdentity.getIdentityData();
                    break;
                }
            }
        }

        return identity;
    }

    protected void setPatientName(ClinicalPatientData data) {
        data.setPatientName(patientService.getLastFirstName());
        data.setFirstName(patientService.getFirstName());
        data.setLastName(patientService.getLastName());
    }

    protected void reportResultAndConclusion(ClinicalPatientData data) {
        List<Result> resultList = resultDAO.getResultsByAnalysis(reportAnalysis);

        Test test = reportAnalysis.getTest();
        String note = new NoteService(reportAnalysis).getNotesAsString(true, true, "<br/>", FILTER, true);
        if (note != null) {
            data.setNote(note);
        }
        data.setTestSection(reportAnalysis.getTestSection().getLocalizedName());
        data.setTestSortOrder(GenericValidator.isBlankOrNull(test.getSortOrder()) ? Integer.MAX_VALUE
                : Integer.parseInt(test.getSortOrder()));
        data.setSectionSortOrder(test.getTestSection().getSortOrderInt());

        if (StatusService.getInstance().matches(reportAnalysis.getStatusId(), AnalysisStatus.Canceled)) {
            data.setResult(StringUtil.getMessageForKey("report.test.status.canceled"));
        } else if (reportAnalysis.isReferredOut()) {
            data.setResult(StringUtil.getMessageForKey("report.test.status.inProgress"));
            return;
            /* Not sure which rules this would support -- above statement was conditional on no patient alerts
               if( noResults( resultList ) ){
            data.setResult( StringUtil.getMessageForKey( "report.test.status.referredOut" ) );
               }else{
            setAppropriateResults( resultList, data );
            setReferredResult( data, resultList.get( 0 ) );
            setNormalRange( data, test, resultList.get( 0 ) );
               }
            */
        } else if (!StatusService.getInstance().matches(reportAnalysis.getStatusId(), AnalysisStatus.Finalized)) {
            sampleCompleteMap.put(currentSampleService.getAccessionNumber(), Boolean.FALSE);
            data.setResult(StringUtil.getMessageForKey("report.test.status.inProgress"));
        } else {
            if (resultList.isEmpty()) {
                data.setResult(StringUtil.getMessageForKey("report.test.status.inProgress"));
            } else {
                setAppropriateResults(resultList, data);
                Result result = resultList.get(0);
                setCorrectedStatus(result, data);
                setNormalRange(data, test, result);
                data.setResult(getAugmentedResult(data, result));
                data.setFinishDate(reportAnalysis.getCompletedDateForDisplay());
                data.setAlerts(getResultFlag(result, null, data));
            }
        }

        data.setParentResult(reportAnalysis.getParentResult());
        data.setConclusion(currentConclusion);
    }

    private void setCorrectedStatus(Result result, ClinicalPatientData data) {
        if (reportAnalysis.isCorrectedSincePatientReport() && !GenericValidator.isBlankOrNull(result.getValue())) {
            data.setCorrectedResult(true);
            sampleCorrectedMap.put(currentSampleService.getAccessionNumber(), true);
            reportAnalysis.setCorrectedSincePatientReport(false);
            updatedAnalysis.add(reportAnalysis);
        }
    }

    private boolean noResults(List<Result> resultList) {
        if (resultList.isEmpty() || GenericValidator.isBlankOrNull(resultList.get(0).getValue())) {
            return true;
        }

        Result result = resultList.get(0);
        return (ResultType.MULTISELECT.getDBValue().equals(result.getResultType())
                || ResultType.DICTIONARY.getDBValue().equals(result.getResultType()))
                && "0".equals(result.getValue());

    }

    private void setNormalRange(ClinicalPatientData data, Test test, Result result) {
        String uom = getUnitOfMeasure(test);
        data.setTestRefRange(addIfNotEmpty(getRange(result), appendUOMToRange() ? uom : null));
        data.setUom(uom);
    }

    private String getAugmentedResult(ClinicalPatientData data, Result result) {
        String resultValue = data.getResult();
        if (TestIdentityService.isTestNumericViralLoad(reportAnalysis.getTest())) {
            try {
                resultValue += " (" + twoDecimalFormat.format(Math.log10(Double.parseDouble(resultValue)))
                        + ")log ";
            } catch (IllegalFormatException e) {
                // no-op
            }
        }

        return resultValue + (augmentResultWithFlag() ? getResultFlag(result, null) : "");
    }

    protected String getResultFlag(Result result, String imbed) {
        return getResultFlag(result, imbed, null);
    }

    protected String getResultFlag(Result result, String imbed, ClinicalPatientData data) {
        String flag = "";
        try {
            if (ResultType.NUMERIC.matches(result.getResultType())
                    && !GenericValidator.isBlankOrNull(result.getValue())) {
                if (result.getMinNormal() != null & result.getMaxNormal() != null
                        && (result.getMinNormal() != 0.0 || result.getMaxNormal() != 0.0)) {
                    if (Double.valueOf(result.getValue()) < result.getMinNormal()) {
                        flag = "B";
                    } else if (Double.valueOf(result.getValue()) > result.getMaxNormal()) {
                        flag = "E";
                    }
                }
            } else if (ResultType.isDictionaryVariant(result.getResultType())) {
                boolean isAbnormal = false;

                if (data == null) {
                    isAbnormal = new ResultService(result).isAbnormalDictionaryResult();
                } else {
                    isAbnormal = data.getAbnormalResult();
                }
                if (isAbnormal) {
                    flag = "*";
                }
            }

            if (!GenericValidator.isBlankOrNull(flag)) {
                if (data != null) {
                    data.setAbnormalResult(Boolean.TRUE);
                }
                if (!GenericValidator.isBlankOrNull(imbed)) {
                    return " <b>" + flag + "," + imbed + "</b>";
                } else {
                    return " <b>" + flag + "</b>";
                }
            }
        } catch (NumberFormatException e) {
            // no-op
        }

        if (!GenericValidator.isBlankOrNull(imbed)) {
            return " (<b>" + imbed + "</b>)";
        }

        return "";
    }

    protected String getRange(Result result) {
        return new ResultService(result).getDisplayReferenceRange(true);
    }

    protected String getUnitOfMeasure(Test test) {
        return (test != null && test.getUnitOfMeasure() != null) ? test.getUnitOfMeasure().getName() : "";
    }

    private void setAppropriateResults(List<Result> resultList, ClinicalPatientData data) {
        String reportResult = "";
        if (!resultList.isEmpty()) {

            //If only one result just get it and get out
            if (resultList.size() == 1) {
                Result result = resultList.get(0);
                if (ResultType.isDictionaryVariant(result.getResultType())) {
                    Dictionary dictionary = new Dictionary();
                    dictionary.setId(result.getValue());
                    dictionaryDAO.getData(dictionary);
                    data.setAbnormalResult(new ResultService(result).isAbnormalDictionaryResult());

                    if (result.getAnalyte() != null && "Conclusion".equals(result.getAnalyte().getAnalyteName())) {
                        currentConclusion = dictionary.getId() != null ? dictionary.getLocalizedName() : "";
                    } else {
                        reportResult = dictionary.getId() != null ? dictionary.getLocalizedName() : "";
                    }
                } else {
                    reportResult = new ResultService(result).getResultValue(true);
                    //TODO - how is this used.  Selection types can also have UOM and reference ranges
                    data.setHasRangeAndUOM(ResultType.NUMERIC.matches(result.getResultType()));
                }
            } else {
                //If multiple results it can be a quantified result, multiple results with quantified other results or it can be a conclusion

                String resultType = resultList.get(0).getResultType();

                if (ResultType.DICTIONARY.matches(resultType)) {
                    List<Result> dictionaryResults = new ArrayList<Result>();
                    Result quantification = null;
                    for (Result sibResult : resultList) {
                        if (ResultType.DICTIONARY.matches(sibResult.getResultType())) {
                            dictionaryResults.add(sibResult);
                        } else if (ResultType.ALPHA.matches(sibResult.getResultType())
                                && sibResult.getParentResult() != null) {
                            quantification = sibResult;
                        }
                    }

                    Dictionary dictionary = new Dictionary();
                    for (Result sibResult : dictionaryResults) {
                        dictionary.setId(sibResult.getValue());
                        dictionaryDAO.getData(dictionary);
                        if (sibResult.getAnalyte() != null
                                && "Conclusion".equals(sibResult.getAnalyte().getAnalyteName())) {
                            currentConclusion = dictionary.getId() != null ? dictionary.getLocalizedName() : "";
                        } else {
                            reportResult = dictionary.getId() != null ? dictionary.getLocalizedName() : "";
                            if (quantification != null
                                    && quantification.getParentResult().getId().equals(sibResult.getId())) {
                                reportResult += ": " + quantification.getValue();
                            }
                        }
                    }
                } else if (ResultType.isMultiSelectVariant(resultType)) {
                    Dictionary dictionary = new Dictionary();
                    StringBuilder multiResult = new StringBuilder();

                    Collections.sort(resultList, new Comparator<Result>() {
                        @Override
                        public int compare(Result o1, Result o2) {
                            if (o1.getGrouping() == o2.getGrouping()) {
                                return Integer.parseInt(o1.getId()) - Integer.parseInt(o2.getId());
                            } else {
                                return o1.getGrouping() - o2.getGrouping();
                            }
                        }
                    });

                    Result quantifiedResult = null;
                    for (Result subResult : resultList) {
                        if (ResultType.ALPHA.matches(subResult.getResultType())) {
                            quantifiedResult = subResult;
                            resultList.remove(subResult);
                            break;
                        }
                    }
                    int currentGrouping = resultList.get(0).getGrouping();
                    for (Result subResult : resultList) {
                        if (subResult.getGrouping() != currentGrouping) {
                            currentGrouping = subResult.getGrouping();
                            multiResult.append("-------\n");
                        }
                        dictionary.setId(subResult.getValue());
                        dictionaryDAO.getData(dictionary);

                        if (dictionary.getId() != null) {
                            multiResult.append(dictionary.getLocalizedName());
                            if (quantifiedResult != null
                                    && quantifiedResult.getParentResult().getId().equals(subResult.getId())
                                    && !GenericValidator.isBlankOrNull(quantifiedResult.getValue())) {
                                multiResult.append(": ");
                                multiResult.append(quantifiedResult.getValue());
                            }
                            multiResult.append("\n");
                        }
                    }

                    if (multiResult.length() > 1) {
                        // remove last "\n"
                        multiResult.setLength(multiResult.length() - 1);
                    }

                    reportResult = multiResult.toString();
                }
            }
        }
        data.setResult(reportResult);

    }

    /**
     * @see PatientReport#initializeReportItems()
     */
    protected void initializeReportItems() {
        reportItems = new ArrayList<ClinicalPatientData>();
    }

    /**
     * If you have a string that you wish to add a suffix like units of measure,
     * use this.
     *
     * @param base something
     * @param plus something to add, if the above is not null or blank.
     * @return the two args put together, or the original if it was blank to
     * begin with.
     */
    protected String addIfNotEmpty(String base, String plus) {
        return (!GenericValidator.isBlankOrNull(plus)) ? base + " " + plus : base;
    }

    /**
     * Pushes all of the information about a patient, analysis, result and the
     * conclusion into a new reporting object
     *
     * @return  A single record
     */
    protected ClinicalPatientData reportAnalysisResults(Timestamp lastReportTime, boolean hasParent) {
        ClinicalPatientData data = new ClinicalPatientData();
        String testName = null;
        String sortOrder = "";
        String receivedDate = currentSampleService.getReceivedDateForDisplay();

        boolean doAnalysis = reportAnalysis != null;

        if (doAnalysis) {
            testName = getTestName(hasParent);
        }

        if (FormFields.getInstance().useField(Field.SampleEntryUseReceptionHour)) {
            receivedDate += " " + currentSampleService.getReceivedTimeForDisplay();
        }

        data.setContactInfo(currentContactInfo);
        data.setSiteInfo(currentSiteInfo);
        data.setReceivedDate(receivedDate);
        data.setDob(getPatientDOB());
        data.setAge(createReadableAge(data.getDob()));
        data.setGender(patientService.getGender());
        data.setNationalId(patientService.getNationalId());
        setPatientName(data);
        data.setDept(patientDept);
        data.setCommune(patientCommune);
        data.setStNumber(getLazyPatientIdentity(STNumber, ST_NUMBER_IDENTITY_TYPE_ID));
        data.setSubjectNumber(getLazyPatientIdentity(subjectNumber, SUBJECT_NUMBER_IDENTITY_TYPE_ID));
        data.setHealthRegion(getLazyPatientIdentity(healthRegion, HEALTH_REGION_IDENTITY_TYPE_ID));
        data.setHealthDistrict(getLazyPatientIdentity(healthDistrict, HEALTH_DISTRICT_IDENTITY_TYPE_ID));
        //Not sure if it is a bug in escapeHtml but the wrong markup is generated
        testName = StringEscapeUtils.escapeHtml(testName).replace("&mu", "&micro");
        data.setTestName(testName);
        data.setPatientSiteNumber(ObservationHistoryService.getValueForSample(ObservationType.REFERRERS_PATIENT_ID,
                currentSampleService.getId()));

        if (doAnalysis) {
            data.setPanel(reportAnalysis.getPanel());
            if (reportAnalysis.getPanel() != null) {
                data.setPanelName(reportAnalysis.getPanel().getPanelName());
            }
            data.setTestDate(DateUtil.convertSqlDateToStringDate(reportAnalysis.getCompletedDate()));
            sortOrder = reportAnalysis.getSampleItem().getSortOrder();
            data.setOrderFinishDate(completionDate);
            data.setOrderDate(DateUtil.convertSqlDateToStringDate(currentSampleService.getOrderedDate()));
            data.setCollectionDateTime(DateUtil
                    .convertTimestampToStringDateAndTime(reportAnalysis.getSampleItem().getCollectionDate()));
        }

        data.setAccessionNumber(currentSampleService.getAccessionNumber() + "-" + sortOrder);
        data.setLabOrderType(createLabOrderType());

        if (doAnalysis) {
            reportResultAndConclusion(data);
        }

        return data;
    }

    private String getTestName(boolean indent) {
        String testName;

        if (useReportingDescription()) {
            testName = TestService.getLocalizedReportingTestName(reportAnalysis.getTest());
        } else {
            testName = TestService.getLocalizedTestName(reportAnalysis.getTest());
        }

        if (GenericValidator.isBlankOrNull(testName)) {
            testName = TestService.getLocalizedTestName(reportAnalysis.getTest());
        }
        return (indent ? "    " : "") + testName;
    }

    private String createLabOrderType() {
        if (LAB_TYPE_OBSERVATION_ID == null) {
            return "";
        }

        List<ObservationHistory> primaryOrderTypes = observationDAO.getAll(patientService.getPatient(),
                currentSampleService.getSample(), LAB_TYPE_OBSERVATION_ID);
        if (primaryOrderTypes.isEmpty()) {
            return "";
        }

        LabOrderType primaryLabOrderType = labOrderTypeDAO
                .getLabOrderTypeByType(primaryOrderTypes.get(0).getValue());
        if (primaryLabOrderType == null) {
            return "";
        }

        if (LAB_SUBTYPE_OBSERVATION_ID == null) {
            return primaryLabOrderType.getLocalizedName();
        }

        List<ObservationHistory> subOrderTypes = observationDAO.getAll(patientService.getPatient(),
                currentSampleService.getSample(), LAB_SUBTYPE_OBSERVATION_ID);
        if (subOrderTypes.isEmpty()) {
            return primaryLabOrderType.getLocalizedName();
        } else {
            return primaryLabOrderType.getLocalizedName() + " : " + subOrderTypes.get(0).getValue();
        }

    }

    /**
     * Given a list of referralResults for a particular analysis, generated the
     * next displayable value made of from one or more of the values from the
     * list starting at the given index. It uses multiresult form the list when
     * the results are for the same test.
     *
     * @param referralResultsForReferral The referral
     * @param i                          starting index.
     * @return last index actually used. If you start with 2 and this routine
     * uses just item #2, then return result is 2, but if there are two
     * results for the same test (e.g. a multi-select result) and those
     * are in item item 2 and item 3 this routine returns #3.
     */
    protected int reportReferralResultValue(List<ReferralResult> referralResultsForReferral, int i) {
        ReferralResult referralResult = referralResultsForReferral.get(i);
        reportReferralResultValue = "";
        String currTestId = referralResult.getTestId();
        do {
            reportReferralResultValue += findDisplayableReportResult(referralResult.getResult()) + ", ";
            i++;
            if (i >= referralResultsForReferral.size()) {
                break;
            }
            referralResult = referralResultsForReferral.get(i);
        } while (currTestId.equals(referralResult.getTestId()));
        reportReferralResultValue = reportReferralResultValue.substring(0, reportReferralResultValue.length() - 2);
        i--;
        return i;
    }

    /**
     * Derive the appropriate displayable string results, either dictionary
     * result or direct value.
     *
     * @param result    The result
     * @return a reportable result string.
     */
    private String findDisplayableReportResult(Result result) {
        String reportResult = "";
        if (result == null) {
            return reportResult;
        }
        String type = result.getResultType();
        String value = result.getValue();
        if (value == null) {
            return reportResult;
        }
        if (ResultType.isDictionaryVariant(type)) {
            if (result.getValue() != null && !"null".equals(result.getValue())) {
                Dictionary dictionary = new Dictionary();
                dictionary.setId(result.getValue());
                dictionaryDAO.getData(dictionary);
                reportResult = dictionary.getId() != null ? dictionary.getLocalizedName() : "";
            }
        } else {
            reportResult = result.getValue();
        }
        return reportResult;
    }

    private String createReadableAge(String dob) {
        if (GenericValidator.isBlankOrNull(dob)) {
            return "";
        }

        dob = dob.replaceAll("xx", "01");
        Date dobDate = DateUtil.convertStringDateToSqlDate(dob);
        int months = DateUtil.getAgeInMonths(dobDate, DateUtil.getNowAsSqlDate());
        if (months > 35) {
            return (months / 12) + " A";
        } else if (months > 0) {
            return months + " M";
        } else {
            int days = DateUtil.getAgeInDays(dobDate, DateUtil.getNowAsSqlDate());
            return days + " J";
        }

    }

    @Override
    public List<String> getReportedOrders() {
        return handledOrders;
    }
}