oscar.oscarLab.ca.all.parsers.OLISHL7Handler.java Source code

Java tutorial

Introduction

Here is the source code for oscar.oscarLab.ca.all.parsers.OLISHL7Handler.java

Source

/**
 * Copyright (c) 2008-2012 Indivica Inc.
 *
 * This software is made available under the terms of the
 * GNU General Public License, Version 2, 1991 (GPLv2).
 * License details are available via "indivica.ca/gplv2"
 * and "gnu.org/licenses/gpl-2.0.html".
 */

/*
 * OLISHL7Handler.java
 */

package oscar.oscarLab.ca.all.parsers;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.bouncycastle.util.encoders.Base64;
import org.oscarehr.olis.dao.OLISRequestNomenclatureDao;
import org.oscarehr.olis.dao.OLISResultNomenclatureDao;
import org.oscarehr.olis.model.OLISRequestNomenclature;
import org.oscarehr.olis.model.OLISResultNomenclature;
import org.oscarehr.util.MiscUtils;
import org.oscarehr.util.SpringUtils;

import oscar.util.UtilDateUtilities;
import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.model.GenericComposite;
import ca.uhn.hl7v2.model.Message;
import ca.uhn.hl7v2.model.Segment;
import ca.uhn.hl7v2.model.Structure;
import ca.uhn.hl7v2.model.Type;
import ca.uhn.hl7v2.model.Varies;
import ca.uhn.hl7v2.parser.Parser;
import ca.uhn.hl7v2.parser.PipeParser;
import ca.uhn.hl7v2.util.Terser;
import ca.uhn.hl7v2.validation.impl.NoValidation;

/**
 * @author Adam Balanga
 */
public class OLISHL7Handler implements MessageHandler {

    Logger logger = Logger.getLogger(DefaultGenericHandler.class);
    protected boolean isFinal = true;
    protected boolean isCorrected = false;
    protected Message msg = null;
    protected Terser terser;
    protected ArrayList<ArrayList<Segment>> obrGroups = null;
    private ArrayList<String> obrSpecimenSource;
    private ArrayList<String> obrStatus;
    private HashMap<String, String> sourceOrganizations;

    private HashMap<String, String> defaultSourceOrganizations;

    private void initDefaultSourceOrganizations() {
        defaultSourceOrganizations = new HashMap<String, String>();
        defaultSourceOrganizations.put("4001", "BSD Lab1");
        defaultSourceOrganizations.put("4002", "BSD Lab2");
        defaultSourceOrganizations.put("4003", "BSD Lab3");
        defaultSourceOrganizations.put("4004", "BSD Lab4");
        defaultSourceOrganizations.put("4005", "BSD Lab5");
        defaultSourceOrganizations.put("4006", "BSD Lab6");
        defaultSourceOrganizations.put("4007", "BSD Lab7");
        defaultSourceOrganizations.put("4008", "BSD Lab8");
        defaultSourceOrganizations.put("4009", "BSD Lab9");
        defaultSourceOrganizations.put("4010", "BSD Lab10");
    }

    public String getSourceOrganization(String org) {
        return sourceOrganizations.containsKey(org) ? sourceOrganizations.get(org)
                : defaultSourceOrganizations.get(org);
    }

    public String getObrStatus(int index) {
        return obrStatus.get(index);
    }

    public String getObrSpecimenSource(int index) {
        return obrSpecimenSource.get(index);
    }

    private ArrayList<String> headers = null;

    /** Creates a new instance of OLISHL7Handler */
    public OLISHL7Handler() {
        super();
    }

    String[] getDentistLicenceNumber() {
        return patientIdentifiers.get("DDSL");
    }

    String[] getDriversLicenceNumber() {
        return patientIdentifiers.get("DL");
    }

    String[] getJurisdictionalHealthNumber() {
        return patientIdentifiers.get("JHN");
    }

    String[] getPhysicianLicenceNumber() {
        return patientIdentifiers.get("MDL");
    }

    String[] getMidwifeLicenceNumber() {
        return patientIdentifiers.get("ML");
    }

    String[] getMedicalRecordNumber() {
        return patientIdentifiers.get("MR");
    }

    String[] getNursePractitionerLicenceNumber() {
        return patientIdentifiers.get("NPL");
    }

    String[] getPassportNumber() {
        return patientIdentifiers.get("PPN");
    }

    String[] getUSASocialSecurityNumber() {
        return patientIdentifiers.get("SS");
    }

    public String[] getPatientIdentifier(String ident) {
        return patientIdentifiers.get(ident);
    }

    public Set<String> getPatientIdentifiers() {
        return patientIdentifiers.keySet();
    }

    public String getNameOfIdentifier(String ident) {
        return patientIdentifierNames.get(ident);
    }

    HashMap<String, String[]> patientIdentifiers;
    HashMap<String, String> patientIdentifierNames;

    private void initPatientIdentifierNames() {
        patientIdentifierNames.put("ANON", "Non Nominal Identifier");
        patientIdentifierNames.put("DDSL", "Dentist Licence Number");
        patientIdentifierNames.put("DL", "Driver's Licence Number");
        patientIdentifierNames.put("JHN", "Jurisdictional Health Number");
        patientIdentifierNames.put("MDL", "Physician Licence Number");
        patientIdentifierNames.put("ML", "Midwife Licence Number");
        patientIdentifierNames.put("MR", "Medical Record Number");
        patientIdentifierNames.put("NPL", "Nurse Practitioner Licence Number");
        patientIdentifierNames.put("PPN", "Passport Number");
        patientIdentifierNames.put("SS", "USA Social Security number");

    }

    private HashMap<String, String> addressTypeNames;
    private HashMap<String, String> telecomUseCode;
    private HashMap<String, String> telecomEquipType;

    public String getAddressTypeName(String ident) {
        return addressTypeNames.get(ident);
    }

    private void initAddressTypeNames() {
        addressTypeNames.put("M", "Mailing Address");
        addressTypeNames.put("B", "Business");
        addressTypeNames.put("O", "Office");
        addressTypeNames.put("H", "Home Address");
        addressTypeNames.put("E", "Emergency Contact");
    }

    private void initTelecomUseCodes() {
        telecomUseCode.put("PRN", "Primary Residence Number");
        telecomUseCode.put("ORN", "Other Residence Number");
        telecomUseCode.put("WPN", "Work Number");
        telecomUseCode.put("VHN", "Vacation Home Number");
        telecomUseCode.put("ASN", "Answering Service Number");
        telecomUseCode.put("EMR", "Emergency Number");
        telecomUseCode.put("NET", "Network (email) Address");
    }

    private void initTelecomEquipTypes() {
        telecomEquipType.put("PH", "Telephone");
        telecomEquipType.put("FX", "Fax");
        telecomEquipType.put("CP", "Cellular Phone");
        telecomEquipType.put("BP", "Beeper");
        telecomEquipType.put("Internet", "Internet Address");
    }

    private ArrayList<HashMap<String, String>> patientAddresses;

    public ArrayList<HashMap<String, String>> getPatientAddresses() {
        return patientAddresses;
    }

    private ArrayList<HashMap<String, String>> patientHomeTelecom;

    public ArrayList<HashMap<String, String>> getPatientHomeTelecom() {
        return patientHomeTelecom;
    }

    public ArrayList<HashMap<String, String>> getPatientWorkTelecom() {
        return patientWorkTelecom;
    }

    private ArrayList<HashMap<String, String>> patientWorkTelecom;

    public String getAdmittingProviderName() {
        try {
            return getFullDocName("/.PV1-17-");
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
            return "";
        }
    }

    public String getAdmittingProviderNameShort() {
        try {
            return getShortName("/.PV1-17-");
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
            return "";
        }
    }

    public String getAttendingProviderName() {
        try {
            return getFullDocName("/.PV1-7-");
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
            return "";
        }
    }

    public boolean reportBlocked = false;

    public boolean isReportBlocked() {
        return reportBlocked;
    }

    public boolean isOBRBlocked(int obr) {
        obr++;
        try {
            String indicator;
            Segment zbr = null;
            if (obr == 1) {
                zbr = terser.getSegment("/.ZBR");
            } else {
                zbr = (Segment) terser.getFinder().getRoot().get("ZBR" + obr);
            }
            indicator = Terser.get(zbr, 1, 0, 1, 1);
            return "Y".equals(indicator);

        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return false;
    }

    public String getOBRPerformingFacilityName(int obr) {
        obr++;
        try {
            String key = "", value = "", ident = "";
            Segment zbr = null;
            if (obr == 1) {
                zbr = terser.getSegment("/.ZBR");
            } else {
                zbr = (Segment) terser.getFinder().getRoot().get("ZBR" + obr);
            }
            key = getString(Terser.get(zbr, 6, 0, 6, 2));
            if (key != null && key.indexOf(":") > 0) {
                ident = key.substring(0, key.indexOf(":"));
                ident = getOrganizationType(ident);
                key = key.substring(key.indexOf(":") + 1);
            }
            if (key == null || "".equals(key.trim())) {
                return "";
            }
            value = getString(Terser.get(zbr, 6, 0, 1, 1));
            return String.format("%s (%s %s)", value, ident, key);

        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return "";
    }

    public HashMap<String, String> getPerformingFacilityAddress(int obr) {
        obr++;
        try {
            String value = "";
            Segment zbr = null;
            if (obr == 1) {
                zbr = terser.getSegment("/.ZBR");
            } else {
                zbr = (Segment) terser.getFinder().getRoot().get("ZBR" + obr);
            }
            HashMap<String, String> address;

            String identifier = getString(Terser.get(zbr, 7, 0, 7, 1));
            if ("".equals(identifier)) {
                return null;
            }
            address = new HashMap<String, String>();
            value = getString(Terser.get(zbr, 7, 0, 1, 1));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Street Address", value);
            }
            value = getString(Terser.get(zbr, 7, 0, 2, 1));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Other Designation", value);
            }
            value = getString(Terser.get(zbr, 7, 0, 3, 1));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("City", value);
            }
            value = getString(Terser.get(zbr, 7, 0, 4, 1));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Province", value);
            }
            value = getString(Terser.get(zbr, 7, 0, 5, 1));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Postal Code", value);
            }
            value = getString(Terser.get(zbr, 7, 0, 6, 1));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Country", value);
            }
            address.put("Address Type", addressTypeNames.get(identifier));
            return address;

        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return null;
    }

    public String getCategoryList() {
        String result = "";
        ArrayList<String> categories = new ArrayList<String>();
        for (int i = 0; i < getOBRCount(); i++) {
            categories.add(getOBRCategory(i));
        }
        String[] uniqueCategories = new HashSet<String>(categories).toArray(new String[0]);
        Arrays.sort(uniqueCategories);
        int count = 0;
        for (String category : uniqueCategories) {
            result += (count++ > 0 ? " / " : "") + category;
        }
        return result;
    }

    public String getTestList() {
        String result = "";
        String[] uniqueTests = new HashSet<String>(headers).toArray(new String[0]);
        Arrays.sort(uniqueTests);
        int count = 0;
        for (String test : uniqueTests) {
            result += (count++ > 0 ? " / " : "") + test;
        }
        return result;
    }

    public String getPerformingFacilityName() {
        try {
            String key = "", value = "", ident = "";
            key = getString(terser.get("/.ZBR-6-6-2"));
            if (key != null && key.indexOf(":") > 0) {
                ident = key.substring(0, key.indexOf(":"));
                ident = getOrganizationType(ident);
                key = key.substring(key.indexOf(":") + 1);
            } else {
                key = "";
            }
            if (key == null || key.trim().equals("")) {
                return "";
            }
            value = getString(terser.get("/.ZBR-6-1"));

            return String.format("%s (%s %s)", value, ident, key);
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return "";
    }

    public HashMap<String, String> getPerformingFacilityAddress() {
        try {
            String value;
            HashMap<String, String> address;
            String identifier = getString(terser.get("/.ZBR-7-7"));
            if ("".equals(identifier)) {
                return null;
            }
            address = new HashMap<String, String>();
            value = getString(terser.get("/.ZBR-7-1"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Street Address", value);
            }
            value = getString(terser.get("/.ZBR-7-2"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Other Designation", value);
            }
            value = getString(terser.get("/.ZBR-7-3"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("City", value);
            }
            value = getString(terser.get("/.ZBR-7-4"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Province", value);
            }
            value = getString(terser.get("/.ZBR-7-5"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Postal Code", value);
            }
            value = getString(terser.get("/.ZBR-7-6"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Country", value);
            }
            address.put("Address Type", addressTypeNames.get(identifier));
            return address;
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
            return null;
        }
    }

    public String getReportingFacilityName() {
        try {
            String key = "", value = "", ident = "";
            key = getString(terser.get("/.ZBR-4-6-2"));
            if (key != null && key.indexOf(":") > 0) {
                ident = key.substring(0, key.indexOf(":"));
                ident = getOrganizationType(ident);
                key = key.substring(key.indexOf(":") + 1);
            } else {
                key = "";
            }
            if (key == null || key.trim().equals("")) {
                return "";
            }
            value = getString(terser.get("/.ZBR-4-1"));
            return String.format("%s (%s %s)", value, ident, key);
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return "";
    }

    public HashMap<String, String> getReportingFacilityAddress() {
        try {
            String value;
            HashMap<String, String> address;
            String identifier = getString(terser.get("/.ZBR-5-7"));
            if ("".equals(identifier)) {
                return null;
            }
            address = new HashMap<String, String>();
            value = getString(terser.get("/.ZBR-5-1"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Street Address", value);
            }
            value = getString(terser.get("/.ZBR-5-2"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Other Designation", value);
            }
            value = getString(terser.get("/.ZBR-5-3"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("City", value);
            }
            value = getString(terser.get("/.ZBR-5-4"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Province", value);
            }
            value = getString(terser.get("/.ZBR-5-5"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Postal Code", value);
            }
            value = getString(terser.get("/.ZBR-5-6"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Country", value);
            }
            address.put("Address Type", addressTypeNames.get(identifier));
            return address;
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
            return null;
        }
    }

    public String getOrderingFacilityName() {
        try {
            return (getString(terser.get("/.ORC-21-1")));
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
            return "";
        }
    }

    public HashMap<String, String> getOrderingFacilityAddress() {
        try {
            String value;
            HashMap<String, String> address;
            String identifier = getString(terser.get("/.ORC-22-7"));
            if ("".equals(identifier)) {
                return null;
            }
            address = new HashMap<String, String>();
            value = getString(terser.get("/.ORC-22-1"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Street Address", value);
            }
            value = getString(terser.get("/.ORC-22-2"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Other Designation", value);
            }
            value = getString(terser.get("/.ORC-22-3"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("City", value);
            }
            value = getString(terser.get("/.ORC-22-4"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Province", value);
            }
            value = getString(terser.get("/.ORC-22-5"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Postal Code", value);
            }
            value = getString(terser.get("/.ORC-22-6"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Country", value);
            }
            address.put("Address Type", addressTypeNames.get(identifier));
            return address;
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
            return null;
        }
    }

    public String getOrderingProviderName() {
        try {
            return (getString(terser.get("/.ORC-21-1")));
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
            return "";
        }
    }

    public HashMap<String, String> getOrderingProviderAddress() {
        try {
            String value;
            HashMap<String, String> address;
            String identifier = getString(terser.get("/.ORC-24-7"));
            if ("".equals(identifier)) {
                return null;
            }
            address = new HashMap<String, String>();
            value = getString(terser.get("/.ORC-24-1"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Street Address", value);
            }
            value = getString(terser.get("/.ORC-24-2"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Other Designation", value);
            }
            value = getString(terser.get("/.ORC-24-3"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("City", value);
            }
            value = getString(terser.get("/.ORC-24-4"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Province", value);
            }
            value = getString(terser.get("/.ORC-24-5"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Postal Code", value);
            }
            value = getString(terser.get("/.ORC-24-6"));
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Country", value);
            }
            address.put("Address Type", addressTypeNames.get(identifier));
            return address;
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
            return null;
        }
    }

    private boolean stringIsNotNullOrEmpty(String value) {
        return value != null && value.trim().length() > 0;
    }

    public ArrayList<HashMap<String, String>> getOrderingProviderPhones() {
        ArrayList<HashMap<String, String>> results = new ArrayList<HashMap<String, String>>();
        try {
            int rep = -1;

            String value;
            HashMap<String, String> telecom;
            String identifier;
            while (!"".equals((identifier = getString(terser.get("/.OBR-17(" + (++rep) + ")-2"))))) {
                telecom = new HashMap<String, String>();
                value = getString(terser.get("/.OBR-17(" + (rep) + ")-1"));
                if (stringIsNotNullOrEmpty(value)) {
                    telecom.put("phoneNumber", value);
                }
                value = getString(terser.get("/.OBR-17(" + (rep) + ")-3"));
                if (stringIsNotNullOrEmpty(value)) {
                    value = telecomEquipType.get(value);
                    if (stringIsNotNullOrEmpty(value)) {
                        telecom.put("equipType", value);
                    }
                }
                value = getString(terser.get("/.OBR-17(" + (rep) + ")-4"));
                if (stringIsNotNullOrEmpty(value)) {
                    telecom.put("email", value);
                }
                value = getString(terser.get("/.OBR-17(" + (rep) + ")-5"));
                if (stringIsNotNullOrEmpty(value)) {
                    telecom.put("countryCode", value);
                }
                value = getString(terser.get("/.OBR-17(" + (rep) + ")-6"));
                if (stringIsNotNullOrEmpty(value)) {
                    telecom.put("areaCode", value);
                }
                value = getString(terser.get("/.OBR-17(" + (rep) + ")-7"));
                if (stringIsNotNullOrEmpty(value)) {
                    telecom.put("localNumber", value);
                }
                value = getString(terser.get("/.OBR-17(" + (rep) + ")-8"));
                if (stringIsNotNullOrEmpty(value)) {
                    telecom.put("extension", value);
                }
                telecom.put("useCode", telecomUseCode.get(identifier));
                results.add(telecom);
            }

            return results;
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
            return null;
        }
    }

    public String getSpecimenReceivedDateTime() {
        try {
            String date = getString(terser.get("/.OBR-14-1"));
            if (date.length() > 13) {
                return formatDateTime(date);
            }
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return "";
    }

    public String getOrderDate() {
        try {
            return (formatDate(getString(terser.get("/.OBR-27-4")).substring(0, 8)));
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
            return "";
        }
    }

    public String getLastUpdateInOLIS() {
        try {
            String date = getString(terser.get("/.OBR-22-1"));
            if (date.length() > 0)
                return formatDateTime(date);
            return "";
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
            return "";
        }
    }

    public String getOBXCEParentId(int obr, int obx) {
        return getOBXField(obr, obx, 4, 0, 1);
    }

    HashMap<String, String> obrParentMap;

    public int getChildOBR(String parentId) {
        try {
            return Integer.valueOf(obrParentMap.get(parentId));
        } catch (Exception e) {
            return -1;
        }
    }

    public boolean isChildOBR(int obr) {
        return obrParentMap.containsValue(String.valueOf(obr));
    }

    public String getDiagnosis(int obr) {
        try {
            return obrDiagnosis.containsKey(obr) ? getString(Terser.get(obrDiagnosis.get(obr), 3, 0, 2, 1)) : "";
        } catch (HL7Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return "";
    }

    public int getMappedOBR(int obr) {
        try {
            String[] keys = obrSortMap.keySet().toArray(new String[0]);
            Arrays.sort(keys);
            if (obr > keys.length - 1) {
                return obr;
            }
            return obrSortMap.get(keys[obr]);
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return obr;
    }

    public int getMappedOBX(int obr, int obx) {
        try {
            String[] keys = obxSortMap.get(obr).keySet().toArray(new String[0]);
            Arrays.sort(keys);
            return obxSortMap.get(obr).get(keys[obx]);
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return obr;
    }

    HashMap<Integer, Segment> obrDiagnosis;

    private ArrayList<String> disciplines;

    public ArrayList<String> getDisciplines() {
        return disciplines;
    }

    List<OLISError> errors;

    public List<OLISError> getReportErrors() {
        List<OLISError> result = new ArrayList<OLISError>();
        if (errors == null) {
            return result;
        }
        for (OLISError error : errors) {
            if (error.segment == null || error.segment.equals("") || error.segment.equals("ERR")
                    || error.segment.equals("SPR")) {
                result.add(error);
            }
        }
        return result;
    }

    @Override
    public void init(String hl7Body) throws HL7Exception {
        initDefaultSourceOrganizations();

        obrDiagnosis = new HashMap<Integer, Segment>();

        obrParentMap = new HashMap<String, String>();

        patientIdentifierNames = new HashMap<String, String>();
        initPatientIdentifierNames();

        addressTypeNames = new HashMap<String, String>();
        initAddressTypeNames();

        telecomUseCode = new HashMap<String, String>();
        initTelecomUseCodes();

        telecomEquipType = new HashMap<String, String>();
        initTelecomEquipTypes();

        sourceOrganizations = new HashMap<String, String>();
        obrSpecimenSource = new ArrayList<String>();
        obrStatus = new ArrayList<String>();
        Parser p = new PipeParser();

        p.setValidationContext(new NoValidation());
        // force parsing as a generic message by changing the message structure
        hl7Body = hl7Body.replaceAll("R01", "");
        msg = p.parse(hl7Body.replaceAll("\n", "\r\n"));
        headers = new ArrayList<String>();
        terser = new Terser(msg);
        int zbrNum = 1;
        int obrCount = getOBRCount();
        int obrNum = 1;
        boolean obrFlag;
        String segmentName;
        String[] segments = terser.getFinder().getRoot().getNames();
        obrGroups = new ArrayList<ArrayList<Segment>>();
        int k = 0;

        // We only need to parse a few segments if there are no OBRs.
        if (obrCount == 0) {
            for (; k < segments.length; k++) {
                segmentName = segments[k].substring(0, 3);
                if (segmentName.equals("ZPD")) {
                    parseZPDSegment();
                }
                if (segmentName.equals("ERR")) {
                    parseERRSegment();
                }
            }
            return;
        }
        for (int i = 0; i < obrCount; i++) {
            ArrayList<Segment> obxSegs = new ArrayList<Segment>();

            headers.add(getOBRName(i));
            obrNum = i + 1;
            obrFlag = false;
            for (; k < segments.length; k++) {
                try {
                    segmentName = segments[k].substring(0, 3);
                    if (segmentName.equals("ZPD")) {
                        parseZPDSegment();
                    }
                    if (segmentName.equals("ERR")) {
                        parseERRSegment();
                    }
                    if (segmentName.equals("PID")) {
                        parsePIDSegment();
                    } else if (segmentName.equals("ZBR")) {
                        parseZBRSegment(zbrNum++);
                    } else if (obrFlag && segmentName.equals("OBX")) {
                        Structure[] segs = terser.getFinder().getRoot().getAll(segments[k]);
                        for (int l = 0; l < segs.length; l++) {
                            Segment obxSeg = (Segment) segs[l];
                            obxSegs.add(obxSeg);
                        }

                    } else if (obrFlag && segmentName.equals("OBR")) {
                        break;
                    } else if (segments[k].equals("OBR" + obrNum) || (obrNum == 1 && segments[k].equals("OBR"))) {
                        obrFlag = true;
                        Segment obr = null;
                        if (obrNum == 1) {
                            obr = terser.getSegment("/.OBR");
                        } else {
                            obr = (Segment) terser.getFinder().getRoot().get("OBR" + obrNum);
                        }

                        String weirdFixToGetObr1512 = null;
                        Type obr15Types[] = obr.getField(15);
                        if (obr15Types != null && obr15Types.length > 0) {
                            Type obr15Type = obr.getField(15)[0];
                            if (obr15Type instanceof Varies) {
                                Type tt = ((Varies) obr15Type).getData();
                                if (tt instanceof GenericComposite) {
                                    Type comp = ((GenericComposite) tt).getComponent(1);
                                    if (comp instanceof Varies) {
                                        Type ttt = ((Varies) comp).getData();
                                        weirdFixToGetObr1512 = ttt.toString();
                                    }
                                }
                            }
                        }

                        String s1 = getString(Terser.get(obr, 15, 0, 1, 2)); // getString(terser.get("/.OBR-15-1-2"));
                        if (Terser.get(obr, 15, 0, 1, 2) == null && weirdFixToGetObr1512 != null) {
                            s1 = weirdFixToGetObr1512;
                        }
                        String s2 = getString(Terser.get(obr, 15, 0, 5, 2)); // getString(terser.get("/.OBR-15-5-2"));
                        String specimen = String.format("%s%s%s", s1, s1.equals("") || s2.equals("") ? "" : " ",
                                s2);
                        obrSpecimenSource.add(specimen);
                        char status = getString(Terser.get(obr, 25, 0, 1, 1)).charAt(0);
                        isFinal &= isStatusFinal(status);
                        isCorrected |= status == 'C';
                        obrStatus.add(getTestRequestStatusMessage(status));

                        String parent = getString(Terser.get(obr, 26, 0, 2, 1));
                        if (!"".equals(parent)) {
                            obrParentMap.put(parent, String.valueOf(obrNum));
                        }

                    } else if (segmentName.equals("DG1")) {
                        Structure[] segs = terser.getFinder().getRoot().getAll(segments[k]);
                        for (int l = 0; l < segs.length; l++) {
                            Segment dg1Seg = (Segment) segs[l];
                            obrDiagnosis.put(obrNum - 1, dg1Seg);
                        }
                    }
                } catch (Exception e) {
                    MiscUtils.getLogger().error("OLIS HL7 Error", e);
                }
            }
            obrGroups.add(obxSegs);
        }
        obxSortMap = new HashMap<Integer, HashMap<String, Integer>>();
        obrSortMap = new HashMap<String, Integer>();
        mapOBRSortKeys();

        disciplines = new ArrayList<String>();
        for (int i = 0; i < getOBRCount(); i++) {
            disciplines.add(getOBRCategory(i));
        }
    }

    private void parseZBRSegment(int zbrNum) {
        try {
            String key = "", value = "";
            Segment zbr = null;
            if (zbrNum == 1) {
                zbr = terser.getSegment("/.ZBR");
            } else {
                zbr = (Segment) terser.getFinder().getRoot().get("ZBR" + zbrNum);
            }
            int[] indexes = { 2, 3, 4, 6, 8 };
            for (int index : indexes) {
                if (getString(Terser.get(zbr, index, 0, 6, 2)).equals("")) {
                    continue;
                }
                key = getString(Terser.get(zbr, index, 0, 6, 2));
                if (key != null && key.indexOf(":") > 0) {
                    key = key.substring(key.indexOf(":") + 1);
                }
                value = getString(Terser.get(zbr, index, 0, 1, 1));
                sourceOrganizations.put(key, value);
            }
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
    }

    private void parsePIDSegment() throws HL7Exception {
        Segment pid = terser.getSegment("/.PID");
        int rep = -1;
        String identifier = "";
        String value = "";
        String attrib = "";

        patientIdentifiers = new HashMap<String, String[]>();
        while ((identifier = Terser.get(pid, 3, ++rep, 5, 1)) != null) {

            value = Terser.get(pid, 3, rep, 1, 1);

            attrib = Terser.get(pid, 3, rep, 4, 2);
            if (attrib != null) {
                attrib = attrib.substring(attrib.indexOf(":") + 1);
            }

            patientIdentifiers.put(identifier, new String[] { value, attrib });

        }
        patientAddresses = new ArrayList<HashMap<String, String>>();
        rep = -1;
        HashMap<String, String> address;
        while ((identifier = Terser.get(pid, 11, ++rep, 7, 1)) != null) {
            address = new HashMap<String, String>();
            value = Terser.get(pid, 11, rep, 1, 1);
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Street Address", value);
            }
            value = Terser.get(pid, 11, rep, 2, 1);
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Other Designation", value);
            }
            value = Terser.get(pid, 11, rep, 3, 1);
            if (stringIsNotNullOrEmpty(value)) {
                address.put("City", value);
            }
            value = Terser.get(pid, 11, rep, 4, 1);
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Province", value);
            }
            value = Terser.get(pid, 11, rep, 5, 1);
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Postal Code", value);
            }
            value = Terser.get(pid, 11, rep, 6, 1);
            if (stringIsNotNullOrEmpty(value)) {
                address.put("Country", value);
            }
            address.put("Address Type", addressTypeNames.get(identifier));
            patientAddresses.add(address);
        }

        patientHomeTelecom = new ArrayList<HashMap<String, String>>();
        rep = -1;
        HashMap<String, String> telecom;
        while ((identifier = Terser.get(pid, 13, ++rep, 2, 1)) != null) {
            telecom = new HashMap<String, String>();
            value = Terser.get(pid, 13, rep, 1, 1);
            if (stringIsNotNullOrEmpty(value)) {
                telecom.put("phoneNumber", value);
            }
            value = Terser.get(pid, 13, rep, 3, 1);
            if (stringIsNotNullOrEmpty(value)) {
                value = telecomEquipType.get(value);
                if (stringIsNotNullOrEmpty(value)) {
                    telecom.put("equipType", value);
                }
            }
            value = Terser.get(pid, 13, rep, 4, 1);
            if (stringIsNotNullOrEmpty(value)) {
                telecom.put("email", value);
            }
            value = Terser.get(pid, 13, rep, 5, 1);
            if (stringIsNotNullOrEmpty(value)) {
                telecom.put("countryCode", value);
            }
            value = Terser.get(pid, 13, rep, 6, 1);
            if (stringIsNotNullOrEmpty(value)) {
                telecom.put("areaCode", value);
            }
            value = Terser.get(pid, 13, rep, 7, 1);
            if (stringIsNotNullOrEmpty(value)) {
                telecom.put("localNumber", value);
            }
            value = Terser.get(pid, 13, rep, 8, 1);
            if (stringIsNotNullOrEmpty(value)) {
                telecom.put("extension", value);
            }
            telecom.put("useCode", telecomUseCode.get(identifier));
            patientHomeTelecom.add(telecom);
        }

        patientWorkTelecom = new ArrayList<HashMap<String, String>>();
        rep = -1;
        while ((identifier = Terser.get(pid, 14, ++rep, 2, 1)) != null) {
            telecom = new HashMap<String, String>();
            value = Terser.get(pid, 14, rep, 1, 1);
            if (stringIsNotNullOrEmpty(value)) {
                telecom.put("phoneNumber", value);
            }
            value = Terser.get(pid, 14, rep, 3, 1);
            if (stringIsNotNullOrEmpty(value)) {
                value = telecomEquipType.get(value);
                if (stringIsNotNullOrEmpty(value)) {
                    telecom.put("equipType", value);
                }
            }
            value = Terser.get(pid, 14, rep, 4, 1);
            if (stringIsNotNullOrEmpty(value)) {
                telecom.put("email", value);
            }
            value = Terser.get(pid, 14, rep, 5, 1);
            if (stringIsNotNullOrEmpty(value)) {
                telecom.put("countryCode", value);
            }
            value = Terser.get(pid, 14, rep, 6, 1);
            if (stringIsNotNullOrEmpty(value)) {
                telecom.put("areaCode", value);
            }
            value = Terser.get(pid, 14, rep, 7, 1);
            if (stringIsNotNullOrEmpty(value)) {
                telecom.put("localNumber", value);
            }
            value = Terser.get(pid, 14, rep, 8, 1);
            if (stringIsNotNullOrEmpty(value)) {
                telecom.put("extension", value);
            }
            telecom.put("useCode", telecomUseCode.get(identifier));
            patientWorkTelecom.add(telecom);
        }
    }

    private void parseZPDSegment() throws HL7Exception {
        Segment zpd = terser.getSegment("/.ZPD");
        boolean rb = "Y".equals(oscar.Misc.getStr(Terser.get(zpd, 3, 0, 1, 1), ""));
        if (!reportBlocked && rb) {
            reportBlocked = true;
        }
    }

    private void parseERRSegment() throws HL7Exception {
        Segment err = terser.getSegment("/.ERR");
        errors = new ArrayList<OLISError>();
        String segment, sequence, field, identifier, text;
        int rep = -1;
        while ((identifier = Terser.get(err, 1, ++rep, 4, 1)) != null) {
            if (identifier.trim().equals("320")) {
                reportBlocked = true;
            }
            segment = Terser.get(err, 1, rep, 1, 1);
            sequence = Terser.get(err, 1, rep, 1, 2);
            field = Terser.get(err, 1, rep, 1, 3);
            text = Terser.get(err, 1, rep, 4, 2);
            errors.add(new OLISError(segment, sequence, field, identifier, text));
        }
    }

    HashMap<String, Integer> obrSortMap;

    private void mapOBRSortKeys() {

        int obrCount = getOBRCount();
        Segment zbr;
        String tempKey;
        try {
            for (int i = 0; i < obrCount; i++) {
                mapOBXSortKey(i);
                if (i == 0) {
                    zbr = terser.getSegment("/.ZBR");
                } else {
                    zbr = (Segment) terser.getFinder().getRoot().get("ZBR" + (i + 1));
                }
                try {
                    tempKey = getString(Terser.get(zbr, 11, 0, 1, 1));
                    tempKey = tempKey.equals("") ? String.valueOf(i) : tempKey;
                    if (obrSortMap.containsKey(tempKey)) {
                        tempKey = tempKey + i;
                    }
                    obrSortMap.put(tempKey, i);
                } catch (Exception e) {
                    MiscUtils.getLogger().error("OLIS HL7 Error", e);
                }
            }
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
    }

    HashMap<Integer, HashMap<String, Integer>> obxSortMap;

    private void mapOBXSortKey(int obr) {
        HashMap<String, Integer> obxMap = null;
        int k;
        String tempKey;
        obxMap = new HashMap<String, Integer>();
        for (int i = 0; i < getOBXCount(obr); i++) {

            try {
                k = getZBXLocation(obr, i);
                String[] segments = terser.getFinder().getRoot().getNames();
                if (!segments[k].startsWith("ZBX")) {
                    continue;
                }
                Structure[] zbxSegs = terser.getFinder().getRoot().getAll(segments[k]);
                Segment zbxSeg = (Segment) zbxSegs[0];
                tempKey = getString(Terser.get(zbxSeg, 2, 0, 1, 1));
                obxMap.put(tempKey.equals("") ? String.valueOf(i) : tempKey, i);

            } catch (Exception e) {
                MiscUtils.getLogger().error("OLIS HL7 Error", e);
            }
        }
        obxSortMap.put(obr, obxMap);
    }

    private int getZBXLocation(int i, int j) {

        int obrCount = 0;
        int obxCount = 0;
        // Compensating for -1 parameters for OBR and OBX
        j++;
        i++;
        String[] segments = terser.getFinder().getRoot().getNames();

        String segId = "";
        for (int k = 0; k != segments.length && obxCount <= j && obrCount <= i; k++) {
            segId = segments[k].substring(0, 3);

            // We count all OBRs we see.
            if (segId.equals("OBR")) {
                obrCount++;
            }

            // We count only OBX's for the desired OBR
            else if (segId.equals("OBX") && obrCount == i) {
                obxCount++;
            }

            // Check that this segment is an NTE and we are in the right OBR/OBX position.
            else if (segId.equals("ZBX") && obxCount == j && obrCount == i) {
                return k;
            }
        }
        return segments.length - 1;
    }

    private String finalStatus = "CFEX";

    public boolean isStatusFinal(char status) {
        return finalStatus.contains(String.valueOf(status));
    }

    public String getNatureOfAbnormalTest(int obr, int obx) {
        String nature = getString(getOBXField(obr, obx, 10, 0, 1));
        return stringIsNotNullOrEmpty(nature) ? getNatureOfAbnormalTest(nature.charAt(0)) : "";
    }

    public String getNatureOfAbnormalTest(char nature) {
        switch (nature) {
        case 'A':
            return "An age-based population";
        case 'N':
            return "None  generic normal range";
        case 'R':
            return "A race-based population";
        case 'S':
            return "A sex-based population";
        default:
            return "";
        }
    }

    public String getTestResultStatusMessage(char status) {
        switch (status) {
        case 'C':
            return "Amended";
        case 'F':
            return "Final";
        case 'P':
            return "Preliminary";
        case 'X':
            return "Could not obtain results";
        case 'W':
            return "Invalid";
        case 'Z':
            return "Ancillary information";
        case 'N':
            return "Not performed";
        default:
            return "";
        }
    }

    public String getTestRequestStatusMessage(char status) {
        switch (status) {
        case 'A':
            return "Some, but not all, results available";
        case 'C':
            return "Correction to results";
        case 'E':
            return "OLIS has expired the test request because no activity has occurred within a reasonable amount of time.";
        case 'F':
            return "Final results; results stored and verified. Can only be changed with a corrected result.";
        case 'I':
            return "No results available; specimen received, procedure incomplete.";
        case 'O':
            return "Order received; specimen not yet received. ";
        case 'P':
            return "Preliminary: A verified early result is available, final results not yet obtained.";
        case 'X':
            return "No results available; Order canceled";
        default:
            return "";
        }
    }

    public String getPointOfCare(int i) {
        i++;
        try {
            Segment obr = null;
            if (i == 1) {
                obr = terser.getSegment("/.OBR");
            } else {
                obr = (Segment) terser.getFinder().getRoot().get("OBR" + i);
            }
            return getString(Terser.get(obr, 30, 0, 1, 1));
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return "";
    }

    @Override
    public String getMsgType() {
        return (null);
    }

    @Override
    public String getMsgDate() {

        try {
            String date = getString(terser.get("/.MSH-7-1"));
            String dateString = formatDateTime(date);
            return dateString.substring(0, 19);
        } catch (Exception e) {
            return ("");
        }

    }

    @Override
    public String getRequestDate(int i) {
        return getOrderDate();
    }

    @SuppressWarnings("unused")
    public void processEncapsulatedData(HttpServletRequest request, HttpServletResponse response, int obr,
            int obx) {
        getOBXField(obr, obx, 5, 0, 2);
        String subtype = getOBXField(obr, obx, 5, 0, 3);
        String data = getOBXEDField(obr, obx, 5, 0, 5);
        try {
            if (subtype.equals("PDF")) {
                response.setContentType("application/pdf");
                response.setHeader("Content-Disposition", "attachment; filename=\""
                        + getAccessionNum().replaceAll("\\s", "_") + "_" + obr + "-" + obx + "_Document.pdf\"");
            } else if (subtype.equals("JPEG")) {
                response.setContentType("image/jpeg");
                response.setHeader("Content-Disposition", "attachment; filename=\""
                        + getAccessionNum().replaceAll("\\s", "_") + "_" + obr + "-" + obx + "_Image.jpg\"");
            } else if (subtype.equals("GIF")) {
                response.setContentType("image/gif");
                response.setHeader("Content-Disposition", "attachment; filename=\""
                        + getAccessionNum().replaceAll("\\s", "_") + "_" + obr + "-" + obx + "_Image.gif\"");
            } else if (subtype.equals("RTF")) {
                response.setContentType("application/gif");
                response.setHeader("Content-Disposition", "attachment; filename=\""
                        + getAccessionNum().replaceAll("\\s", "_") + "_" + obr + "-" + obx + "_Document.rtf\"");
            } else if (subtype.equals("HTML")) {
                response.setContentType("text/html");
                response.setHeader("Content-Disposition", "attachment; filename=\""
                        + getAccessionNum().replaceAll("\\s", "_") + "_" + obr + "-" + obx + "_Document.html\"");
            } else if (subtype.equals("RTF")) {
                response.setContentType("text/plain");
                response.setHeader("Content-Disposition", "attachment; filename=\""
                        + getAccessionNum().replaceAll("\\s", "_") + "_" + obr + "-" + obx + "_Document.xml\"");
            }

            byte[] buf = Base64.decode(data);
            /*
            int pos = 0;
            int read;
            while (pos < buf.length) {
               read = buf.length - pos > 1024 ? 1024 : buf.length - pos;
               response.getOutputStream().write(buf, pos, read);
               pos += read;
            }
            */
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            baos.write(buf, 0, buf.length);
            baos.writeTo(response.getOutputStream());

        } catch (IOException e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
    }

    public String getCollectorsComment(int i) {
        String comment;
        i++;
        try {
            if (i == 1) {
                comment = getString(terser.get("/.OBR-39-2"));
            } else {
                Segment obrSeg = (Segment) terser.getFinder().getRoot().get("OBR" + i);
                comment = getString(Terser.get(obrSeg, 39, 0, 2, 1));
            }
            return comment;

        } catch (Exception e) {
            return ("");
        }

    }

    public String getCollectorsCommentSourceOrganization(int i) {
        String ident;
        String id;
        i++;
        try {
            if (i == 1) {
                id = getString(terser.get("/.ZBR-3-6-2"));
                ident = getString(terser.get("/.ZBR-3-1"));

            } else {
                Segment zbrSeg = (Segment) terser.getFinder().getRoot().get("ZBR" + i);
                ident = getString(Terser.get(zbrSeg, 3, 0, 1, 1));
                id = getString(Terser.get(zbrSeg, 3, 0, 6, 2));
            }
            if (id != null && id.trim().length() > 0) {
                id = id.substring(id.indexOf(":") + 1);
            }
            return ident + " (" + id + ")";

        } catch (Exception e) {
            return ("");
        }

    }

    @Override
    public String getMsgPriority() {
        // TODO: Check if need implementation
        return ("");
    }

    /**
     * Methods to get information about the Observation Request
     */
    @Override
    public int getOBRCount() {

        if (obrGroups != null) {
            return (obrGroups.size());
        } else {
            int i = 1;
            // String test;
            Segment test;
            try {

                test = terser.getSegment("/.OBR");
                while (test != null) {
                    i++;
                    test = (Segment) terser.getFinder().getRoot().get("OBR" + i);
                }

            } catch (Exception e) {
                // ignore exceptions
            }

            return (i - 1);
        }
    }

    @Override
    public String getOBRName(int i) {

        String obrName;
        i++;
        try {
            if (i == 1) {

                obrName = getString(terser.get("/.OBR-4-2"));
                if (obrName.equals(""))
                    obrName = getString(terser.get("/.OBR-4-1"));

            } else {
                Segment obrSeg = (Segment) terser.getFinder().getRoot().get("OBR" + i);
                obrName = getString(Terser.get(obrSeg, 4, 0, 2, 1));
                if (obrName.equals(""))
                    obrName = getString(Terser.get(obrSeg, 4, 0, 1, 1));

            }

            return (obrName);

        } catch (Exception e) {
            return ("");
        }
    }

    @Override
    public String getTimeStamp(int i, int j) {
        String timeStamp;
        i++;
        try {
            if (i == 1) {
                timeStamp = formatDateTime(getString(terser.get("/.OBR-7-1")));
            } else {
                Segment obrSeg = (Segment) terser.getFinder().getRoot().get("OBR" + i);
                timeStamp = formatDateTime(getString(Terser.get(obrSeg, 7, 0, 1, 1)));
            }
            return (timeStamp);
        } catch (Exception e) {
            return ("");
        }
    }

    @Override
    public boolean isOBXAbnormal(int i, int j) {
        String abnormalFlag = getOBXAbnormalFlag(i, j);
        if (abnormalFlag.equals("") || abnormalFlag.equals("N"))
            return (false);
        else
            return (true);
    }

    @Override
    public String getOBXAbnormalFlag(int i, int j) {
        return (getOBXField(i, j, 8, 0, 1));
    }

    @Override
    public String getObservationHeader(int i, int j) {

        return getOBRName(i);
        // stored in different places for different messages
        // return("");

    }

    @Override
    public int getOBXCount(int i) {
        try {
            ArrayList<Segment> obxSegs = obrGroups.get(i);
            return (obxSegs.size());
        } catch (Exception e) {
            return 0;
        }
    }

    @Override
    public String getOBXValueType(int i, int j) {
        return (getOBXField(i, j, 2, 0, 1));
    }

    @Override
    public String getOBXIdentifier(int i, int j) {
        return (getOBXField(i, j, 3, 0, 1));
    }

    public String getOBXObservationMethod(int i, int j) {
        return getOBXField(i, j, 17, 0, 2);
    }

    public String getOBXObservationDate(int i, int j) {
        try {
            String date = getOBXField(i, j, 14, 0, 1);
            if (date == null || date.trim().length() == 0) {
                return "";
            }
            return formatDateTime(date);
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
            return "";
        }
    }

    public String getOBRCategory(int i) {
        i++;
        try {
            Segment obr = null;
            if (i == 1) {
                obr = terser.getSegment("/.OBR");
            } else {
                obr = (Segment) terser.getFinder().getRoot().get("OBR" + i);
            }

            String obxCategory = Terser.get(obr, 4, 0, 1, 1);
            OLISRequestNomenclatureDao requestDao = (OLISRequestNomenclatureDao) SpringUtils
                    .getBean("OLISRequestNomenclatureDao");
            OLISRequestNomenclature requestNomenclature = requestDao.findByNameId(obxCategory);
            return StringUtils.trimToEmpty(requestNomenclature.getCategory());
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return "";
    }

    @Override
    public String getOBXName(int i, int j) {
        String obxName = getOBXField(i, j, 3, 0, 1);

        try {
            OLISResultNomenclatureDao resultDao = (OLISResultNomenclatureDao) SpringUtils
                    .getBean("OLISResultNomenclatureDao");
            OLISResultNomenclature resultNomenclature = resultDao.findByNameId(obxName);
            return StringUtils.trimToEmpty(resultNomenclature.getName());
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        // If we're unable to find a LOINC match for the identifier then try to parse out the obx name.
        obxName = getOBXField(i, j, 3, 0, 2);
        return "".equals(obxName) ? " "
                : obxName.indexOf(":") == -1 ? obxName : obxName.substring(0, obxName.indexOf(":"));
    }

    public String getOBXCEName(int i, int j) {
        return getOBXField(i, j, 5, 0, 2);
    }

    public boolean renderAsFT(int i, int j) {
        String obxIdent = getOBXField(i, j, 3, 0, 2).split(":")[4];
        return obxIdent != null && obxIdent.toUpperCase().startsWith("NAR");
    }

    public boolean renderAsNM(int i, int j) {
        String obxIdent = getOBXField(i, j, 3, 0, 2).split(":")[4];
        return obxIdent != null
                && (obxIdent.toUpperCase().startsWith("ORD") || obxIdent.toUpperCase().startsWith("QN"));
    }

    public boolean isAncillary(int i, int j) {
        String obxIdent = getOBXField(i, j, 3, 0, 3);
        return obxIdent != null && (obxIdent.toUpperCase().startsWith("LN"));
    }

    public String getOBXCESensitivity(int i, int j) {
        return (getOBXField(i, j, 5, 0, 1));
    }

    @Override
    public String getOBXResult(int i, int j) {
        return (getOBXField(i, j, 5, 0, 1));
    }

    public String getOBXTSResult(int i, int j) {
        String date = getOBXField(i, j, 5, 0, 1);
        return formatDateTime(date);
    }

    public String getOBXDTResult(int i, int j) {
        String date = getOBXField(i, j, 5, 0, 1);
        return formatDate(date);
    }

    public String getOBXTMResult(int i, int j) {
        String date = getOBXField(i, j, 5, 0, 1);
        return formatTime(date);
    }

    public String getOBXSNResult(int i, int j) {
        return getOBXField(i, j, 5, 0, 1) + getOBXField(i, j, 5, 0, 2);
    }

    @Override
    public String getOBXReferenceRange(int i, int j) {
        return (getOBXField(i, j, 7, 0, 1));
    }

    @Override
    public String getOBXUnits(int i, int j) {
        return (getOBXField(i, j, 6, 0, 1));
    }

    @Override
    public String getOBXResultStatus(int i, int j) {
        return (getOBXField(i, j, 11, 0, 1));
    }

    @Override
    public int getOBXFinalResultCount() {
        int obrCount = getOBRCount();
        int obxCount;
        int count = 0;
        String status;
        for (int i = 0; i < obrCount; i++) {
            obxCount = getOBXCount(i);
            for (int j = 0; j < obxCount; j++) {
                status = getOBXResultStatus(i, j);
                if (status.startsWith("F") || status.startsWith("f"))
                    count++;
            }
        }
        return count;
    }

    /**
     * Retrieve the possible segment headers from the OBX fields
     */
    @Override
    public ArrayList<String> getHeaders() {
        return this.headers;
    }

    /**
     * Methods to get information from observation notes
     */
    @Override
    public int getOBRCommentCount(int i) {

        try {
            String[] segments = terser.getFinder().getRoot().getNames();
            int k = getNTELocation(i, -1);
            int count = 0;

            // make sure to count all the nte segments in the group
            if (k < segments.length && segments[k].substring(0, 3).equals("NTE")) {
                count++;
                ++k;
                while ((k = indexOfNextNTE(segments, k)) != -1) {
                    count++;
                    k++;
                }
            }

            return (count);
        } catch (Exception e) {
            logger.error("OBR Comment count error", e);

            return (0);
        }

    }

    @Override
    public String getOBRComment(int i, int j) {

        try {
            String[] segments = terser.getFinder().getRoot().getNames();
            int k = getNTELocation(i, -1);
            if (j > 0) {
                k = indexOfNextNTE(segments, k + 1, j);
            }
            Structure[] nteSegs = terser.getFinder().getRoot().getAll(segments[k]);
            Segment nteSeg = (Segment) nteSegs[0];
            return formatString(getString(Terser.get(nteSeg, 3, 0, 1, 1)));

        } catch (Exception e) {
            logger.error("Could not retrieve OBR comments", e);

            return ("");
        }
    }

    public String getOBRSourceOrganization(int i, int j) {
        try {
            String[] segments = terser.getFinder().getRoot().getNames();
            int k = getNTELocation(i, -1);
            if (j > 0) {
                k = indexOfNextNTE(segments, k + 1, j);
            }
            k++;
            Structure[] ZNTSegs = terser.getFinder().getRoot().getAll(segments[k]);
            Segment ZNTSeg = (Segment) ZNTSegs[0];
            String key = Terser.get(ZNTSeg, 1, 0, 2, 1);
            if (key == null || key.indexOf(":") == -1) {
                return "";
            }
            String ident = key.substring(0, key.indexOf(":"));
            ident = getOrganizationType(ident);
            key = key.substring(key.indexOf(":") + 1);
            return sourceOrganizations.get(key) + " (" + ident + " " + key + ")";

        } catch (Exception e) {
            logger.error("Could not retrieve OBX comment ZNT", e);

            return ("");
        }
    }

    public String getCollectionDateTime(int obrIndex) {
        obrIndex++;
        Segment obr;

        try {
            if (obrIndex == 1) {
                obr = terser.getSegment("/.OBR");
            } else {
                obr = (Segment) terser.getFinder().getRoot().get("OBR" + obrIndex);
            }
            String from = getString(Terser.get(obr, 7, 0, 1, 1));
            if (from.length() > 13) {
                from = formatDateTime(from);
            }
            String to = getString(Terser.get(obr, 8, 0, 1, 1));
            if (to.length() > 13) {
                to = formatDateTime(to);
            }
            boolean hasBoth = stringIsNotNullOrEmpty(from) && stringIsNotNullOrEmpty(to);
            return String.format("%s %s %s", from, hasBoth ? "-" : "", to);
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return "";
    }

    public String getOrganizationType(String ident) {
        if (ident.equals("2.16.840.1.113883.3.59.1")) {
            return "Lab";
        }
        if (ident.equals("2.16.840.1.113883.3.59.2")) {
            return "SCC";
        }
        if (ident.equals("2.16.840.1.113883.3.59.3")) {
            return "Hospital";
        }
        return "";
    }

    public String getSpecimenCollectedBy(int obr) {
        try {
            obr++;
            String key = "", value = "", ident = "";
            Segment zbr = null;
            if (obr == 1) {
                zbr = terser.getSegment("/.ZBR");
            } else {
                zbr = (Segment) terser.getFinder().getRoot().get("ZBR" + obr);
            }
            key = getString(Terser.get(zbr, 3, 0, 6, 2));
            if (key != null && key.indexOf(":") > 0) {
                ident = key.substring(0, key.indexOf(":"));
                ident = getOrganizationType(ident);
                key = key.substring(key.indexOf(":") + 1);
            }
            if (key == null || key.trim().equals("")) {
                return "";
            }
            value = getString(Terser.get(zbr, 3, 0, 1, 1));
            return String.format("%s (%s %s)", value, ident, key);
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return "";
    }

    public String getCollectionVolume(int obrIndex) {
        obrIndex++;
        Segment obr;

        try {
            if (obrIndex == 1) {
                obr = terser.getSegment("/.OBR");
            } else {
                obr = (Segment) terser.getFinder().getRoot().get("OBR" + obrIndex);
            }
            String volume = getString(Terser.get(obr, 9, 0, 1, 1));
            String units = getString(Terser.get(obr, 9, 0, 2, 1));
            return volume + " " + units;
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return "";
    }

    public String getNoOfSampleContainers(int obrIndex) {
        obrIndex++;
        Segment obr;

        try {
            if (obrIndex == 1) {
                obr = terser.getSegment("/.OBR");
            } else {
                obr = (Segment) terser.getFinder().getRoot().get("OBR" + obrIndex);
            }
            String count = getString(Terser.get(obr, 37, 0, 1, 1));

            return count;
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return "";
    }

    /**
     * Methods to get information from observation notes
     */
    public int getReportCommentCount() {

        try {
            String[] segments = terser.getFinder().getRoot().getNames();
            int k = getNTELocation(-1, -1);
            int count = 0;

            // make sure to count all the nte segments in the group
            if (k < segments.length && segments[k].substring(0, 3).equals("NTE")) {
                count++;
                ++k;
                while ((k = indexOfNextNTE(segments, k)) != -1) {
                    count++;
                    k++;
                }
            }

            return (count);
        } catch (Exception e) {
            logger.error("OBR Comment count error", e);

            return (0);
        }

    }

    public String getReportComment(int j) {

        try {
            String[] segments = terser.getFinder().getRoot().getNames();
            int k = getNTELocation(-1, -1);
            if (j > 0) {
                k = indexOfNextNTE(segments, k + 1, j);
            }
            Structure[] nteSegs = terser.getFinder().getRoot().getAll(segments[k]);
            Segment nteSeg = (Segment) nteSegs[0];
            return formatString(getString(Terser.get(nteSeg, 3, 0, 1, 1)));

        } catch (Exception e) {
            logger.error("Could not retrieve OBR comments", e);

            return ("");
        }
    }

    public String getReportSourceOrganization(int j) {
        try {
            String[] segments = terser.getFinder().getRoot().getNames();
            int k = getNTELocation(-1, -1);
            if (j > 0) {
                k = indexOfNextNTE(segments, k + 1, j);
            }
            k++;
            Structure[] ZNTSegs = terser.getFinder().getRoot().getAll(segments[k]);
            Segment ZNTSeg = (Segment) ZNTSegs[0];
            String key = Terser.get(ZNTSeg, 1, 0, 2, 1);
            if (key == null || key.indexOf(":") == -1) {
                return "";
            }
            String ident = key.substring(0, key.indexOf(":"));
            ident = getOrganizationType(ident);
            key = key.substring(key.indexOf(":") + 1);
            return String.format("%s (%s %s)", sourceOrganizations.get(key), ident, key);
        } catch (Exception e) {
            logger.error("Could not retrieve OBX comment ZNT", e);

            return ("");
        }
    }

    public int indexOfNextNTE(String[] segments, int pos) {
        return indexOfNextNTE(segments, pos, 1);
    }

    public int indexOfNextNTE(String[] segments, int pos, int skip) {
        String segId = "";
        int count = 0;
        while (pos < segments.length) {
            segId = segments[pos].substring(0, 3);
            if (segId.equals("OBR")) {
                break;
            }
            if (segId.equals("OBX")) {
                break;
            }
            if (segId.equals("NTE")) {
                count++;
                if (count >= skip) {
                    return pos;
                }
            }
            pos++;
        }
        return -1;
    }

    /**
     * Methods to get information from observation notes
     */
    @Override
    public int getOBXCommentCount(int i, int j) {
        // jth obx of the ith obr

        try {

            String[] segments = terser.getFinder().getRoot().getNames();
            int k = getNTELocation(i, j);

            int count = 0;
            if (k < segments.length && segments[k].substring(0, 3).equals("NTE")) {
                count++;
                ++k;
                while ((k = indexOfNextNTE(segments, k)) != -1) {
                    count++;
                    k++;
                }
            }

            return (count);
        } catch (Exception e) {
            logger.error("OBR Comment count error", e);

            return (0);
        }

    }

    @Override
    public String getOBXComment(int i, int j, int nteNum) {
        try {
            String[] segments = terser.getFinder().getRoot().getNames();
            int k = getNTELocation(i, j);
            if (nteNum > 0) {
                k = indexOfNextNTE(segments, k, nteNum + 1);
            }
            Structure[] nteSegs = terser.getFinder().getRoot().getAll(segments[k]);
            Segment nteSeg = (Segment) nteSegs[0];
            return formatString(getString(Terser.get(nteSeg, 3, 0, 1, 1))).replace(" ", "&nbsp;");

        } catch (Exception e) {
            logger.error("Could not retrieve OBX comments", e);

            return ("");
        }
    }

    public String getOBXSourceOrganization(int i, int j, int nteNum) {
        try {
            String[] segments = terser.getFinder().getRoot().getNames();
            int k = getNTELocation(i, j);
            if (nteNum > 0) {
                k = indexOfNextNTE(segments, k, nteNum + 1);
            }
            k++;
            Structure[] ZNTSegs = terser.getFinder().getRoot().getAll(segments[k]);
            Segment ZNTSeg = (Segment) ZNTSegs[0];
            String key = Terser.get(ZNTSeg, 1, 0, 2, 1);
            if (key == null || key.indexOf(":") == -1) {
                return "";
            }
            String ident = key.substring(0, key.indexOf(":"));
            ident = getOrganizationType(ident);
            key = key.substring(key.indexOf(":") + 1);
            return String.format("%s (%s %s)", sourceOrganizations.get(key), ident, key);

        } catch (Exception e) {
            logger.error("Could not retrieve OBX comment ZNT", e);

            return ("");
        }
    }

    /*
     * Patient Name 1 Last Name 2 First Name 3 Second Name 4 Suffix (e.g., JR or III) 5 Prefix (e.g., DR) 6 Degree 7 Name Type Code
     */

    public String parseFullNameFromSegment(String ident) {
        String name = "";
        String temp = null;

        // get name prefix ie/ DR.
        try {
            temp = terser.get(ident + "5");
        } catch (HL7Exception e) {
            // TODO Auto-generated catch block
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        if (temp != null) {
            name = temp;
        }

        // get the name
        try {
            temp = terser.get(ident + "2");
        } catch (HL7Exception e) {
            temp = null;
        }
        if (temp != null) {
            if (name.equals("")) {
                name = temp;
            } else {
                name = name + " " + temp;
            }
        }
        try {
            if (terser.get(ident + "3") != null)
                name = name + " " + terser.get(ident + "3");
        } catch (HL7Exception e) {
            name = null;
        }
        try {
            if (terser.get(ident + "1") != null)
                name = name + " " + terser.get(ident + "1");
        } catch (HL7Exception e) {
            temp = null;
        }
        try {
            if (terser.get(ident + "4") != null)
                name = name + " " + terser.get(ident + "4");
        } catch (HL7Exception e) {
            temp = null;
        }
        try {
            if (terser.get(ident + "6") != null)
                name = name + " " + terser.get(ident + "6");
        } catch (HL7Exception e) {
            temp = null;
        }

        return (name);
    }

    public String getFillerOrderNumber() {
        return "";
    }

    public String getEncounterId() {
        return "";
    }

    public String getRadiologistInfo() {
        return "";
    }

    public String getNteForOBX(int i, int j) {

        return "";
    }

    /**
     * Methods to get information about the patient
     */
    @Override
    public String getPatientName() {
        return (parseFullNameFromSegment("/.PID-5-"));
    }

    @Override
    public String getFirstName() {
        try {
            return (getString(terser.get("/.PID-5-2")));
        } catch (HL7Exception ex) {
            return ("");
        }
    }

    @Override
    public String getLastName() {
        try {
            return (getString(terser.get("/.PID-5-1")));
        } catch (HL7Exception ex) {
            return ("");
        }
    }

    @Override
    public String getDOB() {
        try {
            return (formatDateTime(getString(terser.get("/.PID-7-1"))));
        } catch (Exception e) {
            return ("");
        }
    }

    @Override
    public String getAge() {
        String age = "N/A";
        String dob = getDOB();
        try {
            // Some examples
            DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
            java.util.Date date = formatter.parse(dob);
            age = UtilDateUtilities.calcAge(date);
        } catch (ParseException e) {
            logger.error("Could not get age", e);

        }
        return age;
    }

    @Override
    public String getSex() {
        try {
            return (getString(terser.get("/.PID-8-1")));
        } catch (Exception e) {
            return ("");
        }
    }

    @Override
    public String getHealthNum() {
        String healthNum;

        try {

            // Try finding the health number in the external ID
            healthNum = getString(terser.get("/.PID-2-1"));
            if (healthNum.length() == 10)
                return (healthNum);

            // Try finding the health number in the alternate patient ID
            healthNum = getString(terser.get("/.PID-4-1"));
            if (healthNum.length() == 10)
                return (healthNum);

            // Try finding the health number in the internal ID
            healthNum = getString(terser.get("/.PID-3-1"));
            if (healthNum.length() == 10)
                return (healthNum);

            // Try finding the health number in the SSN field
            healthNum = getString(terser.get("/.PID-19-1"));
            if (healthNum.length() == 10)
                return (healthNum);
        } catch (Exception e) {
            // ignore exceptions
        }

        return ("");
    }

    @Override
    public String getHomePhone() {
        try {
            String ext = getString(terser.get("/.PID-13-8"));
            return (getString(terser.get("/.PID-13-6")) + "-" + getString(terser.get("/.PID-13-7")) + " "
                    + (ext != null && ext.length() > 0 ? "x" : "") + ext);
        } catch (Exception e) {
            return ("");
        }
    }

    @Override
    public String getWorkPhone() {
        try {
            String ext = getString(terser.get("/.PID-14-8"));
            return (getString(terser.get("/.PID-14-6")) + "-" + getString(terser.get("/.PID-14-7")) + " "
                    + (ext != null && ext.length() > 0 ? "x" : "") + ext);
        } catch (Exception e) {
            return ("");
        }
    }

    @Override
    public String getPatientLocation() {
        /*
         * try{ String address = getString(terser.get("/.PID-11-1")); String mailing = String.format("%s %s %s", getString(terser.get("/.PID-11-3")), getString(terser.get("/.PID-11-4")), getString(terser.get("/.PID-11-5"))); return address + "<br/>" +
         * mailing; }catch(Exception e){ return(""); }
         */
        return getPerformingFacilityName();
    }

    public String getWorkLocation() {
        try {
            String address = getString(terser.get("/.PID-11-1"));
            String mailing = String.format("%s %s %s", getString(terser.get("/.PID-11-3")),
                    getString(terser.get("/.PID-11-4")), getString(terser.get("/.PID-11-5")));
            return address + "<br/>" + mailing;
        } catch (Exception e) {
            return ("");
        }
    }

    @Override
    public String getServiceDate() {
        try {
            Date mshDate = UtilDateUtilities.StringToDate(getMsgDate(), "yyyy-MM-dd");
            return UtilDateUtilities.DateToString(mshDate, "dd-MMM-yyyy");
        } catch (Exception e) {
            return ("");
        }
    }

    @Override
    public String getOrderStatus() {
        return isCorrected ? "C" : isFinal ? "F" : "P";
    }

    @Override
    public String getClientRef() {
        try {
            return (getString(terser.get("/.OBR-16-1")));
        } catch (Exception e) {
            return ("");
        }
    }

    @Override
    public String getAccessionNum() {
        try {
            return (getString(terser.get("/.ORC-4-1")));
        } catch (Exception e) {
            return ("");
        }
    }

    public String getAccessionNumSourceOrganization() {
        try {
            String key = getString(terser.get("/.ORC-4-3"));
            String ident = "";
            if (key != null && key.indexOf(":") > 0) {
                ident = key.substring(0, key.indexOf(":"));
                ident = getOrganizationType(ident);
                key = key.substring(key.indexOf(":") + 1);
            } else {
                key = "";
            }
            if (key == null || "".equals(key.trim())) {
                return "";
            }
            String sourceOrg = sourceOrganizations.get(key);
            if (sourceOrg == null)
                sourceOrg = defaultSourceOrganizations.get(key);
            return String.format("%s (%s %s)", sourceOrg, ident, key);
        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }
        return "";
    }

    @Override
    public String getDocName() {
        try {
            return (getFullDocName("/.OBR-16-"));
        } catch (Exception e) {
            return ("");
        }
    }

    public String getShortDocName() {
        try {
            return (getShortName("/.OBR-16-"));
        } catch (Exception e) {
            return ("");
        }
    }

    @Override
    public String getCCDocs() {

        try {
            int i = 0;
            String docs = getFullDocName("/.OBR-28(" + i + ")-");
            i++;
            String nextDoc = getFullDocName("/.OBR-28(" + i + ")-");

            while (!nextDoc.equals("")) {
                docs = docs + ", " + nextDoc;
                i++;
                nextDoc = getFullDocName("/.OBR-28(" + i + ")-");
            }

            return (docs);
        } catch (Exception e) {
            return ("");
        }
    }

    @Override
    public ArrayList<String> getDocNums() {
        ArrayList<String> nums = new ArrayList<String>();
        String docNum;
        try {
            if ((docNum = terser.get("/.OBR-16-1")) != null)
                nums.add(docNum);

            int i = 0;
            while ((docNum = terser.get("/.OBR-28(" + i + ")-1")) != null) {
                nums.add(docNum);
                i++;
            }

        } catch (Exception e) {
            MiscUtils.getLogger().error("OLIS HL7 Error", e);
        }

        return (nums);
    }

    @Override
    public String audit() {
        return "";
    }

    protected String getOBXField(int i, int j, int field, int rep, int comp) {
        ArrayList<Segment> obxSegs = obrGroups.get(i);

        try {
            Segment obxSeg = obxSegs.get(j);
            return (getString(Terser.get(obxSeg, field, rep, comp, 1))).trim();
        } catch (Exception e) {
            return ("");
        }
    }

    protected String getOBXEDField(int i, int j, int field, int rep, int comp) {
        ArrayList<Segment> obxSegs = obrGroups.get(i);

        try {
            Segment obxSeg = obxSegs.get(j);
            return Terser.get(obxSeg, field, rep, comp, 1);
        } catch (Exception e) {
            return ("");
        }
    }

    private int getNTELocation(int i, int j) {

        int obrCount = 0;
        int obxCount = 0;
        // Compensating for -1 parameters for OBR and OBX
        j++;
        i++;
        String[] segments = terser.getFinder().getRoot().getNames();

        String segId = "";
        for (int k = 0; k != segments.length && obxCount <= j && obrCount <= i; k++) {
            segId = segments[k].substring(0, 3);

            // We count all OBRs we see.
            if (segId.equals("OBR")) {
                obrCount++;
            }

            // We count only OBX's for the desired OBR
            else if (segId.equals("OBX") && obrCount == i) {
                obxCount++;
            }

            // Check that this segment is an NTE and we are in the right OBR/OBX position.
            else if (segId.equals("NTE") && obxCount == j && obrCount == i) {
                return k;
            }
        }
        return segments.length - 1;
    }

    private String getFullDocName(String docSeg) throws HL7Exception {
        String docName = "";
        String temp;

        // get name prefix ie/ DR.
        temp = terser.get(docSeg + "6");
        if (temp != null)
            docName = temp;

        // get the name
        temp = terser.get(docSeg + "3");
        if (temp != null) {
            if (docName.equals("")) {
                docName = temp;
            } else {
                docName = docName + " " + temp;
            }
        }

        if (terser.get(docSeg + "4") != null) {
            docName = docName + " " + terser.get(docSeg + "4");
        }
        if (terser.get(docSeg + "2") != null) {
            docName = docName + " " + terser.get(docSeg + "2");
        }
        if (terser.get(docSeg + "5") != null) {
            docName = docName + " " + terser.get(docSeg + "5");
        }
        if (terser.get(docSeg + "7") != null) {
            docName = docName + " " + terser.get(docSeg + "7");
        }
        String modifier = "";
        if (terser.get(docSeg + "13") != null) {
            modifier = terser.get(docSeg + "13").toUpperCase();
            if (modifier.equals("MDL")) {
                modifier = "MD";
            }
            if (modifier.equals("ML")) {
                modifier = "RM";
            }
            if (modifier.equals("NPL")) {
                modifier = "RN(EC)";
            }
            if (modifier.equals("DDSL")) {
                modifier = "DDS";
            }

        }
        if (terser.get(docSeg + "1") != null) {
            docName = docName + " " + "<span style=\"margin-left:15px; font-size:8px; color:#333333;\">" + modifier
                    + " " + terser.get(docSeg + "1") + "</span>";
        }

        return (docName);
    }

    private String getShortName(String docSeg) throws HL7Exception {
        String docName = "";
        String temp;

        // get name prefix ie/ DR.
        temp = terser.get(docSeg + "6");
        if (temp != null)
            docName = temp;

        // get the name
        temp = terser.get(docSeg + "3");
        if (temp != null) {
            if (docName.equals("")) {
                docName = temp;
            } else {
                docName = docName + " " + temp;
            }
        }

        if (terser.get(docSeg + "4") != null) {
            docName = docName + " " + terser.get(docSeg + "4");
        }
        if (terser.get(docSeg + "2") != null) {
            docName = docName + " " + terser.get(docSeg + "2");
        }
        if (terser.get(docSeg + "5") != null) {
            docName = docName + " " + terser.get(docSeg + "5");
        }
        if (terser.get(docSeg + "7") != null) {
            docName = docName + " " + terser.get(docSeg + "7");
        }

        return docName;
    }

    protected String formatTime(String plain) {

        String dateFormat = "HHmmss";
        dateFormat = dateFormat.substring(0, plain.length());
        String stringFormat = "HH:mm:ss";
        stringFormat = stringFormat.substring(0,
                stringFormat.lastIndexOf(dateFormat.charAt(dateFormat.length() - 1)) + 1);

        Date date = UtilDateUtilities.StringToDate(plain, dateFormat);
        return UtilDateUtilities.DateToString(date, stringFormat);
    }

    protected String formatDateTime(String plain) {
        if (plain == null || plain.trim().equals(""))
            return "";

        String offset = "";
        if (plain.length() > 14) {
            offset = plain.substring(14, 19);
            plain = plain.substring(0, 14);
        }
        String dateFormat = "yyyyMMddHHmmss";
        dateFormat = dateFormat.substring(0, plain.length());
        String stringFormat = "yyyy-MM-dd HH:mm:ss";
        stringFormat = stringFormat.substring(0,
                stringFormat.lastIndexOf(dateFormat.charAt(dateFormat.length() - 1)) + 1);

        Date date = UtilDateUtilities.StringToDate(plain, dateFormat);
        return UtilDateUtilities.DateToString(date, stringFormat) + " " + getOffsetName(offset);
    }

    private String getOffsetName(String offset) {
        if (offset.equals("-0400")) {
            return "EDT";
        } else if (offset.equals("-0500")) {
            return "EST";
        } else if (offset.equals("-0600")) {
            return "CST";
        } else if (!offset.trim().equals("")) {
            return "UTC" + offset;
        }
        return "";
    }

    public void importSourceOrganizations(OLISHL7Handler instance) {
        if (instance == null) {
            return;
        }
        HashMap<String, String> foreignSource = instance.sourceOrganizations;
        for (String key : foreignSource.keySet()) {
            if (!sourceOrganizations.containsKey(key)) {
                sourceOrganizations.put(key, foreignSource.get(key));
            }
        }
    }

    protected String formatDate(String plain) {

        String dateFormat = "yyyyMMdd";
        dateFormat = dateFormat.substring(0, plain.length());
        String stringFormat = "yyyy-MM-dd";
        stringFormat = stringFormat.substring(0,
                stringFormat.lastIndexOf(dateFormat.charAt(dateFormat.length() - 1)) + 1);

        Date date = UtilDateUtilities.StringToDate(plain, dateFormat);
        return UtilDateUtilities.DateToString(date, stringFormat);
    }

    protected String getString(String retrieve) {
        if (retrieve != null) {
            return retrieve.trim();
        } else {
            return ("");
        }
    }

    boolean centered = false;

    public String formatString(String s) {
        int pos = 0;
        StringBuilder sb = new StringBuilder();
        centered = false;
        if (s == null || s.equals("")) {
            return "";
        }
        int pieceStart = 0;
        int pieceEnd = 0;
        String op = "";
        String result = "";
        while (pos < s.length()) {
            pieceStart = s.indexOf('\\', pos);
            pieceEnd = s.indexOf('\\', pieceStart + 1);

            // If there are no delimiters take the whole string from this position.
            if (pieceStart == -1 || pieceEnd == -1) {
                sb.append(s.substring(pos, s.length()));
                pos = s.length();
            } else {
                if (pos < pieceStart) {
                    sb.append(s.substring(pos, pieceStart));
                    pos = pieceStart;
                }
                // If two delimiters are adjacent ignore the first one
                if (pieceStart + 1 == pieceEnd) {
                    sb.append("\\");
                    pos = pieceEnd;
                } else {
                    op = s.substring(pieceStart + 1, pieceEnd);
                    result = parseOperator(op);
                    if (result.equals("")) {
                        sb.append(op);
                    } else {
                        sb.append(result);
                    }
                    pos = pieceEnd + 1;
                }
            }
        }

        return sb.toString();
    }

    public String parseOperator(String op) {
        if (op == null || op.equals("")) {
            return "";
        }

        String piece = op.toUpperCase();
        boolean matchFound = true;

        if (piece.equals(".BR")) {
            boolean old = centered;
            centered = false;
            return old ? "</center>" : "<br/>";

        } else if (piece.equals(".H")) {
            return "<span style=\"color:#767676\">";
        } else if (piece.equals(".N")) {
            return "</span>";
        } else if (piece.equals(".CE")) {
            centered = true;
            return (centered ? "</center>" : "") + "<br/><center>";

        } else if (piece.equals(".FE")) {
            // TODO: Implement
        } else if (piece.equals(".NF")) {
            // TODO: Implement
        } else if (piece.equals("F")) {
            return "|";
        } else if (piece.equals("S")) {
            return "^";
        } else if (piece.equals("T")) {
            return "&";
        } else if (piece.equals("R")) {
            return "~";
        } else if (piece.equals("SLASHHACK")) {
            return "\\";
        } else if (piece.equals("MUHACK")) {
            return "&#181;";
        } else {
            matchFound = false;
        }

        if (!matchFound) {
            // If we haven't already matched a command, look for a command with a parameter.
            String patternStr = "\\.(SP|IN|TI|SK)\\s*(\\d*)\\s*";
            Pattern pattern = Pattern.compile(patternStr);
            Matcher matcher = pattern.matcher(piece.toUpperCase());
            matchFound = matcher.find();
            if (matchFound) {
                // Get all groups for this match
                String result = parseParamsAndFormat(matcher.group(1), matcher.group(2), centered);
                if (result.contains("</center>")) {
                    centered = false;
                }
                return result == null ? "" : result;
            }
        }
        return "";
    }

    public static String parseParamsAndFormat(String operator, String operand, boolean centered) {
        Integer opInt = operand.equals("") ? 1 : Integer.valueOf(operand);
        String result = "";
        if (operator.equals("SP")) {
            while (opInt > 0) {
                if (centered) {
                    result += "</center>";
                    centered = false;
                }
                result += "<br/>";
                opInt--;
            }
        } else if (operator.equals("IN")) {
            // TODO: Implement
        } else if (operator.equals("TI")) {
            // TODO: Implement
        } else if (operator.equals("SK")) {
            while (opInt > 0) {
                result += "&nbsp;";
                opInt--;
            }
        } else {
            result = null;
        }
        return result;
    }

    public class OLISError {
        public OLISError(String segment, String sequence, String field, String indentifer, String text) {
            super();
            this.segment = segment;
            this.sequence = sequence;
            this.field = field;
            this.indentifer = indentifer;
            this.text = text;
        }

        String segment, sequence, field, indentifer, text;

        public String getSegment() {
            return segment;
        }

        public void setSegment(String segment) {
            this.segment = segment;
        }

        public String getSequence() {
            return sequence;
        }

        public void setSequence(String sequence) {
            this.sequence = sequence;
        }

        public String getField() {
            return field;
        }

        public void setField(String field) {
            this.field = field;
        }

        public String getIndentifer() {
            return indentifer;
        }

        public void setIndentifer(String indentifer) {
            this.indentifer = indentifer;
        }

        public String getText() {
            return text;
        }

        public void setText(String text) {
            this.text = text;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + getOuterType().hashCode();
            result = prime * result + ((field == null) ? 0 : field.hashCode());
            result = prime * result + ((indentifer == null) ? 0 : indentifer.hashCode());
            result = prime * result + ((segment == null) ? 0 : segment.hashCode());
            result = prime * result + ((sequence == null) ? 0 : sequence.hashCode());
            return result;
        }

        /**
         * OLIS Errors are identified by the error code for global errors or the segment, sequence and field of the error for localised errors.
         */
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (obj instanceof String) {
                return this.indentifer.equals(obj);
            }
            if (getClass() != obj.getClass())
                return false;
            OLISError other = (OLISError) obj;
            if (!getOuterType().equals(other.getOuterType()))
                return false;
            if (field == null) {
                if (other.field != null)
                    return false;
            } else if (!field.equals(other.field))
                return false;
            if (segment == null) {
                if (other.segment != null)
                    return false;
            } else if (!segment.equals(other.segment))
                return false;
            if (sequence == null) {
                if (other.sequence != null)
                    return false;
            } else if (!sequence.equals(other.sequence))
                return false;
            return true;
        }

        private OLISHL7Handler getOuterType() {
            return OLISHL7Handler.this;
        }

    }
}