/* * OpenClinica is distributed under the * GNU Lesser General Public License (GNU LGPL). * For details see: http://www.openclinica.org/license * copyright 2003-2005 Akaza Research */ package org.akaza.openclinica.service.managestudy; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import javax.sql.DataSource; import org.akaza.openclinica.bean.admin.CRFBean; import org.akaza.openclinica.bean.core.DataEntryStage; import org.akaza.openclinica.bean.core.Status; import org.akaza.openclinica.bean.core.SubjectEventStatus; import org.akaza.openclinica.bean.login.StudyUserRoleBean; import org.akaza.openclinica.bean.login.UserAccountBean; import org.akaza.openclinica.bean.managestudy.DisplayEventDefinitionCRFBean; import org.akaza.openclinica.bean.managestudy.DisplayStudyEventBean; import org.akaza.openclinica.bean.managestudy.EventDefinitionCRFBean; import org.akaza.openclinica.bean.managestudy.StudyBean; import org.akaza.openclinica.bean.managestudy.StudyEventBean; import org.akaza.openclinica.bean.managestudy.StudyEventDefinitionBean; import org.akaza.openclinica.bean.managestudy.StudySubjectBean; import org.akaza.openclinica.bean.submit.CRFVersionBean; import org.akaza.openclinica.bean.submit.DisplayEventCRFBean; import org.akaza.openclinica.bean.submit.EventCRFBean; import org.akaza.openclinica.dao.admin.CRFDAO; import org.akaza.openclinica.dao.managestudy.EventDefinitionCRFDAO; import org.akaza.openclinica.dao.managestudy.StudyDAO; import org.akaza.openclinica.dao.managestudy.StudyEventDAO; import org.akaza.openclinica.dao.managestudy.StudyEventDefinitionDAO; import org.akaza.openclinica.dao.submit.CRFVersionDAO; import org.akaza.openclinica.dao.submit.EventCRFDAO; /** * @author Doug Rodrigues (douglas.rodrigues@openclinica.com) * */ public class StudySubjectServiceImpl implements StudySubjectService { private DataSource dataSource; @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public List<DisplayStudyEventBean> getDisplayStudyEventsForStudySubject(StudySubjectBean studySubject, UserAccountBean userAccount, StudyUserRoleBean currentRole) { StudyEventDAO studyEventDao = new StudyEventDAO(dataSource); StudyEventDefinitionDAO studyEventDefinitionDao = new StudyEventDefinitionDAO(dataSource); StudyDAO studyDao = new StudyDAO(dataSource); EventDefinitionCRFDAO eventDefinitionCrfDao = new EventDefinitionCRFDAO(dataSource); EventCRFDAO eventCrfDao = new EventCRFDAO(dataSource); CRFDAO crfDao = new CRFDAO(dataSource); CRFVersionDAO crfVersionDao = new CRFVersionDAO(dataSource); ArrayList events = studyEventDao.findAllByStudySubject(studySubject); Map<Integer, StudyEventDefinitionBean> eventDefinitionByEvent = studyEventDefinitionDao.findByStudySubject(studySubject.getId()); StudyBean study = (StudyBean) studyDao.findByPK(studySubject.getStudyId()); Map<Integer, SortedSet<EventDefinitionCRFBean>> eventDefinitionCrfByStudyEventDefinition; if (study.getParentStudyId() < 1) { // Is a study eventDefinitionCrfByStudyEventDefinition = eventDefinitionCrfDao.buildEventDefinitionCRFListByStudyEventDefinitionForStudy(studySubject.getId()); } else { // Is a site eventDefinitionCrfByStudyEventDefinition = eventDefinitionCrfDao.buildEventDefinitionCRFListByStudyEventDefinition(studySubject.getId(), study.getId(), study.getParentStudyId()); } Map<Integer, SortedSet<EventCRFBean>> eventCrfListByStudyEvent = eventCrfDao.buildEventCrfListByStudyEvent(studySubject.getId()); Map<Integer, Integer> maxOrdinalByStudyEvent = studyEventDefinitionDao.buildMaxOrdinalByStudyEvent(studySubject.getId()); Set<Integer> nonEmptyEventCrf = eventCrfDao.buildNonEmptyEventCrfIds(studySubject.getId()); Map<Integer, CRFVersionBean> crfVersionById = crfVersionDao.buildCrfVersionById(studySubject.getId()); Map<Integer, CRFBean> crfById = crfDao.buildCrfById(studySubject.getId()); ArrayList<DisplayStudyEventBean> displayEvents = new ArrayList<DisplayStudyEventBean>(); for (int i = 0; i < events.size(); i++) { StudyEventBean event = (StudyEventBean) events.get(i); StudyEventDefinitionBean sed = eventDefinitionByEvent.get(event.getStudyEventDefinitionId()); event.setStudyEventDefinition(sed); List eventDefinitionCRFs = new ArrayList((eventDefinitionCrfByStudyEventDefinition.containsKey(sed.getId()) ? eventDefinitionCrfByStudyEventDefinition.get(sed.getId()) : Collections.EMPTY_LIST)); List eventCRFs = new ArrayList((eventCrfListByStudyEvent.containsKey(event.getId())) ? eventCrfListByStudyEvent.get(event.getId()) : Collections.EMPTY_LIST); // construct info needed on view study event page DisplayStudyEventBean de = new DisplayStudyEventBean(); de.setStudyEvent(event); de.setDisplayEventCRFs((ArrayList<DisplayEventCRFBean>) getDisplayEventCRFs(eventCRFs, userAccount, currentRole, event.getSubjectEventStatus(), study, nonEmptyEventCrf, crfVersionById, crfById, event.getStudyEventDefinitionId(), eventDefinitionCRFs)); ArrayList<DisplayEventDefinitionCRFBean> al = getUncompletedCRFs(eventDefinitionCRFs, eventCRFs, event.getSubjectEventStatus(), nonEmptyEventCrf, crfVersionById, crfById); populateUncompletedCRFsWithCRFAndVersions(al, crfVersionById, crfById); de.setUncompletedCRFs(al); // de.setMaximumSampleOrdinal(studyEventDao.getMaxSampleOrdinal(sed, // studySubject)); de.setMaximumSampleOrdinal(maxOrdinalByStudyEvent.get(event.getStudyEventDefinitionId())); displayEvents.add(de); // event.setEventCRFs(createAllEventCRFs(eventCRFs, // eventDefinitionCRFs)); } return displayEvents; } private List<DisplayEventCRFBean> getDisplayEventCRFs(List eventCRFs, UserAccountBean ub, StudyUserRoleBean currentRole, SubjectEventStatus status, StudyBean study, Set<Integer> nonEmptyEventCrf, Map<Integer, CRFVersionBean> crfVersionById, Map<Integer, CRFBean> crfById, Integer studyEventDefinitionId, List eventDefinitionCRFs) { ArrayList<DisplayEventCRFBean> answer = new ArrayList<DisplayEventCRFBean>(); for (int i = 0; i < eventCRFs.size(); i++) { EventCRFBean ecb = (EventCRFBean) eventCRFs.get(i); // populate the event CRF with its crf bean int crfVersionId = ecb.getCRFVersionId(); // CRFVersionBean cvb = crfVersionById.get(ecb.getCRFVersionId()); CRFVersionBean cvb = crfVersionById.get(crfVersionId); ecb.setCrfVersion(cvb); // CRFBean cb = crfDao.findByVersionId(crfVersionId); CRFBean cb = crfById.get(cvb.getCrfId()); ecb.setCrf(cb); EventDefinitionCRFBean edc = null; Iterator it = eventDefinitionCRFs.iterator(); while (it.hasNext()) { EventDefinitionCRFBean edcBean = (EventDefinitionCRFBean) it.next(); if (edcBean.getCrfId() == cb.getId()) { edc = edcBean; break; } } // below added 092007 tbh // rules updated 112007 tbh if (status.equals(SubjectEventStatus.LOCKED) || status.equals(SubjectEventStatus.SKIPPED) || status.equals(SubjectEventStatus.STOPPED)) { ecb.setStage(DataEntryStage.LOCKED); // we need to set a SED-wide flag here, because other edcs // in this event can be filled in and change the status, tbh } else if (status.equals(SubjectEventStatus.INVALID)) { ecb.setStage(DataEntryStage.LOCKED); } else if (!cb.getStatus().equals(Status.AVAILABLE)) { ecb.setStage(DataEntryStage.LOCKED); } else if (!cvb.getStatus().equals(Status.AVAILABLE)) { ecb.setStage(DataEntryStage.LOCKED); } // above added 092007-102007 tbh // TODO need to refactor since this is similar to other code, tbh if (edc != null) { // System.out.println("edc is not null, need to set flags"); DisplayEventCRFBean dec = new DisplayEventCRFBean(); dec.setEventDefinitionCRF(edc); // System.out.println("edc.isDoubleEntry()" + // edc.isDoubleEntry() + ecb.getId()); dec.setFlags(ecb, ub, currentRole, edc.isDoubleEntry()); if (dec.isLocked()) { // System.out.println("*** found a locked DEC: // "+edc.getCrfName()); } if (nonEmptyEventCrf.contains(ecb.getId())) { // consider an event crf started only if item data get // created answer.add(dec); } } } return answer; } private ArrayList<DisplayEventDefinitionCRFBean> getUncompletedCRFs(List eventDefinitionCRFs, List eventCRFs, SubjectEventStatus status, Set<Integer> nonEmptyEventCrf, Map<Integer, CRFVersionBean> crfVersionById, Map<Integer, CRFBean> crfById) { int i; HashMap<Integer, Boolean> completed = new HashMap<Integer, Boolean>(); HashMap<Integer, EventCRFBean> startedButIncompleted = new HashMap<Integer, EventCRFBean>(); ArrayList<DisplayEventDefinitionCRFBean> answer = new ArrayList<DisplayEventDefinitionCRFBean>(); /** * A somewhat non-standard algorithm is used here: let answer = empty; * foreach event definition ED, set isCompleted(ED) = false foreach * event crf EC, set isCompleted(EC.getEventDefinition()) = true foreach * event definition ED, if (!isCompleted(ED)) { answer += ED; } return * answer; This algorithm is guaranteed to find all the event * definitions for which no event CRF exists. * * The motivation for using this algorithm is reducing the number of * database hits. * * -jun-we have to add more CRFs here: the event CRF which dones't have * item data yet */ for (i = 0; i < eventDefinitionCRFs.size(); i++) { EventDefinitionCRFBean edcrf = (EventDefinitionCRFBean) eventDefinitionCRFs.get(i); completed.put(new Integer(edcrf.getCrfId()), Boolean.FALSE); startedButIncompleted.put(new Integer(edcrf.getCrfId()), new EventCRFBean()); } for (i = 0; i < eventCRFs.size(); i++) { EventCRFBean ecrf = (EventCRFBean) eventCRFs.get(i); // System.out.println("########event crf id:" + ecrf.getId()); // int crfId = // crfVersionDao.getCRFIdFromCRFVersionId(ecrf.getCRFVersionId()); int crfId = crfVersionById.get(ecrf.getCRFVersionId()).getCrfId(); if (nonEmptyEventCrf.contains(ecrf.getId())) {// this crf has data // already completed.put(new Integer(crfId), Boolean.TRUE); } else {// event crf got created, but no data entered startedButIncompleted.put(new Integer(crfId), ecrf); } } // TODO possible relation to 1689 here, tbh for (i = 0; i < eventDefinitionCRFs.size(); i++) { DisplayEventDefinitionCRFBean dedc = new DisplayEventDefinitionCRFBean(); EventDefinitionCRFBean edcrf = (EventDefinitionCRFBean) eventDefinitionCRFs.get(i); // Display event definition without event CRF data only if it is // available (i.e., not removed) if (edcrf.getStatus().equals(Status.AVAILABLE)) { dedc.setEdc(edcrf); // below added tbh, 112007 to fix bug 1943 if (status.equals(SubjectEventStatus.LOCKED)) { dedc.setStatus(Status.LOCKED); } Boolean b = completed.get(new Integer(edcrf.getCrfId())); EventCRFBean ev = startedButIncompleted.get(new Integer(edcrf.getCrfId())); if (b == null || !b.booleanValue()) { dedc.setEventCRF(ev); answer.add(dedc); } } } return answer; } @SuppressWarnings({ "rawtypes", "unchecked" }) public void populateUncompletedCRFsWithCRFAndVersions(ArrayList<DisplayEventDefinitionCRFBean> uncompletedEventDefinitionCRFs, Map<Integer, CRFVersionBean> crfVersionById, Map<Integer, CRFBean> crfById) { CRFVersionDAO crfVersionDao = new CRFVersionDAO(dataSource); int size = uncompletedEventDefinitionCRFs.size(); for (int i = 0; i < size; i++) { DisplayEventDefinitionCRFBean dedcrf = uncompletedEventDefinitionCRFs.get(i); // CRFBean cb = (CRFBean) // crfDao.findByPK(dedcrf.getEdc().getCrfId()); CRFBean cb = crfById.get(dedcrf.getEdc().getCrfId()); dedcrf.getEdc().setCrf(cb); ArrayList<CRFVersionBean> theVersions = (ArrayList<CRFVersionBean>) crfVersionDao.findAllActiveByCRF(dedcrf.getEdc().getCrfId()); ArrayList<CRFVersionBean> versions = new ArrayList<CRFVersionBean>(); HashMap<String, CRFVersionBean> crfVersionIds = new HashMap<String, CRFVersionBean>(); for (int j = 0; j < theVersions.size(); j++) { CRFVersionBean crfVersion = theVersions.get(j); crfVersionIds.put(String.valueOf(crfVersion.getId()), crfVersion); } if (!dedcrf.getEdc().getSelectedVersionIds().equals("")) { String[] kk = dedcrf.getEdc().getSelectedVersionIds().split(","); for (String string : kk) { if (crfVersionIds.get(string) != null) { versions.add(crfVersionIds.get(string)); } } } else { versions = theVersions; } dedcrf.getEdc().setVersions(versions); uncompletedEventDefinitionCRFs.set(i, dedcrf); } } public DataSource getDataSource() { return dataSource; } public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } }