package edu.ualberta.med.biobank.common.action.patient;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import org.hibernate.Session;
import edu.ualberta.med.biobank.common.action.Action;
import edu.ualberta.med.biobank.common.action.ActionContext;
import edu.ualberta.med.biobank.common.action.BooleanResult;
import edu.ualberta.med.biobank.common.action.exception.ActionException;
import edu.ualberta.med.biobank.common.permission.patient.PatientMergePermission;
import edu.ualberta.med.biobank.model.CollectionEvent;
import edu.ualberta.med.biobank.model.Log;
import edu.ualberta.med.biobank.model.Patient;
import edu.ualberta.med.biobank.model.Specimen;
/**
* Merge patient2 into patient1.
*
*/
public class PatientMergeAction implements Action<BooleanResult> {
private static final long serialVersionUID = 1L;
private Integer patient1Id;
private Integer patient2Id;
public PatientMergeAction(Integer patient1Id, Integer patient2Id) {
this.patient1Id = patient1Id;
this.patient2Id = patient2Id;
}
@Override
public boolean isAllowed(ActionContext context) throws ActionException {
return new PatientMergePermission(patient1Id, patient2Id).isAllowed(
context);
}
@Override
public BooleanResult run(ActionContext context) throws ActionException {
// FIXME add checks
// FIXME logging?
Patient patient1 = context.load(Patient.class, patient1Id);
Patient patient2 = context.load(Patient.class, patient2Id);
if (!patient1.getStudy().equals(patient2.getStudy())) {
throw new PatientMergeException(
PatientMergeException.ExceptionTypeEnum.STUDY);
}
Set<CollectionEvent> c1events =
patient1.getCollectionEvents();
Set<CollectionEvent> c2events =
patient2.getCollectionEvents();
if (!c2events.isEmpty()) {
boolean merged = false;
// for loop on a different list.
for (CollectionEvent c2event : new ArrayList<CollectionEvent>(
c2events)) {
for (CollectionEvent c1event : c1events) {
merged = merge(context.getSession(), c1event, c2event);
if (merged)
break;
}
if (!merged) {
// the collection has not been merged, so we can add it
// as a new collection event in patient1
c1events.add(c2event);
c2events.remove(c2event);
c2event.setPatient(patient1);
}
merged = false;
}
context.getSession().saveOrUpdate(patient1);
// flush so deleting the patient realizes its collection events have been removed.
context.getSession().flush();
context.getSession().delete(patient2);
// FIXME see how logs should be done properly...
Log logP2 = new Log();
logP2.setAction("merge"); //$NON-NLS-1$
logP2.setPatientNumber(patient2.getPnumber());
logP2.setDetails(patient2.getPnumber() + " --> " //$NON-NLS-1$
+ patient1.getPnumber());
logP2.setType("Patient"); //$NON-NLS-1$
context.getSession().save(logP2);
Log logP1 = new Log();
logP1.setAction("merge"); //$NON-NLS-1$
logP1.setPatientNumber(patient1.getPnumber());
logP1.setDetails(patient1.getPnumber() + " <-- " //$NON-NLS-1$
+ patient2.getPnumber());
logP1.setType("Patient"); //$NON-NLS-1$
context.getSession().save(logP1);
}
return new BooleanResult(true);
}
/**
* merge 2 collection event if their visitNumber are identical.
*
* @return true if a merge has been made, otherwise false
*/
private boolean merge(Session session, CollectionEvent c1event,
CollectionEvent c2event) {
if (c1event.getVisitNumber().equals(c2event.getVisitNumber())) {
Collection<Specimen> c2Origspecs =
c2event.getOriginalSpecimens();
Collection<Specimen> c2AllSpecs =
c2event.getAllSpecimens();
Collection<Specimen> c1OrigSpecs =
c1event.getOriginalSpecimens();
Collection<Specimen> c1AllSpecs =
c1event.getAllSpecimens();
for (Specimen spec : c2AllSpecs) {
if (c2Origspecs.contains(spec)) {
spec.setOriginalCollectionEvent(c1event);
c1OrigSpecs.add(spec);
}
spec.setCollectionEvent(c1event);
c1AllSpecs.add(spec);
}
// because of this and the move of specimens into another cevent, we
// can't use delete-orphan
session.delete(c2event);
return true;
}
return false;
}
}