package edu.ualberta.med.biobank.common.wrappers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import edu.ualberta.med.biobank.common.exception.BiobankCheckException;
import edu.ualberta.med.biobank.common.exception.BiobankException;
import edu.ualberta.med.biobank.common.exception.BiobankQueryResultSizeException;
import edu.ualberta.med.biobank.common.peer.AliquotedSpecimenPeer;
import edu.ualberta.med.biobank.common.peer.ClinicPeer;
import edu.ualberta.med.biobank.common.peer.CollectionEventPeer;
import edu.ualberta.med.biobank.common.peer.ContactPeer;
import edu.ualberta.med.biobank.common.peer.PatientPeer;
import edu.ualberta.med.biobank.common.peer.StudyPeer;
import edu.ualberta.med.biobank.common.wrappers.WrapperTransaction.TaskList;
import edu.ualberta.med.biobank.common.wrappers.base.StudyBaseWrapper;
import edu.ualberta.med.biobank.common.wrappers.internal.EventAttrTypeWrapper;
import edu.ualberta.med.biobank.model.ActivityStatus;
import edu.ualberta.med.biobank.model.AliquotedSpecimen;
import edu.ualberta.med.biobank.model.CollectionEvent;
import edu.ualberta.med.biobank.model.Contact;
import edu.ualberta.med.biobank.model.Patient;
import edu.ualberta.med.biobank.model.SpecimenType;
import edu.ualberta.med.biobank.model.Study;
import gov.nih.nci.system.applicationservice.ApplicationException;
import gov.nih.nci.system.applicationservice.WritableApplicationService;
import gov.nih.nci.system.query.hibernate.HQLCriteria;
public class StudyWrapper extends StudyBaseWrapper {
private Map<String, StudyEventAttrWrapper> studyEventAttrMap;
public StudyWrapper(WritableApplicationService appService,
Study wrappedObject) {
super(appService, wrappedObject);
}
public StudyWrapper(WritableApplicationService appService) {
super(appService);
}
protected Collection<StudyEventAttrWrapper> getStudyEventAttrCollection() {
Map<String, StudyEventAttrWrapper> map = getStudyEventAttrMap();
if (map == null) {
return null;
}
return map.values();
}
private Map<String, StudyEventAttrWrapper> getStudyEventAttrMap() {
if (studyEventAttrMap != null)
return studyEventAttrMap;
studyEventAttrMap = new HashMap<String, StudyEventAttrWrapper>();
List<StudyEventAttrWrapper> eventAttrList =
getStudyEventAttrCollection(false);
// StudyEventAttrWrapper.getStudyEventAttrCollection(this);
for (StudyEventAttrWrapper studyEventAttr : eventAttrList) {
studyEventAttrMap.put(studyEventAttr.getGlobalEventAttr()
.getLabel(), studyEventAttr);
}
return studyEventAttrMap;
}
private void updateStudyEventAttrCollection() {
if (studyEventAttrMap != null) {
List<StudyEventAttrWrapper> allStudyEventAttrWrappers =
new ArrayList<StudyEventAttrWrapper>();
for (StudyEventAttrWrapper ss : studyEventAttrMap.values()) {
allStudyEventAttrWrappers.add(ss);
}
setWrapperCollection(StudyPeer.STUDY_EVENT_ATTRS,
allStudyEventAttrWrappers);
}
}
public String[] getStudyEventAttrLabels() {
getStudyEventAttrMap();
return studyEventAttrMap.keySet().toArray(new String[] {});
}
public StudyEventAttrWrapper getStudyEventAttr(String label)
throws Exception {
getStudyEventAttrMap();
StudyEventAttrWrapper studyEventAttr = studyEventAttrMap.get(label);
if (studyEventAttr == null) {
throw new Exception("StudyEventAttr with label \"" + label //$NON-NLS-1$
+ "\" is invalid"); //$NON-NLS-1$
}
return studyEventAttr;
}
public EventAttrTypeEnum getStudyEventAttrType(String label)
throws Exception {
return EventAttrTypeEnum.getEventAttrType(getStudyEventAttr(label)
.getGlobalEventAttr().getEventAttrType().getName());
}
/**
* Retrieves the permissible values for a patient visit attribute.
*
* @param label The label to be used by the attribute.
* @return Semicolon separated list of allowed values.
* @throws Exception hrown if there is no patient visit information item
* with the label specified.
*/
public String[] getStudyEventAttrPermissible(String label) throws Exception {
String joinedPossibleValues = getStudyEventAttr(label).getPermissible();
if (joinedPossibleValues == null)
return null;
return joinedPossibleValues.split(";"); //$NON-NLS-1$
}
/**
* Retrieves the activity status for a patient visit attribute. If locked,
* patient visits will not allow information to be saved for this attribute.
*
* @param label
* @return True if the attribute is locked. False otherwise.
* @throws Exception
*/
public ActivityStatus getStudyEventAttrActivityStatus(String label)
throws Exception {
return getStudyEventAttr(label).getActivityStatus();
}
/**
* Assigns patient visit attributes to be used for this study.
*
* @param label The label used for the attribute.
* @param type The string corresponding to the type of the attribute.
* @param permissibleValues If the attribute is of type "select_single" or
* "select_multiple" this array contains the possible values as a
* String array. Otherwise, this parameter should be set to null.
*
* @throws Exception Thrown if the attribute type does not exist.
*/
public void setStudyEventAttr(String label, EventAttrTypeEnum type,
String[] permissibleValues) throws Exception {
Map<String, EventAttrTypeWrapper> EventAttrTypeMap =
EventAttrTypeWrapper
.getAllEventAttrTypesMap(appService);
EventAttrTypeWrapper EventAttrType = EventAttrTypeMap.get(type
.getName());
if (EventAttrType == null) {
throw new Exception("the pv attribute type \"" + type //$NON-NLS-1$
+ "\" does not exist"); //$NON-NLS-1$
}
StudyEventAttrWrapper studyEventAttr = getStudyEventAttrMap()
.get(label);
if (type.isSelectType()) {
// type has permissible values
if ((studyEventAttr == null) && (permissibleValues == null)) {
// nothing to do
return;
}
if ((studyEventAttr != null) && (permissibleValues == null)) {
deleteStudyEventAttr(label);
return;
}
}
if (studyEventAttr == null) {
// does not yet exist
studyEventAttr = new StudyEventAttrWrapper(appService);
studyEventAttr.getGlobalEventAttr().setLabel(label);
studyEventAttr.getGlobalEventAttr().setEventAttrType(EventAttrType);
studyEventAttr.setStudy(this);
}
studyEventAttr.setActivityStatus(ActivityStatus.ACTIVE);
studyEventAttr.setPermissible(StringUtils.join(permissibleValues, ';'));
studyEventAttrMap.put(label, studyEventAttr);
updateStudyEventAttrCollection();
}
/**
* Assigns patient visit attributes to be used for this study.
*
* @param label The label to be used for the attribute.
* @param type The string corresponding to the type of the attribute.
*
* @throws Exception Thrown if there is no possible patient visit with the
* label specified.
*/
public void setStudyEventAttr(String label, EventAttrTypeEnum type)
throws Exception {
setStudyEventAttr(label, type, null);
}
/**
* Used to enable or disable the locked status of a patient visit attribute.
* If an attribute is locked the patient visits will not allow information
* to be saved for this attribute.
*
* @param label The label used for the attribute. Note: the label must
* already exist.
* @param enable True to enable the lock, false otherwise.
*
* @throws Exception if attribute with label does not exist.
*/
public void setStudyEventAttrActivityStatus(String label,
ActivityStatus activityStatus) throws Exception {
getStudyEventAttrMap();
StudyEventAttrWrapper studyEventAttr = getStudyEventAttr(label);
studyEventAttr.setActivityStatus(activityStatus);
}
/**
* Used to delete a patient visit attribute.
*
* @param label The label used for the attribute.
* @throws Exception if attribute with label does not exist.
*/
public void deleteStudyEventAttr(String label) throws Exception {
getStudyEventAttrMap();
StudyEventAttrWrapper studyEventAttr = getStudyEventAttr(label);
if (studyEventAttr.isUsedByCollectionEvents()) {
throw new BiobankCheckException("StudyEventAttr with label \"" //$NON-NLS-1$
+ label + "\" is in use by patient visits"); //$NON-NLS-1$
}
studyEventAttrMap.remove(label);
updateStudyEventAttrCollection();
}
public List<ClinicWrapper> getClinicCollection() {
// unique clinics
List<ContactWrapper> contacts = getContactCollection(false);
HashSet<ClinicWrapper> clinicWrappers = new HashSet<ClinicWrapper>();
if (contacts != null)
for (ContactWrapper contact : contacts) {
clinicWrappers.add(contact.getClinic());
}
return Arrays.asList(clinicWrappers.toArray(new ClinicWrapper[] {}));
}
@SuppressWarnings("nls")
private static final String PATIENT_QRY = "select patients from "
+ Study.class.getName() + " as study inner join study."
+ StudyPeer.PATIENTS.getName()
+ " as patients where patients." + PatientPeer.PNUMBER.getName()
+ " = ? and study." + StudyPeer.ID.getName() + " = ?";
public PatientWrapper getPatient(String patientNumber) throws Exception {
HQLCriteria criteria = new HQLCriteria(PATIENT_QRY,
Arrays.asList(new Object[] { patientNumber, getId() }));
List<Patient> result = appService.query(criteria);
if (result.size() > 1) {
throw new BiobankQueryResultSizeException();
} else if (result.size() == 1) {
return new PatientWrapper(appService, result.get(0));
}
return null;
}
public boolean hasPatients() throws ApplicationException, BiobankException {
return getPatientCount(true) > 0;
}
public long getPatientCount(boolean fast) throws ApplicationException,
BiobankException {
return getPropertyCount(StudyPeer.PATIENTS, fast);
}
@Override
public int compareTo(ModelWrapper<Study> wrapper) {
if (wrapper instanceof StudyWrapper) {
String nameShort1 = getNameShort();
String nameShort2 = wrapper.wrappedObject.getNameShort();
int compare = 0;
if ((nameShort1 != null) && (nameShort2 != null)) {
compare = nameShort1.compareTo(nameShort2);
}
if (compare == 0) {
String name1 = getName();
String name2 = wrapper.wrappedObject.getName();
return name1.compareTo(name2);
}
return compare;
}
return 0;
}
@SuppressWarnings("nls")
public static final String IS_LINKED_TO_CLINIC_QRY =
"select count(clinics) from "
+ Contact.class.getName()
+ " as contacts join contacts."
+ ContactPeer.CLINIC.getName()
+ " as clinics where contacts."
+ Property.concatNames(ContactPeer.STUDIES, StudyPeer.ID)
+ " = ? and clinics." + ClinicPeer.ID.getName() + " = ?";
/**
* return true if this study is linked to the given clinic (through
* contacts)
*/
public boolean isLinkedToClinic(ClinicWrapper clinic)
throws ApplicationException, BiobankException {
HQLCriteria c = new HQLCriteria(IS_LINKED_TO_CLINIC_QRY,
Arrays.asList(new Object[] { getId(), clinic.getId() }));
return getCountResult(appService, c) != 0;
}
@Override
public void resetInternalFields() {
studyEventAttrMap = null;
}
@SuppressWarnings("nls")
public static final String ALL_STUDIES_QRY = "from "
+ Study.class.getName();
public static List<StudyWrapper> getAllStudies(
WritableApplicationService appService) throws ApplicationException {
HQLCriteria c = new HQLCriteria(ALL_STUDIES_QRY);
return ModelWrapper.wrapModelCollection(appService,
appService.query(c), StudyWrapper.class);
}
@SuppressWarnings("nls")
public static final String COUNT_QRY = "select count (*) from "
+ Study.class.getName();
public static long getCount(WritableApplicationService appService)
throws BiobankException, ApplicationException {
return getCountResult(appService, new HQLCriteria(COUNT_QRY));
}
@Override
public String toString() {
return getName();
}
@SuppressWarnings("nls")
private static final String COLLECTION_EVENT_COUNT_QRY =
"select count(distinct ce) from "
+ CollectionEvent.class.getName()
+ " as ce where ce."
+ Property.concatNames(CollectionEventPeer.PATIENT,
PatientPeer.STUDY,
StudyPeer.ID) + "=?";
public long getCollectionEventCount() throws ApplicationException,
BiobankException {
HQLCriteria c = new HQLCriteria(COLLECTION_EVENT_COUNT_QRY,
Arrays.asList(new Object[] { getId() }));
return getCountResult(appService, c);
}
@Override
public boolean canUpdate(UserWrapper user, CenterWrapper<?> center,
StudyWrapper study) {
return super.canUpdate(user, center, study);
}
@Deprecated
@Override
protected void addPersistTasks(TaskList tasks) {
tasks.add(check().notNull(StudyPeer.NAME));
tasks.add(check().notNull(StudyPeer.NAME_SHORT));
tasks.add(check().unique(StudyPeer.NAME));
tasks.add(check().unique(StudyPeer.NAME_SHORT));
tasks.deleteRemoved(this, StudyPeer.STUDY_EVENT_ATTRS);
tasks.deleteRemoved(this, StudyPeer.SOURCE_SPECIMENS);
tasks.deleteRemoved(this, StudyPeer.ALIQUOTED_SPECIMENS);
super.addPersistTasks(tasks);
tasks.persistAdded(this, StudyPeer.STUDY_EVENT_ATTRS);
tasks.persistAdded(this, StudyPeer.SOURCE_SPECIMENS);
tasks.persistAdded(this, StudyPeer.ALIQUOTED_SPECIMENS);
}
@Deprecated
@Override
protected void addDeleteTasks(TaskList tasks) {
tasks.add(check().empty(StudyPeer.PATIENTS));
tasks.delete(this, StudyPeer.STUDY_EVENT_ATTRS);
tasks.delete(this, StudyPeer.SOURCE_SPECIMENS);
tasks.delete(this, StudyPeer.ALIQUOTED_SPECIMENS);
super.addDeleteTasks(tasks);
}
// public List<PatientWrapper> getPatientCollection(boolean sort) {
// return HQLAccessor.getCachedCollection(this, PatientPeer.STUDY,
// Patient.class, PatientWrapper.class, sort);
// }
@SuppressWarnings("nls")
private static final String ACTIVE_ALIQUOTED_SPECIMENS_TYPE_QRY =
"select aspec."
+ AliquotedSpecimenPeer.SPECIMEN_TYPE.getName()
+ " from "
+ AliquotedSpecimen.class.getName()
+ " as aspec where aspec."
+ Property.concatNames(AliquotedSpecimenPeer.STUDY, StudyPeer.ID)
+ " = ? and aspec.activityStatus = "
+ ActivityStatus.ACTIVE.getId();
public List<SpecimenTypeWrapper> getAuthorizedActiveAliquotedTypes(
List<SpecimenTypeWrapper> authorizedTypes) throws ApplicationException {
List<SpecimenType> raw = appService.query(new HQLCriteria(
ACTIVE_ALIQUOTED_SPECIMENS_TYPE_QRY, Arrays
.asList(new Object[] { getId() })));
if (raw == null) {
return new ArrayList<SpecimenTypeWrapper>();
}
List<SpecimenTypeWrapper> studiesAliquotedTypes =
new ArrayList<SpecimenTypeWrapper>();
for (SpecimenType st : raw) {
SpecimenTypeWrapper type = new SpecimenTypeWrapper(appService, st);
if (authorizedTypes == null || authorizedTypes.contains(type)) {
studiesAliquotedTypes.add(type);
}
}
return studiesAliquotedTypes;
}
}