package edu.ualberta.med.biobank.common.wrappers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import edu.ualberta.med.biobank.common.exception.BiobankCheckException;
import edu.ualberta.med.biobank.common.exception.BiobankException;
import edu.ualberta.med.biobank.common.formatters.DateFormatter;
import edu.ualberta.med.biobank.common.peer.CollectionEventPeer;
import edu.ualberta.med.biobank.common.peer.OriginInfoPeer;
import edu.ualberta.med.biobank.common.peer.PatientPeer;
import edu.ualberta.med.biobank.common.peer.ProcessingEventPeer;
import edu.ualberta.med.biobank.common.peer.ShipmentInfoPeer;
import edu.ualberta.med.biobank.common.peer.SpecimenPeer;
import edu.ualberta.med.biobank.common.wrappers.WrapperTransaction.TaskList;
import edu.ualberta.med.biobank.common.wrappers.base.CollectionEventBaseWrapper;
import edu.ualberta.med.biobank.common.wrappers.base.SpecimenBaseWrapper;
import edu.ualberta.med.biobank.common.wrappers.internal.EventAttrWrapper;
import edu.ualberta.med.biobank.common.wrappers.loggers.CollectionEventLogProvider;
import edu.ualberta.med.biobank.model.ActivityStatus;
import edu.ualberta.med.biobank.model.CollectionEvent;
import edu.ualberta.med.biobank.model.Specimen;
import gov.nih.nci.system.applicationservice.ApplicationException;
import gov.nih.nci.system.applicationservice.WritableApplicationService;
import gov.nih.nci.system.query.hibernate.HQLCriteria;
public class CollectionEventWrapper extends CollectionEventBaseWrapper {
private static final CollectionEventLogProvider LOG_PROVIDER =
new CollectionEventLogProvider();
private static final String HAS_SPECIMENS_MSG = Messages
.getString("CollectionEventWrapper.has_specimen_delete_msg"); //$NON-NLS-1$
private static final Collection<Property<?, ? super CollectionEvent>> UNIQUE_VISIT_NUMBER_PROPS;
static {
Collection<Property<?, ? super CollectionEvent>> tmp =
new ArrayList<Property<?, ? super CollectionEvent>>();
tmp.add(CollectionEventPeer.PATIENT.to(PatientPeer.ID));
tmp.add(CollectionEventPeer.VISIT_NUMBER);
UNIQUE_VISIT_NUMBER_PROPS = Collections.unmodifiableCollection(tmp);
};
private Map<String, StudyEventAttrWrapper> studyEventAttrMap;
private Map<String, EventAttrWrapper> eventAttrMap;
public CollectionEventWrapper(WritableApplicationService appService) {
super(appService);
}
public CollectionEventWrapper(WritableApplicationService appService,
CollectionEvent wrappedObject) {
super(appService, wrappedObject);
}
private void removeFromSpecimenCollections(
List<? extends SpecimenBaseWrapper> specimenCollection) {
// super.removeFromAllSpecimenCollection(specimenCollection); is not
// called because it will set the collectionEvent of specimens to null
// Since hibernate will check that it is not null, it is a problem.
// Specimens are deleted after that, so that's ok to keep the cevent
// reference
removeFromWrapperCollection(
CollectionEventPeer.ALL_SPECIMENS, specimenCollection);
removeFromWrapperCollection(
CollectionEventPeer.ORIGINAL_SPECIMENS,
specimenCollection);
}
private void removeFromSpecimenCollectionsWithCheck(
List<? extends SpecimenBaseWrapper> specimenCollection)
throws BiobankCheckException {
super.removeFromAllSpecimenCollectionWithCheck(specimenCollection);
super.removeFromOriginalSpecimenCollectionWithCheck(specimenCollection);
}
@Override
public void removeFromAllSpecimenCollection(
List<? extends SpecimenBaseWrapper> specCollection) {
removeFromSpecimenCollections(specCollection);
}
@Override
public void removeFromOriginalSpecimenCollection(
List<? extends SpecimenBaseWrapper> specCollection) {
removeFromSpecimenCollections(specCollection);
}
@Override
public void removeFromAllSpecimenCollectionWithCheck(
List<? extends SpecimenBaseWrapper> specCollection)
throws BiobankCheckException {
removeFromSpecimenCollectionsWithCheck(specCollection);
}
@Override
public void removeFromOriginalSpecimenCollectionWithCheck(
List<? extends SpecimenBaseWrapper> specCollection)
throws BiobankCheckException {
removeFromSpecimenCollectionsWithCheck(specCollection);
}
@Override
public void addToOriginalSpecimenCollection(
List<? extends SpecimenBaseWrapper> specs) {
super.addToOriginalSpecimenCollection(specs);
super.addToAllSpecimenCollection(specs);
}
@Override
public CollectionEventLogProvider getLogProvider() {
return LOG_PROVIDER;
}
private static final String COLLECTION_EVENTS_BY_WAYBILL_QRY = "from " //$NON-NLS-1$
+ CollectionEvent.class.getName()
+ " ce join ce." //$NON-NLS-1$
+ CollectionEventPeer.ORIGINAL_SPECIMENS
+ " as spcs join spcs." + SpecimenPeer.ORIGIN_INFO.getName() //$NON-NLS-1$
+ " as oi join oi." + OriginInfoPeer.SHIPMENT_INFO.getName() //$NON-NLS-1$
+ " as shipinfo where shipinfo." + ShipmentInfoPeer.WAYBILL + "=?"; //$NON-NLS-1$ //$NON-NLS-2$
// TODO: make sure that these count methods are actually correct if the
// memory contents have been altered...
public static List<CollectionEventWrapper> getCollectionEvents(
WritableApplicationService appService, String waybill)
throws ApplicationException {
HQLCriteria c = new HQLCriteria(COLLECTION_EVENTS_BY_WAYBILL_QRY,
Arrays.asList(new Object[] { waybill }));
List<CollectionEvent> raw = appService.query(c);
if (raw == null) {
return new ArrayList<CollectionEventWrapper>();
}
return wrapModelCollection(appService, raw,
CollectionEventWrapper.class);
}
private static final String COLLECTION_EVENTS_BY_DATE_RECEIVED_QRY =
"from " //$NON-NLS-1$
+ CollectionEvent.class.getName()
+ " ce join ce." //$NON-NLS-1$
+ CollectionEventPeer.ORIGINAL_SPECIMENS
+ " as spcs join spcs." //$NON-NLS-1$
+ SpecimenPeer.ORIGIN_INFO.getName()
+ " as oi join oi." //$NON-NLS-1$
+ OriginInfoPeer.SHIPMENT_INFO.getName()
+ " as shipinfo where shipinfo." + ShipmentInfoPeer.RECEIVED_AT + "=?"; //$NON-NLS-1$ //$NON-NLS-2$
public static List<CollectionEventWrapper> getCollectionEvents(
WritableApplicationService appService, Date dateReceived)
throws ApplicationException {
List<CollectionEvent> raw = appService.query(new HQLCriteria(
COLLECTION_EVENTS_BY_DATE_RECEIVED_QRY, Arrays
.asList(new Object[] { dateReceived })));
if (raw == null) {
return new ArrayList<CollectionEventWrapper>();
}
return wrapModelCollection(appService, raw,
CollectionEventWrapper.class);
}
public long getSourceSpecimensCount(boolean fast) throws BiobankException,
ApplicationException {
return getPropertyCount(
CollectionEventPeer.ORIGINAL_SPECIMENS, fast);
}
public long getAllSpecimensCount(boolean fast) throws BiobankException,
ApplicationException {
return getPropertyCount(CollectionEventPeer.ALL_SPECIMENS,
fast);
}
private static final String ALIQUOTED_SPECIMEN_COUNT_QRY =
"select count(spc) from " //$NON-NLS-1$
+ Specimen.class.getName()
+ " as spc where spc." //$NON-NLS-1$
+ Property.concatNames(SpecimenPeer.COLLECTION_EVENT,
CollectionEventPeer.ID) + "=? and spc." //$NON-NLS-1$
+ SpecimenPeer.PARENT_SPECIMEN.getName() + " is not null"; //$NON-NLS-1$
public long getAliquotedSpecimensCount(boolean fast)
throws BiobankException, ApplicationException {
long count = 0;
if (fast
&& !isInitialized(CollectionEventPeer.ORIGINAL_SPECIMENS)
&& !isInitialized(CollectionEventPeer.ALL_SPECIMENS)) {
HQLCriteria criteria = new HQLCriteria(
ALIQUOTED_SPECIMEN_COUNT_QRY,
Arrays.asList(new Object[] { getId() }));
count = getCountResult(appService, criteria);
} else {
count = getAllSpecimensCount(fast) - getSourceSpecimensCount(fast);
}
return count;
}
public List<SpecimenWrapper> getAliquotedSpecimenCollection(boolean sort) {
List<SpecimenWrapper> aliquotedSpecimens =
new ArrayList<SpecimenWrapper>(
getAllSpecimenCollection(sort));
aliquotedSpecimens.removeAll(getOriginalSpecimenCollection(false));
return aliquotedSpecimens;
}
private static String SOURCE_SPEC_IN_PROCESS_NOT_FLAGGED_QRY =
"select spec from " //$NON-NLS-1$
+ Specimen.class.getName()
+ " as spec where spec." //$NON-NLS-1$
+ Property.concatNames(SpecimenPeer.ORIGINAL_COLLECTION_EVENT,
CollectionEventPeer.ID)
+ " = ? and spec." //$NON-NLS-1$
+ Property.concatNames(SpecimenPeer.PROCESSING_EVENT,
ProcessingEventPeer.ID)
+ " = ? and spec.activityStatus != " + ActivityStatus.FLAGGED.getId(); //$NON-NLS-1$
/**
* source specimen that are in a process event
*
* @throws ApplicationException
*/
public List<SpecimenWrapper> getSourceSpecimenCollectionInProcessNotFlagged(
ProcessingEventWrapper pEvent, boolean sort)
throws ApplicationException {
List<Specimen> raw = appService.query(new HQLCriteria(
SOURCE_SPEC_IN_PROCESS_NOT_FLAGGED_QRY, Arrays.asList(new Object[] {
getId(), pEvent.getId() })));
if (raw == null) {
return new ArrayList<SpecimenWrapper>();
}
List<SpecimenWrapper> specs = wrapModelCollection(appService, raw,
SpecimenWrapper.class);
if (sort)
Collections.sort(specs);
return specs;
}
private Map<String, StudyEventAttrWrapper> getStudyEventAttrMap() {
if (studyEventAttrMap != null)
return studyEventAttrMap;
PatientWrapper patient = getPatient();
studyEventAttrMap = new HashMap<String, StudyEventAttrWrapper>();
if (patient != null && patient.getStudy() != null) {
Collection<StudyEventAttrWrapper> studyEventAttrCollection =
patient
.getStudy().getStudyEventAttrCollection();
if (studyEventAttrCollection != null) {
for (StudyEventAttrWrapper studyEventAttr : studyEventAttrCollection) {
studyEventAttrMap.put(studyEventAttr.getGlobalEventAttr()
.getLabel(),
studyEventAttr);
}
}
}
return studyEventAttrMap;
}
private Map<String, EventAttrWrapper> getEventAttrMap() {
getStudyEventAttrMap();
if (eventAttrMap != null)
return eventAttrMap;
eventAttrMap = new HashMap<String, EventAttrWrapper>();
List<EventAttrWrapper> pvAttrCollection = getEventAttrCollection(false);
if (pvAttrCollection != null) {
for (EventAttrWrapper pvAttr : pvAttrCollection) {
eventAttrMap.put(pvAttr.getStudyEventAttr()
.getGlobalEventAttr().getLabel(), pvAttr);
}
}
return eventAttrMap;
}
public String[] getEventAttrLabels() {
getEventAttrMap();
return eventAttrMap.keySet().toArray(new String[] {});
}
public String getEventAttrValue(String label) throws Exception {
getEventAttrMap();
EventAttrWrapper pvAttr = eventAttrMap.get(label);
if (pvAttr == null) {
StudyEventAttrWrapper studyEventAttr = studyEventAttrMap.get(label);
// make sure "label" is a valid study pv attr
if (studyEventAttr == null) {
throw new Exception("StudyEventAttr with label \"" + label //$NON-NLS-1$
+ "\" is invalid"); //$NON-NLS-1$
}
// not assigned yet so return null
return null;
}
return pvAttr.getValue();
}
public String getEventAttrTypeName(String label) throws Exception {
getEventAttrMap();
EventAttrWrapper pvAttr = eventAttrMap.get(label);
StudyEventAttrWrapper studyEventAttr = null;
if (pvAttr != null) {
studyEventAttr = pvAttr.getStudyEventAttr();
} else {
studyEventAttr = studyEventAttrMap.get(label);
// make sure "label" is a valid study pv attr
if (studyEventAttr == null) {
throw new Exception("StudyEventAttr withr label \"" + label //$NON-NLS-1$
+ "\" does not exist"); //$NON-NLS-1$
}
}
return studyEventAttr.getGlobalEventAttr().getEventAttrType().getName();
}
public String[] getEventAttrPermissible(String label) throws Exception {
getEventAttrMap();
EventAttrWrapper pvAttr = eventAttrMap.get(label);
StudyEventAttrWrapper studyEventAttr = null;
if (pvAttr != null) {
studyEventAttr = pvAttr.getStudyEventAttr();
} else {
studyEventAttr = studyEventAttrMap.get(label);
// make sure "label" is a valid study pv attr
if (studyEventAttr == null) {
throw new Exception("EventAttr for label \"" + label //$NON-NLS-1$
+ "\" does not exist"); //$NON-NLS-1$
}
}
String permissible = studyEventAttr.getPermissible();
if (permissible == null) {
return null;
}
return permissible.split(";"); //$NON-NLS-1$
}
/**
* Assigns a value to a patient visit attribute. The value is parsed for
* correctness.
*
* @param label The attribute's label.
* @param value The value to assign.
* @throws Exception when assigning a label of type "select_single" or
* "select_multiple" and the value is not one of the permissible
* ones.
* @throws NumberFormatException when assigning a label of type "number" and
* the value is not a valid double number.
* @throws ParseException when assigning a label of type "date_time" and the
* value is not a valid date and time.
* @see edu.ualberta.med.biobank
* .common.formatters.DateFormatter.DATE_TIME_FORMAT
*/
public void setEventAttrValue(String label, String value) throws Exception {
getEventAttrMap();
EventAttrWrapper pvAttr = eventAttrMap.get(label);
StudyEventAttrWrapper studyEventAttr = null;
if (pvAttr != null) {
studyEventAttr = pvAttr.getStudyEventAttr();
} else {
studyEventAttr = studyEventAttrMap.get(label);
if (studyEventAttr == null) {
throw new Exception("no StudyEventAttr found for label \"" //$NON-NLS-1$
+ label + "\""); //$NON-NLS-1$
}
}
if (ActivityStatus.ACTIVE != studyEventAttr.getActivityStatus()) {
throw new Exception("attribute for label \"" + label //$NON-NLS-1$
+ "\" is locked, changes not premitted"); //$NON-NLS-1$
}
if (value != null) {
// validate the value
value = value.trim();
if (value.length() > 0) {
String type =
studyEventAttr.getGlobalEventAttr().getEventAttrType()
.getName();
List<String> permissibleSplit = null;
if (EventAttrTypeEnum.SELECT_SINGLE.isSameType(type)
|| EventAttrTypeEnum.SELECT_MULTIPLE.isSameType(type)) {
String permissible = studyEventAttr.getPermissible();
if (permissible != null) {
permissibleSplit = Arrays
.asList(permissible.split(";")); //$NON-NLS-1$
}
}
if (EventAttrTypeEnum.SELECT_SINGLE.isSameType(type)) {
if (!permissibleSplit.contains(value)) {
throw new Exception("value " + value //$NON-NLS-1$
+ "is invalid for label \"" + label + "\""); //$NON-NLS-1$ //$NON-NLS-2$
}
} else if (EventAttrTypeEnum.SELECT_MULTIPLE.isSameType(type)) {
for (String singleVal : value.split(";")) { //$NON-NLS-1$
if (!permissibleSplit.contains(singleVal)) {
throw new Exception("value " + singleVal + " (" //$NON-NLS-1$ //$NON-NLS-2$
+ value + ") is invalid for label \"" + label //$NON-NLS-1$
+ "\""); //$NON-NLS-1$
}
}
} else if (EventAttrTypeEnum.NUMBER.isSameType(type)) {
Double.parseDouble(value);
} else if (EventAttrTypeEnum.DATE_TIME.isSameType(type)) {
DateFormatter.dateFormatter.parse(value);
} else if (EventAttrTypeEnum.TEXT.isSameType(type)) {
// do nothing
} else {
throw new Exception("type \"" + type + "\" not tested"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
if (pvAttr == null) {
pvAttr = new EventAttrWrapper(appService);
pvAttr.setCollectionEvent(this);
pvAttr.setStudyEventAttr(studyEventAttr);
EventAttrWrapper oldValue = eventAttrMap.put(label, pvAttr);
if (oldValue != null) {
removeFromEventAttrCollection(Arrays.asList(oldValue));
}
addToEventAttrCollection(Arrays.asList(pvAttr));
}
pvAttr.setValue(value);
}
@Override
public void resetInternalFields() {
eventAttrMap = null;
studyEventAttrMap = null;
}
@Override
public int compareTo(ModelWrapper<CollectionEvent> wrapper) {
if (wrapper instanceof CollectionEventWrapper) {
Integer nber1 = wrappedObject.getVisitNumber();
Integer nber2 = wrapper.wrappedObject.getVisitNumber();
if (nber1 != null && nber2 != null) {
return nber1.compareTo(nber2);
}
}
return 0;
}
public static Integer getNextVisitNumber(
WritableApplicationService appService, CollectionEventWrapper cevent)
throws Exception {
HQLCriteria c = new HQLCriteria("select max(ce.visitNumber) from " //$NON-NLS-1$
+ CollectionEvent.class.getName() + " ce where ce.patient.id=?", //$NON-NLS-1$
Arrays.asList(cevent.getPatient().getId()));
List<Object> result = appService.query(c);
if (result == null || result.size() == 0 || result.get(0) == null)
return 1;
return (Integer) result.get(0) + 1;
}
@Deprecated
@Override
protected void addPersistTasks(TaskList tasks) {
tasks.add(check().notNull(CollectionEventPeer.VISIT_NUMBER));
tasks.add(check().unique(UNIQUE_VISIT_NUMBER_PROPS));
tasks.deleteRemoved(this, CollectionEventPeer.ALL_SPECIMENS);
tasks.deleteRemoved(this,
CollectionEventPeer.ORIGINAL_SPECIMENS);
super.addPersistTasks(tasks);
}
@Deprecated
@Override
protected void addDeleteTasks(TaskList tasks) {
tasks.add(check().empty(CollectionEventPeer.ALL_SPECIMENS,
HAS_SPECIMENS_MSG));
super.addDeleteTasks(tasks);
}
@Deprecated
public void merge(CollectionEventWrapper p2event) throws Exception {
List<SpecimenWrapper> ospecs = p2event
.getOriginalSpecimenCollection(false);
List<SpecimenWrapper> aspecs = p2event.getAllSpecimenCollection(false);
for (SpecimenWrapper aspec : aspecs) {
if (ospecs.contains(aspec))
aspec.setOriginalCollectionEvent(this);
aspec.setCollectionEvent(this);
aspec.persist();
}
p2event.delete();
}
/**
* return true if the user can delete this object
*/
@Override
public boolean canDelete(UserWrapper user, CenterWrapper<?> center,
StudyWrapper study) {
return super.canDelete(user, center, study)
&& (getPatient() == null || getPatient().getStudy() == null
|| user.getCurrentWorkingCenter() == null || user
.getCurrentWorkingCenter().getStudyCollection()
.contains(getPatient().getStudy()));
}
/**
* return true if the user can edit this object
*/
@Override
public boolean canUpdate(UserWrapper user, CenterWrapper<?> center,
StudyWrapper study) {
return super.canUpdate(user, center, study)
&& (getPatient() == null || getPatient().getStudy() == null
|| user.getCurrentWorkingCenter() == null || user
.getCurrentWorkingCenter().getStudyCollection()
.contains(getPatient().getStudy()));
}
public Date getMinSourceSpecimenDate() {
Date min = null;
for (SpecimenWrapper spec : getOriginalSpecimenCollection(false))
min = (min != null && min.before(spec.getCreatedAt())) ? min : spec
.getCreatedAt();
return min;
}
}