/*
* This file is part of ADDIS (Aggregate Data Drug Information System).
* ADDIS is distributed from http://drugis.org/.
* Copyright © 2009 Gert van Valkenhoef, Tommi Tervonen.
* Copyright © 2010 Gert van Valkenhoef, Tommi Tervonen, Tijs Zwinkels,
* Maarten Jacobs, Hanno Koeslag, Florin Schimbinschi, Ahmad Kamal, Daniel
* Reid.
* Copyright © 2011 Gert van Valkenhoef, Ahmad Kamal, Daniel Reid, Florin
* Schimbinschi.
* Copyright © 2012 Gert van Valkenhoef, Daniel Reid, Joël Kuiper, Wouter
* Reckman.
* Copyright © 2013 Gert van Valkenhoef, Joël Kuiper.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.drugis.addis.entities;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import org.apache.commons.collections15.Predicate;
import org.apache.commons.collections15.Transformer;
import org.drugis.addis.entities.StudyActivity.UsedBy;
import org.drugis.addis.entities.WhenTaken.RelativeTo;
import org.drugis.addis.entities.treatment.TreatmentDefinition;
import org.drugis.addis.util.EntityUtil;
import org.drugis.common.DateUtil;
import org.drugis.common.EqualsUtil;
import org.drugis.common.beans.ContentAwareListModel;
import org.drugis.common.beans.FilteredObservableList;
import com.jgoodies.binding.list.ArrayListModel;
import com.jgoodies.binding.list.ObservableList;
public class Study extends AbstractNamedEntity<Study> implements TypeWithNotes {
public final static String PROPERTY_INDICATION = "indication";
public final static String PROPERTY_CHARACTERISTICS = "characteristics";
public final static String PROPERTY_ENDPOINTS = "endpoints";
public final static String PROPERTY_ADVERSE_EVENTS = "adverseEvents";
public final static String PROPERTY_POPULATION_CHARACTERISTICS = "populationCharacteristics";
public final static String PROPERTY_ARMS = "arms";
public final static String PROPERTY_EPOCHS = "epochs";
public final static String PROPERTY_STUDY_ACTIVITIES = "studyActivities";
private ObjectWithNotes<Indication> d_indication;
private CharacteristicsMap d_chars = new CharacteristicsMap();
private final ObservableList<StudyOutcomeMeasure<? extends Variable>> d_outcomeMeasures = new ArrayListModel<StudyOutcomeMeasure<? extends Variable>>();
private final ObservableList<StudyOutcomeMeasure<Endpoint>> d_endpoints;
private final ObservableList<StudyOutcomeMeasure<AdverseEvent>> d_adverseEvents;
private final ObservableList<StudyOutcomeMeasure<PopulationCharacteristic>> d_populationChars;
private final ObservableList<Arm> d_arms = new ArrayListModel<Arm>();
private final ObservableList<Epoch> d_epochs = new ArrayListModel<Epoch>();
private final ObservableList<StudyActivity> d_studyActivities = new ArrayListModel<StudyActivity>();
private final Map<MeasurementKey, BasicMeasurement> d_measurements = new HashMap<MeasurementKey, BasicMeasurement>();
private final ObservableList<Note> d_notes = new ArrayListModel<Note>();
public Study() {
this(null, null);
}
public Study(final String id, final Indication i) {
super(id);
d_indication = new ObjectWithNotes<Indication>(i);
setCharacteristic(BasicStudyCharacteristic.CREATION_DATE, DateUtil.getCurrentDateWithoutTime());
setCharacteristic(BasicStudyCharacteristic.TITLE, "");
setCharacteristic(BasicStudyCharacteristic.PUBMED, new PubMedIdList());
final ListDataListener orphanListener = new ListDataListener() {
@Override
public void intervalRemoved(final ListDataEvent e) {
removeOrphanMeasurements();
}
@Override
public void intervalAdded(final ListDataEvent e) {
removeOrphanMeasurements();
}
@Override
public void contentsChanged(final ListDataEvent e) {
removeOrphanMeasurements();
}
};
d_arms.addListDataListener(orphanListener);
new ContentAwareListModel<StudyOutcomeMeasure<?>>(d_outcomeMeasures).addListDataListener(orphanListener);
d_endpoints = convert(Endpoint.class, d_outcomeMeasures);
d_adverseEvents = convert(AdverseEvent.class, d_outcomeMeasures);
d_populationChars = convert(PopulationCharacteristic.class, d_outcomeMeasures);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private <T extends Variable> ObservableList<StudyOutcomeMeasure<T>> convert(final Class<T> cls, final ObservableList<StudyOutcomeMeasure<? extends Variable>> list) {
return (ObservableList) new FilteredObservableList<StudyOutcomeMeasure<? extends Variable>>(list, new Predicate<StudyOutcomeMeasure<? extends Variable>>() {
@Override
public boolean evaluate(final StudyOutcomeMeasure<? extends Variable> obj) {
return cls.equals(obj.getValueClass());
}
});
}
@Override
public Study clone() {
final Study newStudy = new Study();
newStudy.setName(getName());
replace(newStudy.d_notes, d_notes);
newStudy.d_indication = d_indication.clone();
// First clone the basic structure
replace(newStudy.d_arms, d_arms);
replace(newStudy.d_epochs, d_epochs);
replace(newStudy.d_outcomeMeasures, cloneStudyOutcomeMeasures(d_outcomeMeasures));
for (final StudyActivity sa : d_studyActivities) {
newStudy.d_studyActivities.add(sa.clone());
}
for (final MeasurementKey key : d_measurements.keySet()) {
newStudy.d_measurements.put(key, d_measurements.get(key).clone());
}
newStudy.setCharacteristics(cloneCharacteristics());
// Now clone objects that act as keys
for (final Arm arm : d_arms) {
newStudy.replaceArm(arm, arm.clone());
}
for (final Epoch epoch : d_epochs) {
newStudy.replaceEpoch(epoch, epoch.clone());
}
for (int i = 0; i < newStudy.getStudyOutcomeMeasures().size(); i++) {
final StudyOutcomeMeasure<?> oldSom = this.getStudyOutcomeMeasures().get(i);
final StudyOutcomeMeasure<?> newSom = newStudy.getStudyOutcomeMeasures().get(i);
for (int j = 0; j < newSom.getWhenTaken().size(); j++) {
newStudy.updateMeasurementKeys(oldSom, newSom, oldSom.getWhenTaken().get(j), newSom.getWhenTaken().get(j));
}
}
return newStudy;
}
/**
* Replace oldArm with newArm. All references to oldArm will be updated.
* @param oldArm The arm to replace.
* @param newArm The new arm.
*/
public void replaceArm(final Arm oldArm, final Arm newArm) {
transformUsedBy(new Transformer<UsedBy, UsedBy>(){
@Override
public UsedBy transform(final UsedBy ub) {
if (ub.getArm().equals(oldArm)) {
return new UsedBy(newArm, ub.getEpoch());
}
return ub;
}
});
transformMeasurementKeys(new Transformer<MeasurementKey, MeasurementKey>() {
@Override
public MeasurementKey transform(final MeasurementKey key) {
if (key.getArm() != null && key.getArm().equals(oldArm)) {
return new MeasurementKey(key.getStudyOutcomeMeasure(), newArm, key.getWhenTaken());
}
return key;
}
});
d_arms.set(d_arms.indexOf(oldArm), newArm);
}
/**
* Replace oldEpoch with newEpoch. All references to oldEpoch will be updated.
* @param oldEpoch The epoch to replace.
* @param newEpoch The new epoch.
*/
public void replaceEpoch(final Epoch oldEpoch, final Epoch newEpoch) {
transformUsedBy(new Transformer<UsedBy, UsedBy>(){
@Override
public UsedBy transform(final UsedBy ub) {
if (ub.getEpoch().equals(oldEpoch)) {
return new UsedBy(ub.getArm(), newEpoch);
}
return ub;
}
});
for (final StudyOutcomeMeasure<?> som : getStudyOutcomeMeasures()) {
for (int i = 0; i < som.getWhenTaken().size(); ++i) {
final WhenTaken oldWhenTaken = som.getWhenTaken().get(i);
if (oldWhenTaken.getEpoch().equals(oldEpoch)) {
final WhenTaken newWhenTaken = new WhenTaken(oldWhenTaken.getDuration(), oldWhenTaken.getRelativeTo(), newEpoch);
newWhenTaken.commit();
replaceWhenTaken(som, oldWhenTaken, newWhenTaken);
}
}
}
d_epochs.set(d_epochs.indexOf(oldEpoch), newEpoch);
}
public <V extends Variable> void replaceWhenTaken(final StudyOutcomeMeasure<V> som,
final WhenTaken oldWhenTaken, final WhenTaken newWhenTaken) {
if (!newWhenTaken.isCommitted()) {
throw new IllegalArgumentException("The new WhenTaken must be committed");
}
updateMeasurementKeys(som, som, oldWhenTaken, newWhenTaken);
final ObservableList<WhenTaken> whenTakens = som.getWhenTaken();
whenTakens.set(whenTakens.indexOf(oldWhenTaken), newWhenTaken);
}
private <V extends Variable> void updateMeasurementKeys(
final StudyOutcomeMeasure<? extends V> oldSom, final StudyOutcomeMeasure<? extends V> newSom,
final WhenTaken oldWhenTaken, final WhenTaken newWhenTaken) {
transformMeasurementKeys(new Transformer<MeasurementKey, MeasurementKey>() {
@Override
public MeasurementKey transform(final MeasurementKey input) {
if (input.getStudyOutcomeMeasure() == oldSom && input.getWhenTaken().equals(oldWhenTaken)) {
return new MeasurementKey(newSom, input.getArm(), newWhenTaken);
}
return input;
}
});
}
private void transformMeasurementKeys(final Transformer<MeasurementKey, MeasurementKey> transform) {
for (final MeasurementKey oldKey : new HashSet<MeasurementKey>(d_measurements.keySet())) {
final MeasurementKey newKey = transform.transform(oldKey);
if (oldKey != newKey) {
final BasicMeasurement measurement = d_measurements.get(oldKey);
d_measurements.remove(oldKey);
d_measurements.put(newKey, measurement);
}
}
}
private void transformUsedBy(final Transformer<UsedBy, UsedBy> transformer) {
for (final StudyActivity sa : d_studyActivities) {
final Set<UsedBy> newUsedBys = new HashSet<UsedBy>();
for (final UsedBy oldUsedBy : sa.getUsedBy()) {
newUsedBys.add(transformer.transform(oldUsedBy));
}
sa.setUsedBy(newUsedBys);
}
}
private static <T> void replace(final ObservableList<T> target, final Collection<T> newValues) {
target.clear();
target.addAll(newValues);
}
private <T extends Variable> List<StudyOutcomeMeasure<? extends Variable>> cloneStudyOutcomeMeasures(final List<StudyOutcomeMeasure<? extends Variable>> soms) {
final List<StudyOutcomeMeasure<? extends Variable>> list = new ArrayList<StudyOutcomeMeasure<? extends Variable>>();
for (final StudyOutcomeMeasure<? extends Variable> som : soms) {
list.add(som.clone());
}
return list;
}
private CharacteristicsMap cloneCharacteristics() {
final CharacteristicsMap cm = new CharacteristicsMap();
for (final Characteristic c : d_chars.keySet()) {
cm.put(c, d_chars.get(c).clone());
}
return cm;
}
public ObservableList<Arm> getArms() {
return d_arms;
}
public ObservableList<Epoch> getEpochs() {
return d_epochs;
}
public ObservableList<StudyActivity> getStudyActivities() {
return d_studyActivities;
}
/**
* Set a particular studyActivity as being used by an (arm, epoch) pair.
* Constraint: At most one StudyActivity exists for each (arm, epoch) pair;
* any previous entry will be overwritten.
*
* @param arm
* @param epoch
* @param activity
* A StudyActivity or null; when null, clears any activity at
* that (arm, epoch) pair.
*/
public void setStudyActivityAt(final Arm arm, final Epoch epoch, StudyActivity activity) {
assertContains(d_arms, arm);
assertContains(d_epochs, epoch);
if (activity == null) {
clearStudyActivityAt(arm, epoch);
} else {
assertContains(d_studyActivities, activity);
activity = d_studyActivities.get(d_studyActivities.indexOf(activity)); // ensure we have the *same* object, not just an *equal* one.
clearStudyActivityAt(arm, epoch);
final Set<UsedBy> usedBy = new HashSet<UsedBy>(activity.getUsedBy());
usedBy.add(new UsedBy(arm, epoch));
activity.setUsedBy(usedBy);
}
}
public StudyActivity getStudyActivityAt(final Arm arm, final Epoch epoch) {
final UsedBy coordinate = new UsedBy(arm, epoch);
for (final StudyActivity activity : d_studyActivities) {
if (activity.getUsedBy().contains(coordinate)) {
return activity;
}
}
return null;
}
private <E> void assertContains(final ObservableList<E> list, final E item) {
if (!list.contains(item)) {
throw new IllegalArgumentException("The "
+ item.getClass().getSimpleName() + " <" + item
+ " > does not exist in this study");
}
}
private void clearStudyActivityAt(final Arm arm, final Epoch epoch) {
final UsedBy coordinate = new UsedBy(arm, epoch);
for (final StudyActivity activity : d_studyActivities) {
if (activity.getUsedBy().contains(coordinate)) {
final Set<UsedBy> usedBy = new HashSet<UsedBy>(activity.getUsedBy());
usedBy.remove(coordinate);
activity.setUsedBy(usedBy);
}
}
}
public Set<TreatmentDefinition> getTreatmentDefinitions() {
final Set<TreatmentDefinition> treatments = new HashSet<TreatmentDefinition>();
for (final Arm a : getArms()) {
treatments.add(getTreatmentDefinition(a));
}
return treatments;
}
public Indication getIndication() {
return d_indication.getValue();
}
public void setIndication(final Indication indication) {
final Indication oldInd = d_indication.getValue();
d_indication.setValue(indication);
firePropertyChange(PROPERTY_INDICATION, oldInd, indication);
}
@Override
public Set<Entity> getDependencies() {
final Set<Entity> dep = new HashSet<Entity>();
dep.addAll(getOutcomeMeasures());
dep.addAll(extractVariables(getPopulationChars()));
dep.add(d_indication.getValue());
for (final StudyActivity sa : getStudyActivities()) {
dep.addAll(sa.getDependencies());
}
return dep;
}
public Object getCharacteristic(final Characteristic c) {
return d_chars.get(c) != null ? d_chars.get(c).getValue() : null;
}
public void setCharacteristic(final BasicStudyCharacteristic c, final Object val) {
final ObjectWithNotes<?> charVal = getCharacteristicWithNotes(c);
if (charVal != null) {
charVal.setValue(val);
setCharacteristicWithNotes(c, charVal); // FIXME: this is a hack because d_chars is exposed & also firing events.
} else {
setCharacteristicWithNotes(c, new ObjectWithNotes<Object>(val));
}
}
public ObjectWithNotes<?> getCharacteristicWithNotes(final Characteristic c) {
return d_chars.get(c);
}
public void setCharacteristicWithNotes(final BasicStudyCharacteristic c, final ObjectWithNotes<?> val) {
d_chars.put(c, val);
firePropertyChange(PROPERTY_CHARACTERISTICS, c, c);
}
public void setCharacteristics(final CharacteristicsMap m) {
d_chars = m;
}
public CharacteristicsMap getCharacteristics() {
return d_chars;
}
public void setName(final String name) {
final String oldVal = d_name;
d_name = name;
firePropertyChange(PROPERTY_NAME, oldVal, d_name);
}
@Override
public String toString() {
return getName();
}
@Override
public boolean equals(final Object o) {
if (o instanceof Study) {
final Study other = (Study) o;
if (other.getName() == null) {
return getName() == null;
}
return other.getName().equals(getName());
}
return false;
}
@Override
public int hashCode() {
return getName() == null ? 0 : getName().hashCode();
}
@Override
public int compareTo(final Study other) {
return getName().compareTo(other.getName());
}
public void setMeasurement(final StudyOutcomeMeasure<? extends Variable> som, final BasicMeasurement m) {
setMeasurement(som, null, m);
}
public void setMeasurement(final StudyOutcomeMeasure<? extends Variable> som, final Arm a, final BasicMeasurement m) {
forceLegalArguments(som, a, m);
d_measurements.put(new MeasurementKey(som, a, defaultMeasurementMoment()), m);
}
public BasicMeasurement setMeasurement(final StudyOutcomeMeasure<? extends Variable> som, final Arm a, WhenTaken wt, final BasicMeasurement m) {
return d_measurements.put(new MeasurementKey(som, a, wt), m);
}
private <T extends Variable> void forceLegalArguments(final StudyOutcomeMeasure<? extends Variable> som, final Arm a, final Measurement m) {
if(som == null) {
throw new IllegalArgumentException("StudyOutcomeMeasure may not be null for measurement " + m);
}
Variable v = som.getValue();
boolean studyContains = false;
for(StudyOutcomeMeasure<? extends Variable> om : getStudyOutcomeMeasures()) {
if (EqualsUtil.equal(om.getValue(), v)) studyContains = true;
}
if (!studyContains) {
throw new IllegalArgumentException("Variable " + som.getValue() + " not in study");
}
if (a != null && !d_arms.contains(a)) {
throw new IllegalArgumentException("Arm " + a + " not in study");
}
if (m != null && v != null && !m.isOfType(v.getVariableType())) {
throw new IllegalArgumentException("Measurement does not conform with outcome");
}
if (findTreatmentEpoch() == null) {
throw new IllegalStateException("Attempting to add measurement before treatment epoch is defined.");
}
}
public BasicMeasurement getMeasurement(final StudyOutcomeMeasure<? extends Variable> som , final Arm a, final WhenTaken wt) {
return d_measurements.get(new MeasurementKey(som, a, wt));
}
public BasicMeasurement getMeasurement(final StudyOutcomeMeasure<? extends Variable> som , final Arm a) {
return getMeasurement(som, a, defaultMeasurementMoment());
}
public BasicMeasurement getMeasurement(final Variable v, final Arm a, final WhenTaken wt) {
StudyOutcomeMeasure<? extends Variable> som = findStudyOutcomeMeasure(v);
return getMeasurement(som != null ? som : new StudyOutcomeMeasure<Variable>(v, wt), a, wt);
}
public BasicMeasurement getMeasurement(final Variable v, final Arm a) {
final WhenTaken mm = defaultMeasurementMoment();
return mm == null ? null : getMeasurement(v, a, mm);
}
public BasicMeasurement getMeasurement(final Variable v) {
return getMeasurement(v, null);
}
public List<OutcomeMeasure> getOutcomeMeasures() {
final List<OutcomeMeasure> sortedList = new ArrayList<OutcomeMeasure>(extractVariables(getEndpoints()));
sortedList.addAll(extractVariables(getAdverseEvents()));
Collections.sort(sortedList);
return sortedList;
}
public static <T extends Variable> List<T> extractVariables(final List<StudyOutcomeMeasure<T>> soms) {
final List<T> vars = new ArrayList<T>();
for (final StudyOutcomeMeasure<T> som : soms) {
vars.add(som.getValue());
}
return vars;
}
public List<? extends Variable> getVariables(final Class<? extends Variable> type) {
return extractVariables(getStudyOutcomeMeasures(type));
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public <T extends Variable> ObservableList<StudyOutcomeMeasure<T>> getStudyOutcomeMeasures(final Class<T> type) {
if (type == Endpoint.class) {
return (ObservableList) getEndpoints();
} else if (type == AdverseEvent.class) {
return (ObservableList) getAdverseEvents();
} else if (type == PopulationCharacteristic.class) {
return (ObservableList) getPopulationChars();
} else if (type == StudyOutcomeMeasure.EmptyVariable.class) {
return new ArrayListModel<StudyOutcomeMeasure<T>>(Collections.<StudyOutcomeMeasure<T>>emptySet());
}
throw new IllegalArgumentException("Unknown variable type " + type.getSimpleName());
}
public ObservableList<StudyOutcomeMeasure<? extends Variable>> getStudyOutcomeMeasures() {
return d_outcomeMeasures;
}
public void addVariable(final Variable om) {
addVariable(om, null);
}
public void addVariable(final Variable om, final WhenTaken wt) {
if (om instanceof Endpoint) {
getEndpoints().add(new StudyOutcomeMeasure<Endpoint>(((Endpoint) om), wt));
} else if (om instanceof AdverseEvent) {
getAdverseEvents().add(new StudyOutcomeMeasure<AdverseEvent>(((AdverseEvent) om), wt));
} else if (om instanceof PopulationCharacteristic) {
getPopulationChars().add(new StudyOutcomeMeasure<PopulationCharacteristic>(((PopulationCharacteristic) om), wt));
} else {
throw new IllegalStateException("Illegal OutcomeMeasure type " + om.getClass());
}
}
private void removeOrphanMeasurements() {
for (final MeasurementKey k : new HashSet<MeasurementKey>(d_measurements.keySet())) {
if (orphanKey(k)) {
d_measurements.remove(k);
}
}
}
public BasicMeasurement buildDefaultMeasurement(final Variable v, final Arm a) {
return v.buildMeasurement(a == null ? getSampleSize() : a.getSize());
}
private boolean orphanKey(final MeasurementKey k) {
if (k.getVariable() instanceof StudyOutcomeMeasure.EmptyVariable) {
return false;
}
StudyOutcomeMeasure<? extends Variable> som = findStudyOutcomeMeasure(k.getVariable());
if (som == null) {
return true;
}
if (!som.getWhenTaken().contains(k.getWhenTaken())) {
return true;
}
// OutcomeMeasure measurement
if (k.getVariable() instanceof OutcomeMeasure) {
if (!d_arms.contains(k.getArm())) {
return true;
}
return false;
}
// PopulationChar measurements
if (k.getVariable() instanceof PopulationCharacteristic) {
if (k.getArm() != null && !d_arms.contains(k.getArm())) {
return true;
}
return false;
}
throw new IllegalStateException(k + " is not a valid measurement key");
}
public int getSampleSize() {
int s = 0;
for (final Arm pg : d_arms) {
s += pg.getSize();
}
return s;
}
public Map<MeasurementKey, BasicMeasurement> getMeasurements() {
return d_measurements;
}
public ObjectWithNotes<?> getIndicationWithNotes() {
return d_indication;
}
public void addStudyOutcomeMeasure(final StudyOutcomeMeasure<?> value) {
d_outcomeMeasures.add(value);
}
public TreatmentActivity getTreatment(final Arm arm) {
return getActivity(arm) instanceof TreatmentActivity ? (TreatmentActivity) getActivity(arm) : null;
}
public Activity getActivity(final Arm arm) {
assertContains(d_arms, arm);
if (d_epochs.isEmpty()) {
return null;
}
final Epoch epoch = findTreatmentEpoch();
if (epoch == null) {
return null;
}
return getStudyActivityAt(arm, epoch).getActivity();
}
public Epoch findTreatmentEpoch() {
for (final Epoch epoch : d_epochs) {
if (isTreatmentEpoch(epoch)) {
return epoch;
}
}
return null;
}
public WhenTaken defaultMeasurementMoment() {
return treatmentWhenTaken(RelativeTo.BEFORE_EPOCH_END);
}
public WhenTaken baselineMeasurementMoment() {
return treatmentWhenTaken(RelativeTo.FROM_EPOCH_START);
}
private WhenTaken treatmentWhenTaken(final RelativeTo relativeTo) {
final Epoch epoch = findTreatmentEpoch();
if (epoch == null) {
return null;
}
final WhenTaken whenTaken = new WhenTaken(EntityUtil.createDuration("P0D"), relativeTo, epoch);
whenTaken.commit();
return whenTaken;
}
private boolean isTreatmentEpoch(final Epoch epoch) {
for (final Arm arm : d_arms) {
final StudyActivity sa = getStudyActivityAt(arm, epoch);
if (sa == null || !(sa.getActivity() instanceof TreatmentActivity)) {
return false;
}
}
return true;
}
public Epoch findEpochWithActivity(final Activity a) {
for (final Epoch epoch : d_epochs) {
if (isActivityEpoch(epoch, a)) {
return epoch;
}
}
return null;
}
private boolean isActivityEpoch(final Epoch epoch, final Activity a) {
for (final Arm arm : d_arms) {
final StudyActivity sa = getStudyActivityAt(arm, epoch);
if (sa == null || !(sa.getActivity().equals(a))) {
return false;
}
}
return true;
}
public TreatmentDefinition getTreatmentDefinition(final Arm a) {
final Activity activity = getActivity(a);
if (activity instanceof TreatmentActivity) {
return buildTreatmentDefinition((TreatmentActivity) activity);
}
return new TreatmentDefinition();
}
private static TreatmentDefinition buildTreatmentDefinition(final TreatmentActivity activity) {
final List<Drug> drugs = new ArrayList<Drug>();
for(final DrugTreatment ta : activity.getTreatments()) {
drugs.add(ta.getDrug());
}
return TreatmentDefinition.createTrivial(drugs);
}
@Override
public boolean deepEquals(final Entity obj) {
if (!equals(obj)) {
return false;
}
final Study other = (Study) obj;
return EntityUtil.deepEqual(other.getIndication(), getIndication())
&& EntityUtil.deepEqual(other.getCharacteristics(), getCharacteristics())
&& EntityUtil.deepEqual(Study.extractVariables(other.getEndpoints()), extractVariables(getEndpoints()))
&& EntityUtil.deepEqual(Study.extractVariables(other.getAdverseEvents()), extractVariables(getAdverseEvents()))
&& EntityUtil.deepEqual(Study.extractVariables(other.getPopulationChars()), extractVariables(getPopulationChars()))
&& EntityUtil.deepEqual(other.getArms(), getArms())
&& EntityUtil.deepEqual(other.getEpochs(), getEpochs())
&& EntityUtil.deepEqual(other.getStudyActivities(), getStudyActivities())
&& EntityUtil.deepEqual(other.getMeasurements(), getMeasurements())
&& EqualsUtil.equal(other.getNotes(), getNotes());
}
public Arm findArm(final String armName) {
for (final Arm a : d_arms) {
if (a.getName().equals(armName)) {
return a;
}
}
return null;
}
public Epoch findEpoch(final String epochName) {
for (final Epoch e : d_epochs) {
if (e.getName().equals(epochName)) {
return e;
}
}
return null;
}
public StudyActivity findStudyActivity(final String activityName) {
for (final StudyActivity sa : d_studyActivities) {
if (sa.getName().equals(activityName)) {
return sa;
}
}
return null;
}
/**
* Creates an Arm, adds it to the Study and creates an appropriate
* TreatmentActivity in the last Epoch.
*
* @param name
* Name of the arm to be created.
* @param size
* Number of subjects in the arm to be created.
* @param drug
* The drug administered.
* @param dose
* The dose administered.
* @return The created arm, already added and embedded in the study
* structure.
*/
public Arm createAndAddArm(final String name, final Integer size, final Drug drug, final AbstractDose dose) {
final Arm arm = new Arm(name, size);
getArms().add(arm);
final StudyActivity studyActivity = new StudyActivity(name + " treatment",
new TreatmentActivity(new DrugTreatment(drug, dose)));
getStudyActivities().add(studyActivity);
final Epoch epoch = getEpochs().get(getEpochs().size() - 1);
this.setStudyActivityAt(arm, epoch, studyActivity);
return arm;
}
/**
* @param wt TODO
* @return The Drugs that have at least one Arm with a complete measurement
* for the Variable v.
*/
public Set<TreatmentDefinition> getMeasuredTreatmentDefinitions(final Variable v, final WhenTaken wt) {
final Set<TreatmentDefinition> definitions = new HashSet<TreatmentDefinition>();
for (final TreatmentDefinition d : getTreatmentDefinitions()) {
if (wt != null && isMeasured(v, d, wt)) {
definitions.add(d);
}
}
return definitions;
}
public Set<TreatmentDefinition> getMeasuredTreatmentDefinitions(final Variable v) {
return getMeasuredTreatmentDefinitions(v, defaultMeasurementMoment());
}
public ObservableList<Arm> getMeasuredArms(final Variable v, final TreatmentDefinition d) {
return getMeasuredArms(v, d, defaultMeasurementMoment());
}
public ObservableList<Arm> getMeasuredArms(final Variable v, final TreatmentDefinition d, final WhenTaken wt) {
return new FilteredObservableList<Arm>(getArms(d), new IsMeasuredFilter(v, wt));
}
private boolean isMeasured(final Variable v, final TreatmentDefinition d, final WhenTaken wt) {
for (final Arm a : getArms(d)) {
if (isMeasured(v, a, wt)) {
return true;
}
}
return false;
}
public boolean isMeasured(final Variable v, final Arm a, final WhenTaken wt) {
return getMeasurement(v, a, wt) != null && getMeasurement(v, a, wt).isComplete();
}
public boolean isMeasured(final Variable v, final Arm a) {
return getMeasurement(v, a) != null && getMeasurement(v, a).isComplete();
}
private ObservableList<Arm> getArms(final TreatmentDefinition d) {
return new FilteredObservableList<Arm>(d_arms, new TreatmentArmFilter(d));
}
public ObservableList<StudyOutcomeMeasure<Endpoint>> getEndpoints() {
return d_endpoints;
}
public ObservableList<StudyOutcomeMeasure<AdverseEvent>> getAdverseEvents() {
return d_adverseEvents;
}
public ObservableList<StudyOutcomeMeasure<PopulationCharacteristic>> getPopulationChars() {
return d_populationChars;
}
public static <T extends Variable> List<StudyOutcomeMeasure<T>> wrapVariables(final List<T> vars) {
final List<StudyOutcomeMeasure<T>> soms = new ArrayList<StudyOutcomeMeasure<T>>();
for (final T v : vars) {
soms.add(wrapVariable(v));
}
return soms;
}
public class IsMeasuredFilter implements Predicate<Arm> {
private final Variable d_v;
private final WhenTaken d_wt;
public IsMeasuredFilter(final Variable v, final WhenTaken wt) {
d_v = v;
d_wt = wt;
}
@Override
public boolean evaluate(final Arm a) {
return isMeasured(d_v, a, d_wt);
}
}
public class TreatmentArmFilter implements Predicate<Arm> {
private final TreatmentDefinition d_d;
public TreatmentArmFilter(final TreatmentDefinition d) {
d_d = d;
}
@Override
public boolean evaluate(final Arm a) {
return d_d.match(Study.this, a);
}
}
@Override
public ObservableList<Note> getNotes() {
return d_notes;
}
public static <T extends Variable> StudyOutcomeMeasure<T> wrapVariable(final T om) {
return new StudyOutcomeMeasure<T>(om);
}
@SuppressWarnings("unchecked")
public <T extends Variable> StudyOutcomeMeasure<T> findStudyOutcomeMeasure(final T v) {
final ObservableList<StudyOutcomeMeasure<T>> soms = getStudyOutcomeMeasures((Class<T>)v.getClass());
for (final StudyOutcomeMeasure<T> som : soms) {
if (EqualsUtil.equal(som.getValue(), v)) {
return som;
}
}
return null;
}
public Arm findMatchingArm(TreatmentDefinition def) {
for (Arm a : getArms()) {
TreatmentActivity treatment = getTreatment(a);
if (treatment != null && def.match(treatment)) {
return a;
}
}
return null;
}
}