package edu.gatech.i3l.fhir.dstu2.entities; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import javax.persistence.Access; import javax.persistence.AccessType; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EntityManager; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.SequenceGenerator; import javax.persistence.Table; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import org.hibernate.envers.Audited; import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.WebApplicationContext; import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt; import ca.uhn.fhir.model.dstu2.composite.CodingDt; import ca.uhn.fhir.model.dstu2.composite.HumanNameDt; import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt; import ca.uhn.fhir.model.dstu2.resource.Patient; import ca.uhn.fhir.model.dstu2.resource.Practitioner; import ca.uhn.fhir.model.dstu2.resource.Practitioner.PractitionerRole; import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum; import ca.uhn.fhir.model.primitive.DateDt; import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.StringDt; import edu.gatech.i3l.fhir.jpa.dao.BaseFhirDao; import edu.gatech.i3l.fhir.jpa.entity.BaseResourceEntity; import edu.gatech.i3l.fhir.jpa.entity.IResourceEntity; import edu.gatech.i3l.omop.mapping.OmopConceptMapping; @Entity @Table(name="provider") @Inheritance(strategy=InheritanceType.JOINED) @Audited public class Provider extends BaseResourceEntity { public static final String RESOURCE_TYPE = "Practitioner"; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="provider_seq_gen") @SequenceGenerator(name="provider_seq_gen", sequenceName="provider_id_seq", allocationSize=1) @Column(name="provider_id") @Access(AccessType.PROPERTY) private Long id; @Column(name="provider_name") private String providerName; @Column(name="npi") private String npi; @Column(name="dea") private String dea; @ManyToOne(cascade={CascadeType.MERGE}) @JoinColumn(name="specialty_concept_id") private Concept specialtyConcept; @ManyToOne(cascade={CascadeType.ALL}) @JoinColumn(name="care_site_id") private CareSite careSite; @Column(name="year_of_birth") private Integer yearOfBirth; @ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.MERGE}) @JoinColumn(name="gender_concept_id") private Concept genderConcept; @Column(name="provider_source_value") private String providerSourceValue; @Column(name="specialty_source_value") private String specialtySourceValue; @ManyToOne(fetch=FetchType.LAZY,cascade={CascadeType.MERGE}) @JoinColumn(name="specialty_source_concept_id") private Concept specialtySourceConcept; @Column(name="gender_source_value") private String genderSourceValue; @ManyToOne(fetch=FetchType.LAZY,cascade={CascadeType.MERGE}) @JoinColumn(name="gender_source_concept_id") private Concept genderSourceConcept; public Provider() { super(); } public Provider(Long id, String providerName, String npi, String dea, Concept specialtyConcept, CareSite careSite, Integer yearOfBirth, Concept genderConcept, String providerSourceValue, String specialtySourceValue, Concept specialtySourceConcept, String genderSourceValue, Concept genderSourceConcept) { this.id = id; this.providerName = providerName; this.npi = npi; this.dea = dea; this.specialtyConcept = specialtyConcept; this.careSite = careSite; this.yearOfBirth = yearOfBirth; this.genderConcept = genderConcept; this.providerSourceValue = providerSourceValue; this.specialtySourceValue = specialtySourceValue; this.specialtySourceConcept = specialtySourceConcept; this.genderSourceValue = genderSourceValue; this.genderSourceConcept = genderSourceConcept; } @Override public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getProviderName() { return providerName; } public void setProviderName(String providerName) { this.providerName = providerName; } public String getNpi() { return npi; } public void setNpi(String npi) { this.npi = npi; } public String getDea() { return dea; } public void setDea(String dea) { this.dea = dea; } public Concept getSpecialtyConcept() { return specialtyConcept; } public void setSpecialtyConcept(Concept specialtyConcept) { this.specialtyConcept = specialtyConcept; } public CareSite getCareSite() { return careSite; } public void setCareSite(CareSite careSite) { this.careSite = careSite; } public Integer getYearOfBirth() { return yearOfBirth; } public void setYearOfBirth(Integer yearOfBirth) { this.yearOfBirth = yearOfBirth; } public String getProviderSourceValue() { return providerSourceValue; } public void setProviderSourceValue(String providerSourceValue) { this.providerSourceValue = providerSourceValue; } public String getSpecialtySourceValue() { return specialtySourceValue; } public void setSpecialtySourceValue(String specialtySourceValue) { this.specialtySourceValue = specialtySourceValue; } @Override public Practitioner getRelatedResource() { Practitioner practitioner = new Practitioner(); practitioner.setId(this.getIdDt()); if (this.getProviderName() != null) { HumanNameDt humanName = new HumanNameDt(); String[] names = this.getProviderName().trim().split(","); List<StringDt> familyNames = new ArrayList<StringDt>(); List<StringDt> givenNames = new ArrayList<StringDt>(); List<StringDt> suffixes = new ArrayList<StringDt>(); if (names.length > 1) { if (names.length > 2) { familyNames.add(new StringDt(names[0].trim())); suffixes.add(new StringDt(names[names.length-1].trim())); for (int i=1; i < names.length-1; i++) { String[] subnames = names[i].trim().split(" "); for (int j=0; j < subnames.length; j++) { givenNames.add(new StringDt(subnames[j].trim())); } } } else { suffixes.add(new StringDt(names[1].trim())); String[] subnames = names[0].trim().split(" "); familyNames.add(new StringDt(subnames[subnames.length-1])); for (int i=0; i < subnames.length-1; i++) { givenNames.add(new StringDt(subnames[i].trim())); } } } else { names = this.getProviderName().trim().split(" "); if (names.length > 0) { familyNames.add(new StringDt(names[names.length-1].trim())); for (int i=0; i < names.length-1; i++) { givenNames.add(new StringDt(names[i].trim())); } } else { familyNames.add(new StringDt(this.getProviderName().trim())); } } humanName.setFamily(familyNames); humanName.setGiven(givenNames); humanName.setSuffix(suffixes); practitioner.setName(humanName); } PractitionerRole practitionerRole = new PractitionerRole(); if (careSite != null) { ResourceReferenceDt organizationResource = new ResourceReferenceDt(careSite.getIdDt()); // List<ResourceReferenceDt> listResourceRef = new ArrayList<ResourceReferenceDt>(); // listResourceRef.add(organizationResource); organizationResource.setDisplay(careSite.getCareSiteName()); practitionerRole.setManagingOrganization(organizationResource); } if (specialtyConcept != null && specialtyConcept.getId() > 0L) { String systemUriString = specialtyConcept.getVocabulary().getVocabularyReference(); String displayString = specialtyConcept.getName(); String codeString = specialtyConcept.getConceptCode(); CodeableConceptDt specialtyCode = new CodeableConceptDt(systemUriString, codeString); specialtyCode.getCodingFirstRep().setDisplay(displayString); List<CodeableConceptDt> listSpecialtyCode = new ArrayList<CodeableConceptDt>(); listSpecialtyCode.add(specialtyCode); practitionerRole.setSpecialty(listSpecialtyCode); } List<PractitionerRole> listPracRole = new ArrayList<PractitionerRole>(); listPracRole.add(practitionerRole); practitioner.setPractitionerRole(listPracRole); if (this.genderConcept != null){ AdministrativeGenderEnum admGender = null;//TODO check if DSTU2 uses values coherent with this enum String gName = this.genderConcept.getName(); AdministrativeGenderEnum[] values = AdministrativeGenderEnum.values(); for (int i = 0; i < values.length; i++) { if(gName.equalsIgnoreCase(values[i].getCode())){ admGender = values[i]; break; } } practitioner.setGender(admGender); } if (this.yearOfBirth != null) { Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, this.yearOfBirth); practitioner.setBirthDate(new DateDt(cal.getTime())); } return practitioner; } @Override public String getResourceType() { return RESOURCE_TYPE; } @Override public FhirVersionEnum getFhirVersion() { return FhirVersionEnum.DSTU2; } @Override public InstantDt getUpdated() { // TODO Auto-generated method stub return null; } @Override public IResourceEntity constructEntityFromResource(IResource resource) { Practitioner practitioner = (Practitioner) resource; HumanNameDt humanName = practitioner.getName(); String familyName = humanName.getFamilyAsSingleString().replace(" ", "_"); String givenName = humanName.getGivenAsSingleString(); String suffixName = humanName.getSuffixAsSingleString(); String omopName = givenName+" "+familyName+", "+suffixName; this.setProviderName(omopName); this.genderConcept = new Concept(); this.genderConcept.setId(OmopConceptMapping.getInstance().get(practitioner.getGender().substring(0, 1), OmopConceptMapping.GENDER)); Date birthDate = practitioner.getBirthDate(); if (birthDate != null) { Calendar cal = Calendar.getInstance(); cal.setTime(birthDate); int year = cal.get(Calendar.YEAR); this.setYearOfBirth(year); } PractitionerRole role = practitioner.getPractitionerRoleFirstRep(); if (role != null) { // Search this organization from care_site table. WebApplicationContext myAppCtx = ContextLoaderListener.getCurrentWebApplicationContext(); EntityManager entityManager = myAppCtx.getBean("myBaseDao", BaseFhirDao.class).getEntityManager(); ResourceReferenceDt org = role.getManagingOrganization(); if (org != null) { StringDt orgDisplay = org.getDisplay(); if (orgDisplay != null) { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<CareSite> criteria = builder.createQuery(CareSite.class); Root<CareSite> from = criteria.from(CareSite.class); criteria.select(from).where( builder.equal(from.get("careSiteName"), orgDisplay.getValueAsString()) ); TypedQuery<CareSite> query = entityManager.createQuery(criteria); List<CareSite> results = query.getResultList(); CareSite careSite = null; if (results.size() > 0) { careSite = results.get(0); } else { careSite = new CareSite(); careSite.setCareSiteName(orgDisplay.getValueAsString()); } this.setCareSite(careSite); } } CodeableConceptDt specialty = role.getSpecialtyFirstRep(); if (specialty != null) { CodingDt specialtyCode = specialty.getCodingFirstRep(); String specialtyDisplay = specialtyCode.getDisplay(); if (specialtyDisplay != null && !specialtyDisplay.isEmpty()) { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<Concept> criteria = builder.createQuery(Concept.class); Root<Concept> from = criteria.from(Concept.class); criteria.select(from).where( builder.equal(from.get("conceptClassId"), OmopConceptMapping.SPECIALTY), builder.equal(from.get("name"), specialtyDisplay) ); TypedQuery<Concept> query = entityManager.createQuery(criteria); List<Concept> results = query.getResultList(); Concept specialtyConcept = null; if (results.size() > 0) { specialtyConcept = results.get(0); this.setSpecialtyConcept(specialtyConcept); } else { specialtyConcept = new Concept(); specialtyConcept.setId(0L); } this.setSpecialtyConcept(specialtyConcept); } } } return this; } public static Provider searchAndUpdate(ResourceReferenceDt resourceRef) { if (resourceRef == null) return null; // See if this exists. Provider provider = (Provider) OmopConceptMapping.getInstance().loadEntityById(Provider.class, resourceRef.getReference().getIdPartAsLong()); if (provider != null) { return provider; } else { // Check source column to see if we have received this before. provider = (Provider) OmopConceptMapping.getInstance() .loadEntityBySource(Provider.class, "Provider", "providerSourceValue", resourceRef.getReference().getIdPart()); if (provider != null) { return provider; } else { provider = new Provider(); provider.setProviderSourceValue(resourceRef.getReference().getIdPart()); if (resourceRef.getDisplay() != null) provider.setProviderName(resourceRef.getDisplay().toString()); return provider; } } } @Override public String translateSearchParam(String chain) { String translatedChain = ""; if(chain.isEmpty()) return translatedChain; String head = ""; if(chain.contains(".")){ head = chain.substring(0, chain.indexOf(".")); chain = chain.substring(chain.indexOf(".") + 1, chain.length()); } else { head = chain; } switch (head) { case Patient.SP_ORGANIZATION: translatedChain = translatedChain.concat("careSite"); break; default: break; } return translatedChain; } }