package org.akaza.openclinica.controller.openrosa.processor;
import java.io.StringReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.akaza.openclinica.controller.openrosa.SubmissionContainer;
import org.akaza.openclinica.dao.hibernate.StudyDao;
import org.akaza.openclinica.dao.hibernate.StudySubjectDao;
import org.akaza.openclinica.dao.hibernate.SubjectDao;
import org.akaza.openclinica.dao.hibernate.UserAccountDao;
import org.akaza.openclinica.domain.Status;
import org.akaza.openclinica.domain.datamap.Study;
import org.akaza.openclinica.domain.datamap.StudySubject;
import org.akaza.openclinica.domain.datamap.Subject;
import org.akaza.openclinica.domain.user.UserAccount;
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.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import static org.akaza.openclinica.controller.openrosa.SubmissionProcessorChain.ProcessorEnum;
@Component
@Order(value=3)
public class StudySubjectProcessor implements Processor {
@Autowired
StudySubjectDao studySubjectDao;
@Autowired
UserAccountDao userAccountDao;
@Autowired
SubjectDao subjectDao;
@Autowired
StudyDao studyDao;
protected final Logger logger = LoggerFactory.getLogger(getClass().getName());
@Override
public ProcessorEnum process(SubmissionContainer container) throws Exception {
logger.info("Executing study subject processor.");
String studySubjectOid = container.getSubjectContext().get("studySubjectOID");
String embeddedStudySubjectId = getEmbeddedStudySubjectOid(container);
int nextLabel = studySubjectDao.findTheGreatestLabel() + 1;
Date currentDate = new Date();
UserAccount rootUser = userAccountDao.findByUserId(1);
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMdd.HHmmss");
// Standard Participant Dashboard submission
if (studySubjectOid != null) {
StudySubject studySubject = studySubjectDao.findByOcOID(studySubjectOid);
container.setSubject(studySubject);
if (studySubject.getStatus() != Status.AVAILABLE) {
container.getErrors().reject("value.incorrect.STATUS");
throw new Exception("StudySubject status is not Available.");
}
// Embedded Study Subject ID in form. An offline submission.
} else if (embeddedStudySubjectId != null) {
Study study = studyDao.findByOcOID(container.getSubjectContext().get("studyOID"));
StudySubject embeddedStudySubject = studySubjectDao.findByLabelAndStudyOrParentStudy(embeddedStudySubjectId, study);
//If Study Subject exists in current study and is available use that
if (embeddedStudySubject != null && embeddedStudySubject.getStatus() == Status.AVAILABLE) {
container.setSubject(embeddedStudySubject);
//If it exists but is in the wrong status, throw an exception
} else if (embeddedStudySubject != null && embeddedStudySubject.getStatus() != Status.AVAILABLE) {
container.getErrors().reject("value.incorrect.STATUS");
throw new Exception("Embedded StudySubject status is not Available");
//If Study Subject exists in a parent/sibling study, create study subject with 'FIXME-<timestamp>' label to avoid data loss and mark it
} else if (subjectExistsInParentSiblingStudy(embeddedStudySubjectId, study)) {
String subjectLabel = "FIXME-" + dateFormatter.format(currentDate);
Subject subject = createSubject(currentDate);
StudySubject studySubject = createStudySubject(subjectLabel, subject, study,rootUser,currentDate,embeddedStudySubjectId);
container.setSubject(studySubject);
//Study Subject does not exist. Create it
} else {
Subject subject = createSubject(currentDate);
StudySubject studySubject = createStudySubject(embeddedStudySubjectId, subject, study,rootUser,currentDate, null);
container.setSubject(studySubject);
}
// Anonymous submission or offline submission with no embedded Study Subject ID
} else {
// create Subject & Study Subject
Study study = studyDao.findByOcOID(container.getSubjectContext().get("studyOID"));
Subject subject = createSubject(currentDate);
StudySubject studySubject = createStudySubject(Integer.toString(nextLabel), subject, study,rootUser,currentDate, null);
container.setSubject(studySubject);
}
return ProcessorEnum.PROCEED;
}
private boolean subjectExistsInParentSiblingStudy(String embeddedStudySubjectId, Study study) {
boolean subjectExists = false;
// Check parent studies
if (study.getStudy() != null && studySubjectDao.findByLabelAndStudy(embeddedStudySubjectId, study.getStudy()) != null) subjectExists = true;
// Check sibling studies
if (study.getStudy() != null) {
List<StudySubject> siblingSubjects = studySubjectDao.findByLabelAndParentStudy(embeddedStudySubjectId, study.getStudy());
for (StudySubject subject:siblingSubjects) {
if (subject.getStudy().getStudyId() != study.getStudyId()) subjectExists = true;
}
}
return subjectExists;
}
private Subject createSubject(Date currentDate) {
UserAccount rootUser = userAccountDao.findByUserId(1);
Subject subject = new Subject();
subject.setUserAccount(rootUser);
subject.setStatus(Status.AVAILABLE);
subject.setDobCollected(false);
subject.setDateCreated(currentDate);
subject.setUniqueIdentifier("");
subject = subjectDao.saveOrUpdate(subject);
return subject;
}
private StudySubject createStudySubject(String label, Subject subject, Study study, UserAccount rootUser, Date currentDate, String secondaryLabel) {
StudySubject studySubject = new StudySubject();
studySubject.setStudy(study);
studySubject.setSubject(subject);
studySubject.setStatus(Status.AVAILABLE);
studySubject.setUserAccount(rootUser);
studySubject.setEnrollmentDate(currentDate);
studySubject.setDateCreated(currentDate);
studySubject.setSecondaryLabel("");
studySubject.setLabel(label);
if (secondaryLabel != null && !secondaryLabel.equals("")) studySubject.setSecondaryLabel(secondaryLabel);
String studySubjectOid = studySubjectDao.getValidOid(studySubject,new ArrayList<String>());
studySubject.setOcOid(studySubjectOid);
studySubject = studySubjectDao.saveOrUpdate(studySubject);
return studySubject;
}
private String getEmbeddedStudySubjectOid(SubmissionContainer container) throws Exception {
String studySubjectId = null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(container.getRequestBody()));
Document doc = db.parse(is);
Node instanceNode = doc.getElementsByTagName("instance").item(0);
NodeList crfNodeList = instanceNode.getChildNodes();
// Form loop
for (int j = 0; j < crfNodeList.getLength(); j = j + 1) {
Node crfNode = crfNodeList.item(j);
if (!(crfNode instanceof Element)) continue;
NodeList groupNodeList = crfNode.getChildNodes();
// Group loop
for (int k = 0; k < groupNodeList.getLength(); k = k + 1) {
Node groupNode = groupNodeList.item(k);
if (!(groupNode instanceof Element && !groupNode.getNodeName().startsWith("SECTION_"))) continue;
NodeList itemNodeList = groupNode.getChildNodes();
// Item loop
for (int m = 0; m < itemNodeList.getLength(); m = m + 1) {
Node itemNode = itemNodeList.item(m);
if (itemNode instanceof Element && itemNode.getNodeName().equals("OC.STUDY_SUBJECT_ID")) { //{
String nodeValue = itemNode.getTextContent();
if (nodeValue != null && !nodeValue.equals("")) studySubjectId = nodeValue;
}
} // Item loop
} // Group loop
} // Form loop
return studySubjectId;
}
}