org.openmrs.module.rwandaprimarycare.PrimaryCareBusinessLogic.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.module.rwandaprimarycare.PrimaryCareBusinessLogic.java

Source

/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */
package org.openmrs.module.rwandaprimarycare;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.Concept;
import org.openmrs.Encounter;
import org.openmrs.EncounterType;
import org.openmrs.Location;
import org.openmrs.Obs;
import org.openmrs.Patient;
import org.openmrs.PatientIdentifier;
import org.openmrs.PatientIdentifierType;
import org.openmrs.Person;
import org.openmrs.PersonAddress;
import org.openmrs.PersonAttribute;
import org.openmrs.PersonAttributeType;
import org.openmrs.Provider;
import org.openmrs.Relationship;
import org.openmrs.RelationshipType;
import org.openmrs.User;
import org.openmrs.Visit;
import org.openmrs.VisitAttributeType;
import org.openmrs.VisitType;
import org.openmrs.api.context.Context;
import org.openmrs.module.idgen.IdentifierSource;
import org.openmrs.module.idgen.service.IdentifierSourceService;
import org.openmrs.module.namephonetics.NamePhoneticsService;

public class PrimaryCareBusinessLogic {

    protected static final Log log = LogFactory.getLog(PrimaryCareBusinessLogic.class);

    /**
     * Convenience method that returns the handle to the primary care service instance.
     *
     * @return PrimaryCareService service instance
     */
    public static PrimaryCareService getService() {
        return Context.getService(PrimaryCareService.class);
    }

    /**
     * Records that the given patient was seen at the given location on the given datetime.
     * First we look for an encounter of type 'Registration' for the given location and date (ignoring time).
     * If one exists, nothing happens, otherwise a new encounter is created with the date+time.
     *
     * @param patient
     * @param location
     * @param datetime
     * @param provider
     * @return a registration encounter that day, either pre-existing or just created
     */
    public static Encounter patientSeen(Patient patient, Location location, Date datetime, User provider) {
        if (location == null) {
            //location = Context.getLocationService().getDefaultLocation();
            throw new IllegalArgumentException("location is required");
        }
        if (datetime == null) {
            datetime = new Date();
        }
        if (provider == null) {
            provider = Context.getAuthenticatedUser();
        }

        Date[] day = getStartAndEndOfDay(datetime);
        List<Encounter> any = Context.getEncounterService().getEncounters(patient, location, day[0], day[1], null,
                Collections.singleton(getRegistrationEncounterType()), null, false);
        if (any != null && any.size() > 0) {
            // found one
            return any.get(0);
        }

        // did not find an encounter that day, so we create a new one 
        Encounter enc = new Encounter();
        enc.setEncounterType(getRegistrationEncounterType());
        enc.setEncounterDatetime(datetime);
        enc.setLocation(location);

        {
            // wow, this sucks to have to do....
            Collection<Provider> provs = Context.getProviderService()
                    .getProvidersByPerson(Context.getPersonService().getPerson(provider.getPerson().getPersonId()));
            Provider prov = null;
            if (provs.size() > 0)
                prov = provs.iterator().next();
            else {
                prov = new Provider();
                prov.setPerson(Context.getPersonService().getPerson(provider.getPerson().getPersonId()));
                prov.setRetired(false);
                prov.setIdentifier(provider.getPerson().getPersonId().toString());
                prov.setDescription("provider object created by ");
                prov = Context.getProviderService().saveProvider(prov);
            }
            enc.setProvider(PrimaryCareConstants.PRIMARY_CARE_ENCOUNTER_ROLE, prov);
        }

        //        enc.setProvider(Context.getPersonService().getPerson(provider.getPerson().getPersonId()));
        enc.setPatient(patient);
        PrimaryCareBusinessLogic.saveEncounterAndVerifyVisit(enc);

        return enc;
    }

    /**
     * Finds or creates a registration encounter on the given datetime, and adds the given observations to it.
     *
     * @param patient
     * @param location
     * @param datetime
     * @param provider
     * @param observations
     * @return
     */
    public static Encounter addObsToRegistrationEncounter(Patient patient, Location location, Date datetime,
            User provider, Collection<Obs> observations) {
        Encounter enc = patientSeen(patient, location, datetime, provider);
        if (observations != null && observations.size() > 0) {
            for (Obs obs : observations) {
                enc.addObs(obs);
            }
            PrimaryCareBusinessLogic.saveEncounterAndVerifyVisit(enc);
        }
        return enc;
    }

    /**
     * Creates a new encounter, with observations
     *
     * @param patient
     * @param encounterType
     * @param location
     * @param date
     * @param provider
     * @param observations
     * @return the encounter created
     */
    public static Encounter createEncounter(Patient patient, EncounterType encounterType, Location location,
            Date datetime, User provider, List<Obs> observations) {
        if (patient == null)
            throw new IllegalArgumentException("patient is required");
        if (encounterType == null)
            throw new IllegalArgumentException("encounterType is required");
        if (location == null)
            throw new IllegalArgumentException("location is required");
        if (datetime == null)
            datetime = new Date();
        if (provider == null)
            provider = Context.getAuthenticatedUser();

        Encounter enc = new Encounter();
        enc.setEncounterType(encounterType);
        enc.setEncounterDatetime(datetime);
        enc.setLocation(location);

        {
            // wow, this sucks to have to do....
            Collection<Provider> provs = Context.getProviderService()
                    .getProvidersByPerson(Context.getPersonService().getPerson(provider.getPerson().getPersonId()));
            Provider prov = null;
            if (provs.size() > 0)
                prov = provs.iterator().next();
            else {
                prov = new Provider();
                prov.setPerson(Context.getPersonService().getPerson(provider.getPerson().getPersonId()));
                prov.setRetired(false);
                prov.setIdentifier(provider.getPerson().getPersonId().toString());
                prov.setDescription("provider object created by ");
                prov = Context.getProviderService().saveProvider(prov);
            }
            enc.setProvider(PrimaryCareConstants.PRIMARY_CARE_ENCOUNTER_ROLE, prov);
        }

        enc.setPatient(patient);
        for (Obs obs : observations) {
            enc.addObs(obs);
        }
        return PrimaryCareBusinessLogic.saveEncounterAndVerifyVisit(enc);
    }

    /**
     * @param datetime
     * @return
     */
    public static Date[] getStartAndEndOfDay(Date datetime) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(datetime);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Date startOfDay = cal.getTime();
        cal.add(Calendar.DAY_OF_MONTH, 1);
        cal.add(Calendar.MILLISECOND, -1);
        Date endOfDay = cal.getTime();
        return new Date[] { startOfDay, endOfDay };
    }

    /**
     *
     * Added by module activator  so should always be there. 
     * TODO: internationalize this?
     *
     * @return
     */
    public static EncounterType getRegistrationEncounterType() {
        if (PrimaryCareConstants.ENCOUNTER_TYPE_REGISTRATION == null)
            throw new RuntimeException("Registration Encounter Type is null");
        return PrimaryCareConstants.ENCOUNTER_TYPE_REGISTRATION;
        //return Context.getEncounterService().getEncounterType("Registration");
    }

    public static EncounterType getVitalsEncounterType() {
        if (PrimaryCareConstants.ENCOUNTER_TYPE_REGISTRATION == null)
            throw new RuntimeException("Vitals Encounter Type is null");
        return PrimaryCareConstants.ENCOUNTER_TYPE_VITALS;
        //return Context.getEncounterService().getEncounterType("Registration");
    }

    public static VisitType getOutpatientVisitType() {
        if (PrimaryCareConstants.ENCOUNTER_TYPE_REGISTRATION == null)
            throw new RuntimeException("Primary Care Visit Type is null");

        List<VisitType> vt = Context.getVisitService().getAllVisitTypes();

        for (VisitType v : vt) {

            String visitName = v.getName();
            if (visitName.equals("Primary Care Outpatient")) {
                return v;
            }

        }

        return PrimaryCareConstants.VISIT_TYPE_OUTPATIENT;
        //return Context.getEncounterService().getEncounterType("Registration");
    }

    public static Concept getWeightConcept() {
        Concept concept = null;
        String gp = Context.getAdministrationService().getGlobalProperty("concept.weight");
        if (gp == null)
            throw new RuntimeException("You must set the global property concept.weight.");

        concept = Context.getConceptService().getConceptByUuid(gp);
        if (concept == null) {
            try {
                concept = Context.getConceptService().getConcept(Integer.valueOf(gp));
            } catch (Exception ex) {
            }
            if (concept == null) {
                throw new RuntimeException("Cannot find concept specified by global property concept.weight");
            }
        }
        return concept;
    }

    public static Concept getHeightConcept() {
        Concept concept = null;
        String gp = Context.getAdministrationService().getGlobalProperty("concept.height");
        if (gp == null)
            throw new RuntimeException("You must set the global property concept.height");
        concept = Context.getConceptService().getConceptByUuid(gp);
        if (concept == null) {
            try {
                concept = Context.getConceptService().getConcept(Integer.valueOf(gp));
            } catch (Exception ex) {
            }
            if (concept == null) {
                throw new RuntimeException("Cannot find concept specified by global property concept.height");
            }
        }
        return concept;
    }

    public static Concept getTemperatureConcept() {
        Concept concept = null;
        String gp = Context.getAdministrationService().getGlobalProperty("concept.temperature");
        if (gp == null)
            throw new RuntimeException("You must set the global property concept.temperature.");
        concept = Context.getConceptService().getConceptByUuid(gp);
        if (concept == null) {
            try {
                concept = Context.getConceptService().getConcept(Integer.valueOf(gp));
            } catch (Exception ex) {
            }
            if (concept == null) {
                throw new RuntimeException("Cannot find concept specified by global property concept.temperature");
            }
        }
        return concept;
    }

    public static Concept getDiagnosisNonCodedConcept() {
        Concept concept = null;
        String gp = Context.getAdministrationService().getGlobalProperty("concept.diagnosisNonCoded");
        if (gp == null)
            throw new RuntimeException("You must set the global property concept.diagnosisNonCoded");
        concept = Context.getConceptService().getConceptByUuid(gp);
        if (concept == null) {
            try {
                concept = Context.getConceptService().getConcept(Integer.valueOf(gp));
            } catch (Exception ex) {
            }
            if (concept == null) {
                throw new RuntimeException(
                        "Cannot find concept specified by global property concept.diagnosisNonCoded");
            }
        }
        return concept;
    }

    public static PatientIdentifierType getPrimaryPatientIdentiferType() {
        String gp = Context.getAdministrationService()
                .getGlobalProperty(PrimaryCareConstants.GLOBAL_PROPERTY_PRIMARY_IDENTIFIER_TYPE);
        if (gp == null)
            throw new RuntimeException(
                    "You must set the value for the main identifier type for primary care.  This is set in GP:  registration.primaryIdentifierType");
        PatientIdentifierType pit = null;
        pit = Context.getPatientService().getPatientIdentifierTypeByUuid(gp);
        try {
            pit = Context.getPatientService().getPatientIdentifierType(Integer.valueOf(gp));
        } catch (Exception ex) {
            pit = Context.getPatientService().getPatientIdentifierTypeByName(gp);
        }
        if (pit == null) {
            throw new RuntimeException("Cannot find patient identifier type specified by global property "
                    + PrimaryCareConstants.GLOBAL_PROPERTY_PRIMARY_IDENTIFIER_TYPE);
        }
        return pit;
    }

    public static Integer getNumberOfBarcodeCopiesToPrint() {
        try {
            return Integer.valueOf(Context.getAdministrationService()
                    .getGlobalProperty(PrimaryCareConstants.GLOBAL_PROPERTY_BAR_CODE_COUNT));
        } catch (Exception ex) {
            log.error("couldn't parse or find global property registration.barCodeCount.  defaulting to 1.");
            return 1;
        }
    }

    /**
     * Gets all patient identifier types that should be used in this module.
     * This includes the primary type and the other types specified in the two global
     * properties.
     *
     * The first element of the returned list is the primary type. This method ensures
     * that the returned list contains no duplicates.
     *
     * @return
     */
    public static List<PatientIdentifierType> getPatientIdentifierTypesToUse() {
        List<PatientIdentifierType> ret = new ArrayList<PatientIdentifierType>();
        ret.add(getPrimaryPatientIdentiferType());

        String s = Context.getAdministrationService()
                .getGlobalProperty(PrimaryCareConstants.GLOBAL_PROPERTY_OTHER_IDENTIFIER_TYPES);
        if (s != null) {
            String[] ids = s.split(",");
            for (String idAsString : ids) {
                try {
                    idAsString = idAsString.trim();
                    if (idAsString.length() == 0)
                        continue;
                    PatientIdentifierType idType = null;
                    idType = Context.getPatientService().getPatientIdentifierTypeByUuid(idAsString);
                    if (idType == null) {
                        try {
                            Integer id = Integer.valueOf(idAsString);
                            idType = Context.getPatientService().getPatientIdentifierType(id);
                        } catch (Exception ex) {
                            idType = Context.getPatientService().getPatientIdentifierTypeByName(idAsString);
                        }
                    }
                    if (idType == null) {
                        throw new IllegalArgumentException("Cannot find patient identifier type " + idAsString
                                + " specified in global property "
                                + PrimaryCareConstants.GLOBAL_PROPERTY_OTHER_IDENTIFIER_TYPES);
                    }
                    if (!ret.contains(idType)) {
                        ret.add(idType);
                    }
                } catch (Exception ex) {
                    throw new IllegalArgumentException("Error in global property "
                            + PrimaryCareConstants.GLOBAL_PROPERTY_OTHER_IDENTIFIER_TYPES + " near '" + idAsString
                            + "'");
                }
            }
        }
        return ret;
    }

    /**
     * Searches for patients with the given identifier. Only looks at identifier types specified by the global
     * properties.
     *
     * Sorts so that matches for the specified location come first.
     * Then sorts the results so that matches for primary identifier type come first.
     *
     * @param identifier required
     * @param location optional
     * @return
     */
    public static List<Patient> findPatientsByIdentifier(String search, final Location location) {
        PatientIdentifierType preferredIdentifierType = getPrimaryPatientIdentiferType();
        List<PatientIdentifier> ids = Context.getPatientService().getPatientIdentifiers(search,
                getPatientIdentifierTypesToUse(), null, null, null);
        List<Patient> ret = new ArrayList<Patient>();

        // first identifiers of the preferred type, then others
        for (PatientIdentifier id : ids) {
            if (id.getIdentifierType().equals(preferredIdentifierType)) {
                if (!id.getPatient().isVoided()) {
                    ret.add(id.getPatient());
                }
            }
        }
        for (PatientIdentifier id : ids) {
            if (!id.getIdentifierType().equals(preferredIdentifierType)) {
                if (!id.getPatient().isVoided()) {
                    ret.add(id.getPatient());
                }
            }
        }
        sortResultsForUser(ret, location);
        return ret;
    }

    /**
     *
     * Sorts patients by location
     *
     * @param patientList
     * @param userLocation
     * @return
     */
    public static List<Patient> sortResultsForUser(List<Patient> patientList, final Location userLocation) {
        if (userLocation != null) {
            Collections.sort(patientList, new Comparator<Patient>() {
                public int compare(Patient left, Patient right) {
                    Integer leftWeight = getLocations(left).contains(userLocation) ? 0 : 1;
                    Integer rightWeight = getLocations(right).contains(userLocation) ? 0 : 1;
                    return leftWeight.compareTo(rightWeight);
                }
            });
        }
        return patientList;
    }

    /**
     * Currently looks for a person attribute named "Health Center" but may eventually be changed to return
     * all encounter locations for the patient.
     *
     * @param patient
     * @return
     */
    public static Collection<Location> getLocations(Patient patient) {
        Collection<Location> ret = new ArrayList<Location>();
        try {
            ret.add((Location) patient.getAttribute(getAssignedLocationPersonAttributeType()).getHydratedObject());
        } catch (Exception ex) {
            // presumably the patient has no assigned location. not really a problem
        }
        return ret;
    }

    public static Location getLocationLoggedIn(HttpSession session) {
        return (Location) session.getAttribute(PrimaryCareConstants.SESSION_ATTRIBUTE_WORKSTATION_LOCATION);
    }

    static PersonAttributeType assignedLocationPersonAttributeType = null;

    public static PersonAttributeType getAssignedLocationPersonAttributeType() {
        if (assignedLocationPersonAttributeType == null) {
            assignedLocationPersonAttributeType = PrimaryCareUtil.getHealthCenterAttributeType();
        }
        return assignedLocationPersonAttributeType;
    }

    public static List<Patient> sortResultsForUmudugudu(List<Patient> patientList, final String umudugudu) {
        if (umudugudu != null) {
            Collections.sort(patientList, new Comparator<Patient>() {
                public int compare(Patient left, Patient right) {
                    return umuduguduWeightHelper(left, umudugudu)
                            .compareTo(umuduguduWeightHelper(right, umudugudu));
                }
            });
        }
        return patientList;

    }

    /**
     * How good a match is the given umudugudu for the given patient?
     *
     * @param patient
     * @param umudugudu
     * @return 0 if the patient is currently in the umudugudu, 1 if they ever have been, 2 if they never have been
     */
    private static Integer umuduguduWeightHelper(Patient patient, String umudugudu) {
        boolean first = true;
        for (PersonAddress pa : patient.getAddresses()) {
            if (pa.getAddress1() != null && pa.getAddress1().equalsIgnoreCase(umudugudu)) {
                return first ? 0 : 1;
            }
            first = false;
        }
        return 2;
    }

    /**
     *
     * Get the parents parents;
     *
     * @param p
     * @return List<Person>
     */
    public static List<Person> getParents(Patient p) {
        List<Person> ret = new ArrayList<Person>();

        RelationshipType rt = getParentRelationshipType();
        List<Relationship> rlist = Context.getPersonService().getRelationshipsByPerson(p);
        for (Relationship r : rlist) {
            if (r.getRelationshipType().getRelationshipTypeId().equals(rt.getRelationshipTypeId())) {
                if (r.getPersonB().getPersonId().equals(p.getPatientId())) {
                    ret.add(r.getPersonA());
                }
            }
        }
        return ret;
    }

    public static RelationshipType getParentRelationshipType() {
        String gp = Context.getAdministrationService()
                .getGlobalProperty(PrimaryCareConstants.GLOBAL_PROPERTY_PARENT_TO_CHILD_RELATIONSHIP_TYPE);
        if (gp == null)
            throw new RuntimeException(
                    "you must set a value for global property registration.parentChildRelationshipTypeId.");
        RelationshipType rt = Context.getPersonService().getRelationshipTypeByUuid(gp);
        if (rt == null) {
            try {
                rt = Context.getPersonService().getRelationshipType(Integer.valueOf(gp));
            } catch (Exception ex) {
                rt = Context.getPersonService().getRelationshipTypeByName(gp);
            }
            if (rt == null)
                throw new RuntimeException("can't parse registration.parentChildRelationshipTypeId.");
        }
        return rt;
    }

    /**
     *
     * This will void a parent relationship from the patient;
     *
     * @param patient
     * @param parent
     */
    public static void voidParent(Patient patient, Person parent) {

        RelationshipType rt = getParentRelationshipType();
        List<Relationship> rlist = Context.getPersonService().getRelationshipsByPerson(patient);
        for (Relationship r : rlist) {
            if (r.getRelationshipType().getRelationshipTypeId().equals(rt.getRelationshipTypeId())) {
                if (r.getPersonA().equals(parent)) {
                    r.setVoided(true);
                    r.setDateChanged(new Date());
                    r.setChangedBy(Context.getAuthenticatedUser());
                    Context.getPersonService().saveRelationship(r);
                }
            }
        }

    }

    /**
     *
     * returns an unused primary identifier string from the identifier source
     *
     * @return
     */
    public static String getNewPrimaryIdentifierString() {
        List<String> idList = getNewPrimaryIdentifiers(1);
        String addIdentifier = idList.get(0);
        if (addIdentifier == null || addIdentifier.length() == 0) {
            IdentifierSource is = PrimaryCareUtil.getPrimaryIdentifierTypeSource();
            throw new RuntimeException("generateNewIdentifier failed for " + is.getName());
        }
        return addIdentifier;
    }

    public static List<String> getNewPrimaryIdentifiers(Integer quantity) {
        IdentifierSourceService iss = Context.getService(IdentifierSourceService.class);
        IdentifierSource is = PrimaryCareUtil.getPrimaryIdentifierTypeSource();
        //TODO:   fix this -- this needs a 'while' loop.
        List<String> idList = iss.generateIdentifiers(is, quantity, "reg module");
        return idList;
    }

    public static List<Patient> getPatientWithSoundex(String givenName, String rwName, Location userLocation,
            String umudugudu) {
        NamePhoneticsService nps = Context.getService(NamePhoneticsService.class);
        List<Patient> ret = nps.findPatient(givenName, null, rwName, null);
        String restrictByHealthCenter = Context.getAdministrationService()
                .getGlobalProperty("registration.restrictSearchByHealthCenter");
        if (restrictByHealthCenter == "true") {
            List<Patient> newList = new ArrayList<Patient>();
            PersonAttributeType pat = PrimaryCareUtil.getHealthCenterAttributeType();
            for (Patient p : ret) {
                PersonAttribute pa = p.getAttribute(pat);
                if (pa.getHydratedObject().equals(userLocation))
                    newList.add(p);
            }
            PrimaryCareBusinessLogic.sortResultsForUser(newList, userLocation);
            PrimaryCareBusinessLogic.sortResultsForUmudugudu(newList, umudugudu);
            return newList;
        }

        PrimaryCareBusinessLogic.sortResultsForUser(ret, userLocation);
        PrimaryCareBusinessLogic.sortResultsForUmudugudu(ret, umudugudu);
        return ret;

    }

    public static List<Concept> getInsuranceTypeAnswers() {
        List<Concept> ret = new ArrayList<Concept>();
        String sList = Context.getAdministrationService()
                .getGlobalProperty(PrimaryCareConstants.GLOBAL_PROPERTY_INSURANCE_TYPE_ANSWERS);
        for (StringTokenizer st = new StringTokenizer(sList, ","); st.hasMoreTokens();) {
            String s = st.nextToken().trim();
            Concept c = Context.getConceptService().getConceptByUuid(s);
            if (c == null) {
                try {
                    c = Context.getConceptService().getConcept(Integer.valueOf(s));
                } catch (Exception ex) {
                    throw new RuntimeException(
                            "Can't parse the global property registration.insuranceTypeConceptAnswers");
                }
            }
            ret.add(c);
        }
        return ret;
    }

    public static Concept getLastInsuranceType(Patient patient) {
        Obs o = PrimaryCareUtil.getMostRecentObs(patient, PrimaryCareUtil.getInsuranceTypeConcept());
        if (o != null)
            return o.getValueCoded();
        else
            return null;
    }

    public static String getLastInsuranceNumber(Patient patient) {
        Obs o = PrimaryCareUtil.getMostRecentObs(patient, PrimaryCareUtil.getInsuranceNumberConcept());
        if (o != null)
            return o.getValueText();
        else
            return null;
    }

    public static PatientIdentifier getPrimaryPatientIdentifierForLocation(Patient patient, Location location) {
        List<PatientIdentifier> piList = patient.getActiveIdentifiers();
        for (PatientIdentifier piTmp : piList) {
            if (piTmp.getIdentifierType().getPatientIdentifierTypeId()
                    .equals(getPrimaryPatientIdentiferType().getPatientIdentifierTypeId())
                    && piTmp.getLocation().getLocationId().equals(location.getLocationId())) {
                return piTmp;
            }
        }

        return null;

    }

    public static Patient setHealthCenter(Patient p, Location location) {
        PersonAttributeType pat = PrimaryCareUtil.getHealthCenterAttributeType();
        PersonAttribute paTmp = p.getAttribute(pat);

        if (location != null
                && (paTmp == null || !paTmp.getValue().equals(String.valueOf(location.getLocationId())))) {
            PersonAttribute pa = PrimaryCareUtil.newPersonAttribute(pat, location.getLocationId().toString(), p);
            p.addAttribute(pa);
            //argh.. check for preferred identifier for validator:

            return preferredIdentifierSafeSavePatient(p);
        }
        return p;
    }

    /**
     * Use this to save patients to ensure there's a preferred identifier
     * @param p
     * @return
     */
    public static Patient preferredIdentifierSafeSavePatient(Patient p) {
        //if there's a preferred patient, just save the patient and return
        //       for (PatientIdentifier pi : p.getActiveIdentifiers()){
        //          if (pi.getPreferred())
        //             return Context.getPatientService().savePatient(p);
        //       }
        //else, find primary care identifier and set that as preferred
        PatientIdentifier pi = p.getPatientIdentifier(getPrimaryPatientIdentiferType());
        if (pi != null) {
            pi.setPreferred(true);
            log.info("Prefered Identifier >>> " + pi.getIdentifier());
            log.info("Person Names FName >>" + p.getFamilyName() + " ** GName >> " + p.getGivenName());
            log.info("Size is >> " + p.getNames().size());
        } else { //set the first identifier as preferred
            try {
                p.getActiveIdentifiers().get(0).setPreferred(true);
            } catch (Exception ex) {
                //there are no identifiers on this patient!
            }
        }
        return Context.getPatientService().savePatient(p);
    }

    public static boolean doesPatientNeedAnIDForThisLocation(Patient patient, Location location) {
        PatientIdentifierType pit = PrimaryCareBusinessLogic.getPrimaryPatientIdentiferType();
        List<PatientIdentifier> piList = patient.getActiveIdentifiers();
        for (PatientIdentifier pi : piList) {
            if (pi.getLocation().getLocationId().equals(location.getLocationId()) && pi.getIdentifierType()
                    .getPatientIdentifierTypeId().equals(pit.getPatientIdentifierTypeId())) {
                return false;
            }
        }
        return true;
    }

    public static boolean doesPatientAlreadyHaveThisID(Patient patient, String identifier) {
        PatientIdentifierType pit = getPrimaryPatientIdentiferType();
        for (PatientIdentifier piTmp : patient.getActiveIdentifiers()) {
            if (piTmp.getIdentifierType().getPatientIdentifierTypeId().equals(pit.getPatientIdentifierTypeId())
                    && piTmp.getIdentifier().equals(identifier)) {
                return true;

            }
        }
        return false;
    }

    public static Concept getBMIConcept() {
        Concept concept = null;
        String gp = Context.getAdministrationService().getGlobalProperty("concept.bmi");
        if (gp == null)
            throw new RuntimeException("you must set the global property concept.bmi");
        concept = Context.getConceptService().getConceptByUuid(gp);
        if (concept == null) {
            try {
                concept = Context.getConceptService().getConcept(Integer.valueOf(gp));
            } catch (Exception ex) {
                //pass
            }
        }
        if (concept == null) {
            throw new RuntimeException("Cannot find concept specified by global property concept.height");
        }
        return concept;
    }

    /**
     * wrapper for saveEncounter that ensures a Visit is created when registration encounter is created.
     * Needs to handle finding the visit for creation of vitals encounter also...
     * @param e
     * @return
     */
    public static Encounter saveEncounterAndVerifyVisit(Encounter e) {

        if (e.getVisit() == null
                && e.getEncounterType().equals(PrimaryCareBusinessLogic.getRegistrationEncounterType())) {
            Visit v = new Visit();
            v.setCreator(Context.getAuthenticatedUser());
            v.setDateCreated(new Date());
            v.setLocation(e.getLocation());
            v.setStartDatetime(e.getEncounterDatetime());

            //either the end of the day, or encounterDatetime + 8 hours, whichever is later.
            Calendar c = Calendar.getInstance();
            c.setTime(e.getEncounterDatetime());
            c.add(Calendar.HOUR, 8);
            //if visit is starting after 10 pm, set end time to start time plus 8 hours.  else 11:59:59 on that day is OK.
            v.setStopDatetime(getStartAndEndOfDay(e.getEncounterDatetime())[1].getTime()
                    - e.getEncounterDatetime().getTime() < 1000 * 60 * 60 * 2 ? c.getTime()
                            : getStartAndEndOfDay(e.getEncounterDatetime())[1]);

            v.setPatient(e.getPatient());
            v.setVisitType(getOutpatientVisitType());
            v.setVoided(false);
            //I don't know if encounter needs to be saved before visit is created, so...
            v.setEncounters(Collections.singleton(e));
            v = Context.getVisitService().saveVisit(v);
            e.setVisit(v);
        } else {
            //try to find existing visit
            List<Visit> vList = Context.getVisitService().getVisits(
                    Collections.singletonList(getOutpatientVisitType()), Collections.singletonList(e.getPatient()),
                    Collections.singleton(e.getLocation()), null, getStartAndEndOfDay(e.getEncounterDatetime())[0],
                    getStartAndEndOfDay(e.getEncounterDatetime())[1], null, null, null, true, false);
            if (vList != null && vList.size() > 0) {
                Visit v = vList.get(0);
                e.setVisit(v);
            }
            //e.setProvider(Context.getAuthenticatedUser());
        }
        //e.setProvider(Context.getAuthenticatedUser());
        return Context.getEncounterService().saveEncounter(e);

    }

}