package org.akaza.openclinica.controller.openrosa.processor;
import java.util.Date;
import java.util.List;
import org.akaza.openclinica.controller.openrosa.SubmissionContainer;
import org.akaza.openclinica.dao.hibernate.CompletionStatusDao;
import org.akaza.openclinica.dao.hibernate.CrfVersionDao;
import org.akaza.openclinica.dao.hibernate.EventCrfDao;
import org.akaza.openclinica.dao.hibernate.EventDefinitionCrfDao;
import org.akaza.openclinica.dao.hibernate.ItemDataDao;
import org.akaza.openclinica.dao.hibernate.StudyDao;
import org.akaza.openclinica.dao.hibernate.StudyEventDao;
import org.akaza.openclinica.dao.hibernate.StudyEventDefinitionDao;
import org.akaza.openclinica.domain.Status;
import org.akaza.openclinica.domain.datamap.CrfVersion;
import org.akaza.openclinica.domain.datamap.EventCrf;
import org.akaza.openclinica.domain.datamap.ItemData;
import org.akaza.openclinica.domain.datamap.Study;
import org.akaza.openclinica.domain.datamap.StudyEvent;
import org.akaza.openclinica.domain.datamap.StudyEventDefinition;
import org.akaza.openclinica.domain.datamap.StudySubject;
import org.akaza.openclinica.domain.datamap.SubjectEventStatus;
import org.akaza.openclinica.domain.user.UserAccount;
import org.akaza.openclinica.patterns.ocobserver.StudyEventChangeDetails;
import org.akaza.openclinica.patterns.ocobserver.StudyEventContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import static org.akaza.openclinica.controller.openrosa.SubmissionProcessorChain.ProcessorEnum;
@Component
@Order(value=5)
public class EventProcessor implements Processor {
@Autowired
StudyEventDao studyEventDao;
@Autowired
StudyEventDefinitionDao studyEventDefinitionDao;
@Autowired
EventCrfDao eventCrfDao;
@Autowired
CrfVersionDao crfVersionDao;
@Autowired
CompletionStatusDao completionStatusDao;
@Autowired
EventDefinitionCrfDao eventDefinitionCrfDao;
@Autowired
ItemDataDao itemDataDao;
@Autowired
StudyDao studyDao;
protected final Logger logger = LoggerFactory.getLogger(getClass().getName());
public ProcessorEnum process(SubmissionContainer container) throws Exception {
logger.info("Executing Event Processor.");
Errors errors = container.getErrors();
StudySubject studySubject = container.getSubject();
StudyEventDefinition studyEventDefinition = studyEventDefinitionDao.findByStudyEventDefinitionId(Integer.valueOf(container.getSubjectContext().get("studyEventDefinitionID")));
boolean isAnonymous = false;
if (container.getSubjectContext().get("studySubjectOID") == null) isAnonymous = true;
//Create study event if it doesn't exist
if (isAnonymous) processAnonymous(container,errors, studySubject, studyEventDefinition);
else processParticipant(container,errors, studySubject, studyEventDefinition);
//TODO: May need to move this to a new processor that runs at the end
// Update the EventCrf and StudyEvent to the proper status.
// Don't do it in the initial save so it will have the expected audit trail entries.
Study study = null;
if (container.getSubjectContext().get("studyOID") != null)
study = studyDao.findByOcOID(container.getSubjectContext().get("studyOID"));
else study = container.getStudy();
container.setEventCrf(updateEventCrf(container.getEventCrf(), study, studySubject, container.getUser(), isAnonymous));
container.setStudyEvent(updateStudyEvent(container.getStudyEvent(), studyEventDefinition, study, studySubject, container.getUser(), isAnonymous));
return ProcessorEnum.PROCEED;
}
private void processParticipant(SubmissionContainer container, Errors errors, StudySubject studySubject, StudyEventDefinition studyEventDefinition) throws Exception {
Integer ordinal = Integer.valueOf(container.getSubjectContext().get("studyEventOrdinal"));
StudyEvent existingEvent = studyEventDao.fetchByStudyEventDefOIDAndOrdinal(studyEventDefinition.getOc_oid(),ordinal,studySubject.getStudySubjectId());
if (existingEvent == null) {
container.setStudyEvent(createStudyEvent(studySubject,studyEventDefinition,ordinal,container.getUser()));
} else container.setStudyEvent(existingEvent);
//Create event crf if it doesn't exist
if (studyEventDefinition.getStatus() != Status.AVAILABLE) {
logger.info("This Crf Version has a Status Not available in this Study Event Defn");
errors.reject("This Crf Version has a Status Not available in this Study Event Defn");
throw new Exception("This Crf Version has a Status Not available in this Study Event Defn");
}
CrfVersion crfVersion = crfVersionDao.findByOcOID(container.getSubjectContext().get("crfVersionOID"));
EventCrf existingEventCrf = eventCrfDao.findByStudyEventIdStudySubjectIdCrfId(container.getStudyEvent().getStudyEventId(), container.getSubject().getStudySubjectId(), crfVersion.getCrf().getCrfId());
if (existingEventCrf == null) {
logger.info("***New EventCrf is created***");
//create event crf
container.setEventCrf(createEventCrf(crfVersion,container.getStudyEvent(),container.getSubject(),container.getUser()));
} else if (existingEventCrf.getCrfVersion().getOcOid().equals(crfVersion.getOcOid())) {
logger.info("*** Existing EventCrf with same CRF Version ***");
//use existing event crf
container.setEventCrf(existingEventCrf);
} else {
// different version already exists. log error and abort submission
errors.reject("Existing EventCrf with other CRF version");
logger.info("*** Existing EventCrf with other CRF version ***");
throw new Exception("*** Existing EventCrf with other CRF version ***");
}
}
private void processAnonymous(SubmissionContainer container, Errors errors, StudySubject studySubject, StudyEventDefinition studyEventDefinition) throws Exception {
Integer ordinal = 1; //Integer.valueOf(container.getSubjectContext().get("studyEventOrdinal"));
Integer maxExistingOrdinal = studyEventDao.findMaxOrdinalByStudySubjectStudyEventDefinition(studySubject.getStudySubjectId(),studyEventDefinition.getStudyEventDefinitionId());
CrfVersion crfVersion = crfVersionDao.findByOcOID(container.getSubjectContext().get("crfVersionOID"));
while (ordinal <= maxExistingOrdinal + 1) {
StudyEvent existingStudyEvent = studyEventDao.fetchByStudyEventDefOIDAndOrdinal(studyEventDefinition.getOc_oid(),ordinal,studySubject.getStudySubjectId());
if (existingStudyEvent == null) {
container.setStudyEvent(createStudyEvent(studySubject,studyEventDefinition,ordinal,container.getUser()));
container.setEventCrf(createEventCrf(crfVersion,container.getStudyEvent(),container.getSubject(),container.getUser()));
break;
} else if (!existingStudyEvent.getStatusId().equals(Status.AVAILABLE.getCode())
|| (!existingStudyEvent.getSubjectEventStatusId().equals(SubjectEventStatus.SCHEDULED.getCode())
&& !existingStudyEvent.getSubjectEventStatusId().equals(SubjectEventStatus.NOT_SCHEDULED.getCode())
&& !existingStudyEvent.getSubjectEventStatusId().equals(SubjectEventStatus.DATA_ENTRY_STARTED.getCode()))){
if (studyEventDefinition.getRepeating()) {
ordinal++;
continue;
} else {
errors.reject("Existing StudyEvent is not Available and EventDef is not repeating");
logger.info("*** Existing StudyEvent is not Available and EventDef is not repeating ***");
throw new Exception("*** Existing StudyEvent is not Available and EventDef is not repeating ***");
}
} else {
EventCrf existingEventCrf = eventCrfDao.findByStudyEventIdStudySubjectIdCrfId(existingStudyEvent.getStudyEventId(), container.getSubject().getStudySubjectId(), crfVersion.getCrf().getCrfId());
if (existingEventCrf == null) {
container.setStudyEvent(existingStudyEvent);
container.setEventCrf(createEventCrf(crfVersion,container.getStudyEvent(),container.getSubject(),container.getUser()));
break;
} else {
List<ItemData> itemDataList = itemDataDao.findByEventCrfId(existingEventCrf.getEventCrfId());
if (existingEventCrf.getStatusId().equals(Status.AVAILABLE.getCode()) && itemDataList.size() == 0) {
container.setStudyEvent(existingStudyEvent);
container.setEventCrf(existingEventCrf);
break;
}else if (studyEventDefinition.getRepeating()) {
ordinal++;
continue;
} else {
errors.reject("Existing EventCRF is not usable and EventDef is not repeating");
logger.info("*** Existing EventCRF is not usable and EventDef is not repeating ***");
throw new Exception("*** Existing EventCRF is not usable and EventDef is not repeating ***");
}
}
}
}
if (container.getStudyEvent() == null || container.getEventCrf() == null) {
errors.reject("Unable to identify StudyEvent or EventCrf.");
logger.info("*** Unable to identify StudyEvent or EventCrf. ***");
throw new Exception("*** Unable to identify StudyEvent or EventCrf. ***");
}
}
private StudyEvent createStudyEvent(StudySubject studySubject, StudyEventDefinition studyEventDefinition, Integer ordinal, UserAccount user) {
Date currentDate = new Date();
StudyEvent studyEvent = new StudyEvent();
studyEvent.setStudySubject(studySubject);
studyEvent.setStudyEventDefinition(studyEventDefinition);
studyEvent.setSampleOrdinal(ordinal);
studyEvent.setStatusId(Status.AVAILABLE.getCode());
studyEvent.setUserAccount(user);
studyEvent.setDateStart(currentDate);
studyEvent.setSubjectEventStatusId(SubjectEventStatus.SCHEDULED.getCode());
studyEvent.setStartTimeFlag(false);
studyEvent.setEndTimeFlag(false);
studyEvent.setDateCreated(currentDate);
studyEvent.setLocation("");
StudyEventChangeDetails changeDetails = new StudyEventChangeDetails(true,true);
StudyEventContainer container = new StudyEventContainer(studyEvent,changeDetails);
studyEventDao.saveOrUpdateTransactional(container);
studyEvent = studyEventDao.fetchByStudyEventDefOIDAndOrdinal(studyEventDefinition.getOc_oid(),ordinal,studySubject.getStudySubjectId());
return studyEvent;
}
private EventCrf createEventCrf(CrfVersion crfVersion, StudyEvent studyEvent, StudySubject studySubject, UserAccount user) {
EventCrf eventCrf = new EventCrf();
Date currentDate = new Date();
eventCrf.setAnnotations("");
eventCrf.setDateCreated(currentDate);
eventCrf.setCrfVersion(crfVersion);
eventCrf.setInterviewerName("");
eventCrf.setDateInterviewed(null);
eventCrf.setUserAccount(user);
eventCrf.setStatusId(Status.AVAILABLE.getCode());
eventCrf.setCompletionStatus(completionStatusDao.findByCompletionStatusId(1));//setCompletionStatusId(1);
eventCrf.setStudySubject(studySubject);
eventCrf.setStudyEvent(studyEvent);
eventCrf.setValidateString("");
eventCrf.setValidatorAnnotations("");
eventCrf.setUpdateId(user.getUserId());
eventCrf.setDateUpdated(new Date());
eventCrf.setValidatorId(0);
eventCrf.setOldStatusId(0);
eventCrf.setSdvUpdateId(0);
eventCrfDao.saveOrUpdate(eventCrf);
eventCrf = eventCrfDao.findByStudyEventIdStudySubjectIdCrfVersionId(studyEvent.getStudyEventId(), studySubject.getStudySubjectId(), crfVersion.getCrfVersionId());
logger.debug("*********CREATED EVENT CRF");
return eventCrf;
}
private StudyEvent updateStudyEvent(StudyEvent studyEvent, StudyEventDefinition studyEventDefinition, Study study, StudySubject studySubject, UserAccount user, boolean isAnonymous) {
SubjectEventStatus newStatus = null;
int crfCount = 0;
int hiddenSiteCrfCount = 0;
int completedCrfCount = 0;
if (!isAnonymous) {
if (studyEvent.getSubjectEventStatusId().intValue() == SubjectEventStatus.SCHEDULED.getCode().intValue()) newStatus = SubjectEventStatus.DATA_ENTRY_STARTED;
} else {
// Get a count of CRFs defined for the event
// TODO: What i need to do to fix this is get the study from the context
// Then i need to query the site for hidden crfs then subtract that from the count of study defined crfs to get the crf count
if (study.getStudy() != null ) {
hiddenSiteCrfCount = eventDefinitionCrfDao.findSiteHiddenByStudyEventDefStudy(studyEventDefinition.getStudyEventDefinitionId(),study.getStudyId()).size();
crfCount = eventDefinitionCrfDao.findAvailableByStudyEventDefStudy(studyEventDefinition.getStudyEventDefinitionId(),study.getStudy().getStudyId()).size();
} else
crfCount = eventDefinitionCrfDao.findAvailableByStudyEventDefStudy(studyEventDefinition.getStudyEventDefinitionId(),study.getStudyId()).size();
// Get a count of completed CRFs for the event
completedCrfCount = eventCrfDao.findByStudyEventStatus(studyEvent.getStudyEventId(), Status.UNAVAILABLE.getCode()).size();
if ((crfCount - hiddenSiteCrfCount) == completedCrfCount){
if (studyEvent.getSubjectEventStatusId().intValue() == SubjectEventStatus.SCHEDULED.getCode().intValue() || studyEvent.getSubjectEventStatusId().intValue() == SubjectEventStatus.DATA_ENTRY_STARTED.getCode().intValue()) {
newStatus = SubjectEventStatus.COMPLETED;
}
} else if (studyEvent.getSubjectEventStatusId().intValue() == SubjectEventStatus.SCHEDULED.getCode().intValue()) {
newStatus = SubjectEventStatus.DATA_ENTRY_STARTED;
}
}
if (newStatus != null) {
studyEvent.setUpdateId(user.getUserId());
studyEvent.setDateUpdated(new Date());
studyEvent.setSubjectEventStatusId(newStatus.getCode());
StudyEventChangeDetails changeDetails = new StudyEventChangeDetails(true,false);
StudyEventContainer container = new StudyEventContainer(studyEvent,changeDetails);
studyEvent = studyEventDao.saveOrUpdateTransactional(container);
logger.debug("*********UPDATED STUDY EVENT ");
}
return studyEvent;
}
/**
* Update Status in Event CRF Table
*
* @param ecBean
* @param studyBean
* @param studySubjectBean
* @param isAnonymous
* @return
*/
private EventCrf updateEventCrf(EventCrf eventCrf, Study study, StudySubject studySubject, UserAccount user, boolean isAnonymous) {
eventCrf.setUpdateId(user.getUserId());
eventCrf.setDateUpdated(new Date());
if (isAnonymous) eventCrf.setStatusId(Status.UNAVAILABLE.getCode());
else eventCrf.setStatusId(Status.AVAILABLE.getCode());
eventCrf = eventCrfDao.saveOrUpdate(eventCrf);
logger.debug("*********UPDATED EVENT CRF");
return eventCrf;
}
}