package edu.ualberta.med.biobank.common.action.study;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.ualberta.med.biobank.common.action.Action;
import edu.ualberta.med.biobank.common.action.ActionContext;
import edu.ualberta.med.biobank.common.action.ActionResult;
import edu.ualberta.med.biobank.common.action.IdResult;
import edu.ualberta.med.biobank.common.action.comment.CommentUtil;
import edu.ualberta.med.biobank.common.action.exception.ActionCheckException;
import edu.ualberta.med.biobank.common.action.exception.ActionException;
import edu.ualberta.med.biobank.common.permission.Permission;
import edu.ualberta.med.biobank.common.permission.study.StudyCreatePermission;
import edu.ualberta.med.biobank.common.permission.study.StudyUpdatePermission;
import edu.ualberta.med.biobank.common.util.SetDifference;
import edu.ualberta.med.biobank.model.ActivityStatus;
import edu.ualberta.med.biobank.model.AliquotedSpecimen;
import edu.ualberta.med.biobank.model.Comment;
import edu.ualberta.med.biobank.model.Contact;
import edu.ualberta.med.biobank.model.GlobalEventAttr;
import edu.ualberta.med.biobank.model.SourceSpecimen;
import edu.ualberta.med.biobank.model.SpecimenType;
import edu.ualberta.med.biobank.model.Study;
import edu.ualberta.med.biobank.model.StudyEventAttr;
public class StudySaveAction implements Action<IdResult> {
private static final long serialVersionUID = 1L;
private static Logger log = LoggerFactory.getLogger(StudySaveAction.class
.getName());
public static class SourceSpecimenSaveInfo implements ActionResult {
private static final long serialVersionUID = 1L;
public Integer id = null;
public Boolean needOriginalVolume;
public Integer specimenTypeId;
public SourceSpecimenSaveInfo() {
}
public SourceSpecimenSaveInfo(SourceSpecimen sourceSpecimen) {
this.id = sourceSpecimen.getId();
this.needOriginalVolume = sourceSpecimen.getNeedOriginalVolume();
this.specimenTypeId = sourceSpecimen.getSpecimenType().getId();
}
public SourceSpecimen populateSourceSpecimen(Study study,
SourceSpecimen sourceSpecimen,
SpecimenType specimenType) {
sourceSpecimen.setId(this.id);
sourceSpecimen.setNeedOriginalVolume(this.needOriginalVolume);
sourceSpecimen.setSpecimenType(specimenType);
sourceSpecimen.setStudy(study);
return sourceSpecimen;
}
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("SourceSpecimenSaveInfo: id/").append(id);
sb.append(" needOriginalVolume/").append(needOriginalVolume);
sb.append(" specimenTypeId/").append(specimenTypeId);
return sb.toString();
}
}
public static class AliquotedSpecimenSaveInfo implements ActionResult {
private static final long serialVersionUID = 1L;
public Integer id = null;
public Integer quantity;
public BigDecimal volume;
public ActivityStatus activityStatus;
public Integer specimenTypeId;
public AliquotedSpecimenSaveInfo() {
}
public AliquotedSpecimenSaveInfo(AliquotedSpecimen aliquotedSpecimen) {
this.id = aliquotedSpecimen.getId();
this.quantity = aliquotedSpecimen.getQuantity();
this.volume = aliquotedSpecimen.getVolume();
this.activityStatus = aliquotedSpecimen.getActivityStatus();
this.specimenTypeId = aliquotedSpecimen.getSpecimenType().getId();
}
public AliquotedSpecimen populateAliquotedSpecimen(Study study,
AliquotedSpecimen aliquotedSpecimen, ActivityStatus activityStatus,
SpecimenType specimenType) {
aliquotedSpecimen.setId(this.id);
aliquotedSpecimen.setQuantity(this.quantity);
aliquotedSpecimen.setVolume(this.volume);
aliquotedSpecimen.setActivityStatus(activityStatus);
aliquotedSpecimen.setSpecimenType(specimenType);
aliquotedSpecimen.setStudy(study);
return aliquotedSpecimen;
}
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("AliquotedSpecimenSaveInfo: id/").append(id);
sb.append(" quantity/").append(quantity);
sb.append(" volume/").append(volume);
sb.append(" activityStatus/").append(activityStatus);
sb.append(" specimenTypeId/").append(specimenTypeId);
return sb.toString();
}
}
public static class StudyEventAttrSaveInfo implements ActionResult {
private static final long serialVersionUID = 1L;
public Integer id = null;
public Integer globalEventAttrId;
public Boolean required;
public String permissible;
public ActivityStatus activityStatus;
public StudyEventAttrSaveInfo() {
}
public StudyEventAttrSaveInfo(StudyEventAttr studyEventAttr) {
this.id = studyEventAttr.getId();
this.globalEventAttrId =
studyEventAttr.getGlobalEventAttr().getId();
this.required = studyEventAttr.getRequired();
this.permissible = studyEventAttr.getPermissible();
this.activityStatus = studyEventAttr.getActivityStatus();
}
public StudyEventAttr populateStudyEventAttr(Study study,
StudyEventAttr studyEventAttr,
GlobalEventAttr globalEventAttr, ActivityStatus activityStatus) {
studyEventAttr.setId(this.id);
studyEventAttr.setGlobalEventAttr(globalEventAttr);
studyEventAttr.setRequired(this.required);
studyEventAttr.setPermissible(this.permissible);
studyEventAttr.setActivityStatus(activityStatus);
studyEventAttr.setStudy(study);
return studyEventAttr;
}
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("id/").append(id);
sb.append(" globalEventAttrId/").append(globalEventAttrId);
sb.append(" required/").append(required);
sb.append(" permissible/").append(permissible);
sb.append(" activityStatus/").append(activityStatus);
return sb.toString();
}
}
private Integer id = null;
private String name;
private String nameShort;
private ActivityStatus activityStatus;
private Set<Integer> contactIds;
private Collection<SourceSpecimenSaveInfo> sourceSpecimenSaveInfos;
private Collection<AliquotedSpecimenSaveInfo> aliquotSpecimenSaveInfos;
private Collection<StudyEventAttrSaveInfo> studyEventAttrSaveInfos;
private String commentText;
private Study study = null;
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setNameShort(String nameShort) {
this.nameShort = nameShort;
}
public void setActivityStatus(ActivityStatus activityStatus) {
this.activityStatus = activityStatus;
}
public void setContactIds(Set<Integer> contactIds) {
this.contactIds = contactIds;
}
public void setSourceSpecimenSaveInfo(
Collection<SourceSpecimenSaveInfo> sourceSpecimenSaveInfos) {
this.sourceSpecimenSaveInfos = sourceSpecimenSaveInfos;
}
public void setAliquotSpecimenSaveInfo(
Collection<AliquotedSpecimenSaveInfo> aliquotSpecimenSaveInfos) {
this.aliquotSpecimenSaveInfos = aliquotSpecimenSaveInfos;
}
public void setStudyEventAttrSaveInfo(
Collection<StudyEventAttrSaveInfo> studyEventAttrSaveInfos) {
this.studyEventAttrSaveInfos = studyEventAttrSaveInfos;
}
public void setCommentText(String commentText) {
this.commentText = commentText;
}
@Override
public boolean isAllowed(ActionContext context) throws ActionException {
Permission permission;
if (id == null)
permission = new StudyCreatePermission();
else
permission = new StudyUpdatePermission(id);
return permission.isAllowed(context);
}
@Override
public IdResult run(ActionContext context) throws ActionException {
study = context.get(Study.class, id, new Study());
study.setId(id);
study.setName(name);
study.setNameShort(nameShort);
study.setActivityStatus(activityStatus);
saveContacts(context);
saveSourceSpecimens(context);
saveAliquotedSpecimens(context);
saveEventAttributes(context);
saveComment(context);
context.getSession().saveOrUpdate(study);
context.getSession().flush();
return new IdResult(study.getId());
}
private void saveContacts(ActionContext context) {
Set<Contact> contacts =
context.load(Contact.class, contactIds);
SetDifference<Contact> contactsDiff =
new SetDifference<Contact>(study.getContacts(),
contacts);
study.setContacts(contactsDiff.getNewSet());
for (Contact contact : contactsDiff.getAddSet()) {
Set<Study> contactStudies = contact.getStudies();
contactStudies.add(study);
contact.setStudies(contactStudies);
}
// remove this study from contacts in removed list
for (Contact contact : contactsDiff.getRemoveSet()) {
Set<Study> contactStudies = contact.getStudies();
if (contactStudies.remove(study)) {
contact.setStudies(contactStudies);
} else {
throw new ActionException(
"study not found in removed contact's collection");
}
}
}
private void saveSourceSpecimens(ActionContext context) {
Set<SourceSpecimen> newSsCollection = new HashSet<SourceSpecimen>();
for (SourceSpecimenSaveInfo ssSaveInfo : sourceSpecimenSaveInfos) {
SourceSpecimen ss;
if (ssSaveInfo.id == null) {
ss = new SourceSpecimen();
} else {
ss = context.load(SourceSpecimen.class, ssSaveInfo.id);
}
newSsCollection.add(ssSaveInfo.populateSourceSpecimen(study, ss,
context.load(SpecimenType.class,
ssSaveInfo.specimenTypeId)));
log.trace("added source specimen: {}", ssSaveInfo.specimenTypeId);
}
// delete source specimens no longer in use
SetDifference<SourceSpecimen> srcSpcsDiff =
new SetDifference<SourceSpecimen>(
study.getSourceSpecimens(), newSsCollection);
study.getSourceSpecimens().clear();
study.getSourceSpecimens().addAll(srcSpcsDiff.getNewSet());
// delete source specimens no longer in use
for (SourceSpecimen srcSpc : srcSpcsDiff.getRemoveSet()) {
context.getSession().delete(srcSpc);
log.trace("deleted source specimen: {}", srcSpc.getSpecimenType()
.getName());
}
}
private void saveAliquotedSpecimens(ActionContext context) {
Set<AliquotedSpecimen> newAsCollection =
new HashSet<AliquotedSpecimen>();
for (AliquotedSpecimenSaveInfo asSaveInfo : aliquotSpecimenSaveInfos) {
AliquotedSpecimen as;
if (asSaveInfo.id == null) {
as = new AliquotedSpecimen();
} else {
as = context.load(AliquotedSpecimen.class, asSaveInfo.id);
}
newAsCollection.add(asSaveInfo.populateAliquotedSpecimen(study, as,
asSaveInfo.activityStatus, context.load(SpecimenType.class,
asSaveInfo.specimenTypeId)));
log.trace("added aliquoted specimen: {}", asSaveInfo.specimenTypeId);
}
SetDifference<AliquotedSpecimen> aqSpcsDiff =
new SetDifference<AliquotedSpecimen>(
study.getAliquotedSpecimens(), newAsCollection);
study.getAliquotedSpecimens().clear();
study.getAliquotedSpecimens().addAll(aqSpcsDiff.getNewSet());
// delete aliquoted specimens no longer in use
for (AliquotedSpecimen aqSpc : aqSpcsDiff.getRemoveSet()) {
context.getSession().delete(aqSpc);
log.trace("deleted aliquoted specimen: {}", aqSpc.getSpecimenType()
.getName());
}
}
private void saveEventAttributes(ActionContext context) {
Set<Integer> geAttrIdsUsed = new HashSet<Integer>();
Set<StudyEventAttr> newEAttrCollection = new HashSet<StudyEventAttr>();
for (StudyEventAttrSaveInfo eAttrSaveInfo : studyEventAttrSaveInfos) {
if (geAttrIdsUsed.contains(eAttrSaveInfo.globalEventAttrId)) {
throw new ActionCheckException(
"canot add multiple study event attributes with same global id "
+ eAttrSaveInfo.globalEventAttrId);
}
StudyEventAttr seAttr;
if (eAttrSaveInfo.id == null) {
seAttr = new StudyEventAttr();
} else {
seAttr = context.load(StudyEventAttr.class,
eAttrSaveInfo.id);
}
newEAttrCollection.add(eAttrSaveInfo.populateStudyEventAttr(study,
seAttr, context.load(GlobalEventAttr.class,
eAttrSaveInfo.globalEventAttrId),
eAttrSaveInfo.activityStatus));
geAttrIdsUsed.add(eAttrSaveInfo.globalEventAttrId);
}
SetDifference<StudyEventAttr> attrsDiff =
new SetDifference<StudyEventAttr>(
study.getStudyEventAttrs(), newEAttrCollection);
study.setStudyEventAttrs(attrsDiff.getNewSet());
for (StudyEventAttr attr : attrsDiff.getRemoveSet()) {
context.getSession().delete(attr);
}
}
private void saveComment(ActionContext context) {
Comment comment = CommentUtil.create(context.getUser(), commentText);
if (comment != null) {
context.getSession().save(comment);
study.getComments().add(comment);
}
}
}