org.drugis.addis.imports.ClinicaltrialsImporter.java Source code

Java tutorial

Introduction

Here is the source code for org.drugis.addis.imports.ClinicaltrialsImporter.java

Source

/*
 * 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, Jol Kuiper, Wouter
 * Reckman.
 * Copyright  2013 Gert van Valkenhoef, Jol 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.imports;

import static org.apache.commons.collections15.CollectionUtils.find;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;

import org.apache.commons.collections15.CollectionUtils;
import org.apache.commons.collections15.Predicate;
import org.apache.commons.collections15.PredicateUtils;
import org.apache.commons.lang.StringUtils;
import org.drugis.addis.entities.AdverseEvent;
import org.drugis.addis.entities.Arm;
import org.drugis.addis.entities.BasicContinuousMeasurement;
import org.drugis.addis.entities.BasicMeasurement;
import org.drugis.addis.entities.BasicRateMeasurement;
import org.drugis.addis.entities.BasicStudyCharacteristic;
import org.drugis.addis.entities.BasicStudyCharacteristic.Allocation;
import org.drugis.addis.entities.BasicStudyCharacteristic.Blinding;
import org.drugis.addis.entities.ContinuousVariableType;
import org.drugis.addis.entities.DrugTreatment;
import org.drugis.addis.entities.Endpoint;
import org.drugis.addis.entities.Epoch;
import org.drugis.addis.entities.Indication;
import org.drugis.addis.entities.Note;
import org.drugis.addis.entities.ObjectWithNotes;
import org.drugis.addis.entities.PopulationCharacteristic;
import org.drugis.addis.entities.PredefinedActivity;
import org.drugis.addis.entities.PubMedId;
import org.drugis.addis.entities.PubMedIdList;
import org.drugis.addis.entities.RateVariableType;
import org.drugis.addis.entities.Source;
import org.drugis.addis.entities.Study;
import org.drugis.addis.entities.StudyActivity;
import org.drugis.addis.entities.StudyOutcomeMeasure;
import org.drugis.addis.entities.TreatmentActivity;
import org.drugis.addis.entities.Variable;
import org.drugis.addis.entities.WhenTaken;
import org.drugis.addis.entities.WhenTaken.RelativeTo;
import org.drugis.addis.util.EntityUtil;
import org.drugis.common.EqualsUtil;
import org.drugis.common.gui.ErrorDialog;

public class ClinicaltrialsImporter {

    private static final String INCLUSION_CRITERIA = "inclusion criteria";
    private static final String EXCLUSION_CRITERIA = "exclusion criteria";

    public static Study getClinicaltrialsData(String url, boolean importResults)
            throws MalformedURLException, IOException {
        Study study = new Study("", new Indication(0l, ""));
        getClinicaltrialsData(study, url, importResults);
        return study;
    }

    static void getClinicaltrialsData(Study study, String url, boolean importResults) throws IOException {
        URLConnection conn = new URL(url).openConnection();
        conn.setRequestProperty("Accept", "application/xml");
        getClinicaltrialsData(study, conn.getInputStream(), importResults);
    }

    static void getClinicaltrialsData(Study study, InputStream is, boolean importResults) {
        JAXBContext jc;
        try {
            jc = JAXBContext.newInstance("org.drugis.addis.imports");
            ClinicalStudy studyImport = (ClinicalStudy) jc.createUnmarshaller().unmarshal(is);
            new ClinicaltrialsImporter(study, studyImport, importResults).importStudy();
        } catch (Exception e) {
            String exceptionTitle = "Could not complete import from ClinicalTrials.gov";
            StringBuilder errorMessage = new StringBuilder();
            errorMessage.append("Something went wrong while importing from ClinicalTrials.gov.");
            if (importResults) {
                errorMessage.append(" Please try again without importing results.");
            }
            errorMessage.append("\n\nWhen reporting this problem please include the NCT-ID where possible.");
            ErrorDialog.showDialog(e, exceptionTitle, errorMessage.toString(), true);
        }
    }

    private Study d_study;
    private ClinicalStudy d_studyImport;
    private boolean d_importResults;
    private Epoch d_mainEpoch;

    public ClinicaltrialsImporter(Study study, ClinicalStudy studyImport, boolean importResults) {
        d_study = study;
        d_studyImport = studyImport;
        d_importResults = importResults;
    }

    public void importStudy() {
        importStudyCharacteristics();

        importReferences();

        // Add default epochs + the study arms
        d_mainEpoch = new Epoch("Main phase", null);
        d_study.getEpochs().add(d_mainEpoch);
        importArms();
        if (d_study.getCharacteristic(BasicStudyCharacteristic.ALLOCATION).equals(Allocation.RANDOMIZED)) {
            addRandomizationEpochAndActivity();
        }

        importStudyOutcomeMeasures();

        if (shouldImportResults()) {
            importAdverseEvents();
            importPopulationCharacteristics();
        }

        // Import date & Source.
        d_study.setCharacteristicWithNotes(BasicStudyCharacteristic.CREATION_DATE,
                objectWithNote(new Date(), d_studyImport.getRequiredHeader().getDownloadDate().trim()));
        d_study.setCharacteristicWithNotes(BasicStudyCharacteristic.SOURCE,
                objectWithNote(Source.CLINICALTRIALS, d_studyImport.getRequiredHeader().getUrl().trim()));
    }

    /**
     * @return true if results import has been requested AND results are available.
     */
    private boolean shouldImportResults() {
        return d_importResults && d_studyImport.getClinicalResults() != null;
    }

    private void importStudyCharacteristics() {
        // ID  (& ID note =study url)
        d_study.setName(d_studyImport.getIdInfo().getNctId());
        d_study.getNotes().add(new Note(Source.CLINICALTRIALS, d_studyImport.getIdInfo().getNctId()));

        // Title
        d_study.setCharacteristicWithNotes(BasicStudyCharacteristic.TITLE,
                objectWithNote(d_studyImport.getBriefTitle().trim(), createTitleNote(d_studyImport)));

        // Study Centers
        d_study.setCharacteristicWithNotes(BasicStudyCharacteristic.CENTERS,
                objectWithNote(d_studyImport.getLocation().size(), createCentersNote(d_studyImport)));

        d_study.setCharacteristicWithNotes(BasicStudyCharacteristic.ALLOCATION,
                objectWithNote(guessAllocation(d_studyImport), d_studyImport.getStudyDesign().trim()));

        d_study.setCharacteristicWithNotes(BasicStudyCharacteristic.BLINDING,
                objectWithNote(guessBlinding(d_studyImport), d_studyImport.getStudyDesign().trim()));

        // Objective
        d_study.setCharacteristicWithNotes(BasicStudyCharacteristic.OBJECTIVE,
                objectWithNote(deindent(d_studyImport.getBriefSummary().getTextblock()),
                        deindent(d_studyImport.getBriefSummary().getTextblock())));

        // Indication note
        d_study.getIndicationWithNotes().getNotes()
                .add(new Note(Source.CLINICALTRIALS, createIndicationNote(d_studyImport)));

        // Start and end date
        d_study.setCharacteristicWithNotes(BasicStudyCharacteristic.STUDY_START,
                objectWithNote(guessDate(d_studyImport.getStartDate()),
                        d_studyImport.getStartDate() != null ? d_studyImport.getStartDate().getContent() : ""));
        d_study.setCharacteristicWithNotes(BasicStudyCharacteristic.STUDY_END, objectWithNote(
                guessDate(d_studyImport.getCompletionDate()),
                d_studyImport.getCompletionDate() != null ? d_studyImport.getCompletionDate().getContent() : ""));
        d_study.setCharacteristicWithNotes(BasicStudyCharacteristic.STATUS,
                objectWithNote(guessStatus(d_studyImport), d_studyImport.getOverallStatus().trim()));

        String criteria = deindent(d_studyImport.getEligibility().getCriteria().getTextblock());
        d_study.setCharacteristicWithNotes(BasicStudyCharacteristic.INCLUSION,
                objectWithNote(guessInclusionCriteria(criteria), criteria));
        d_study.setCharacteristicWithNotes(BasicStudyCharacteristic.EXCLUSION,
                objectWithNote(guessExclusion(criteria), criteria));
    }

    private void importReferences() {
        PubMedIdList list = (PubMedIdList) d_study.getCharacteristic(BasicStudyCharacteristic.PUBMED);

        for (ReferenceStruct ref : d_studyImport.getReference()) {
            if (ref.getPMID() != null) {
                list.add(new PubMedId(ref.getPMID()));
            }
        }

        if (d_importResults && d_studyImport.getResultsReference() != null) {
            for (ReferenceStruct ref : d_studyImport.getResultsReference()) {
                if (ref.getPMID() != null) {
                    list.add(new PubMedId(ref.getPMID()));
                }
            }
        }
    }

    private WhenTaken createDefaultWhenTaken(StudyOutcomeMeasure<? extends Variable> som) {
        WhenTaken wt = new WhenTaken(EntityUtil.createDuration("P0D"), RelativeTo.BEFORE_EPOCH_END, d_mainEpoch);
        wt.commit();
        som.getWhenTaken().add(wt);
        return wt;
    }

    private void importArms() {
        // Add note to the study-arms.
        Map<String, Arm> armLabels = new HashMap<String, Arm>();
        for (ArmGroupStruct ag : d_studyImport.getArmGroup()) {
            Arm arm = new Arm(ag.getArmGroupLabel(), 0);
            d_study.getArms().add(arm);
            StringBuilder noteBuilder = new StringBuilder();
            noteBuilder.append(formatIfAny("Arm Name", ag.getArmGroupLabel(), ""));
            noteBuilder.append(formatIfAny("Arm Type", ag.getArmGroupType(), "\n"));
            noteBuilder.append(formatIfAny("Arm Description", ag.getDescription(), "\n"));

            arm.getNotes().add(new Note(Source.CLINICALTRIALS, noteBuilder.toString()));
            armLabels.put(ag.getArmGroupLabel(), arm);
        }

        // Add interventions to the study-arms.
        List<String> interventionNames = new ArrayList<String>();
        for (InterventionStruct i : d_studyImport.getIntervention()) {
            interventionNames.add(i.getInterventionName());
        }
        uniqueify(interventionNames);
        for (int i = 0; i < d_studyImport.getIntervention().size(); i++) {
            InterventionStruct intervention = d_studyImport.getIntervention().get(i);
            StringBuilder noteBuilder = new StringBuilder();
            noteBuilder.append(formatIfAny("Intervention Name", intervention.getInterventionName(), "\n"));
            noteBuilder.append(formatIfAny("Intervention Type", intervention.getInterventionType(), "\n"));
            noteBuilder.append(formatIfAny("Intervention Description", intervention.getDescription(), "\n"));

            boolean notAssigned = true;
            for (String label : intervention.getArmGroupLabel()) {
                StudyActivity act = new StudyActivity(interventionNames.get(i),
                        new TreatmentActivity(new DrugTreatment(null, null)));
                d_study.getStudyActivities().add(act);
                act.getNotes().add(new Note(Source.CLINICALTRIALS, intervention.getDescription()));
                Arm arm = armLabels.get(label);
                if (arm != null) {
                    notAssigned = false;
                    Note note = arm.getNotes().get(0);
                    note.setText(note.getText() + "\n" + noteBuilder.toString());
                    d_study.setStudyActivityAt(arm, d_mainEpoch, act);
                }
            }
            // Add the intervention note to all arms if it can't be mapped to any single arm
            if (notAssigned) {
                for (Arm arm : d_study.getArms()) {
                    Note note = arm.getNotes().get(0);
                    note.setText(note.getText() + "\n" + noteBuilder.toString());
                }
            }

            // Add Arm sizes to arms
            if (shouldImportResults()) {
                BaselineStruct baseline = d_studyImport.getClinicalResults().getBaseline();
                for (final GroupStruct xmlArm : baseline.groupList.group) {
                    Arm arm = findArmWithName(d_study, xmlArm.getTitle());
                    if (arm != null) {
                        MeasureCategoryStruct measures = baseline.getMeasureList().measure
                                .get(0).categoryList.category.get(0);
                        MeasurementStruct measurement = findMeasurement(xmlArm.groupId,
                                measures.getMeasurementList().measurement);
                        if (measurement != null) {
                            arm.setSize(convertToInteger(measurement.getValueAttribute()));
                        }
                    }
                }
            }
        }
    }

    private void addRandomizationEpochAndActivity() {
        Epoch randomizationEpoch = new Epoch("Randomization", null);
        d_study.getEpochs().add(0, randomizationEpoch);
        StudyActivity randomizationActivity = new StudyActivity("Randomization", PredefinedActivity.RANDOMIZATION);
        d_study.getStudyActivities().add(randomizationActivity);
        for (Arm a : d_study.getArms()) {
            d_study.setStudyActivityAt(a, randomizationEpoch, randomizationActivity);
        }
    }

    private void importStudyOutcomeMeasures() {
        for (ProtocolOutcomeStruct outcome : d_studyImport.getPrimaryOutcome()) {
            importStudyOutcomeMeasure(outcome, true);
        }
        for (ProtocolOutcomeStruct outcome : d_studyImport.getSecondaryOutcome()) {
            importStudyOutcomeMeasure(outcome, false);
        }
    }

    private void importStudyOutcomeMeasure(ProtocolOutcomeStruct outcome, boolean isPrimary) {
        StudyOutcomeMeasure<Endpoint> som = new StudyOutcomeMeasure<Endpoint>(Endpoint.class);
        som.setIsPrimary(isPrimary);

        StringBuilder noteBuilder = new StringBuilder(outcome.getMeasure());
        noteBuilder.append(formatIfAny("Description", outcome.getDescription(), "\n"));
        noteBuilder.append(formatIfAny("Time frame", outcome.getTimeFrame(), "\n"));
        noteBuilder.append(formatIfAny("Safety issue", outcome.getSafetyIssue(), "\n"));
        som.getNotes().add(new Note(Source.CLINICALTRIALS, noteBuilder.toString()));

        WhenTaken wt = createDefaultWhenTaken(som);
        d_study.getEndpoints().add(som);
        if (shouldImportResults()) {
            importMeasurements(outcome, som, wt);
        }
    }

    private void importMeasurements(final ProtocolOutcomeStruct outcome, StudyOutcomeMeasure<Endpoint> som,
            WhenTaken wt) {
        List<ResultsOutcomeStruct> outcomes = d_studyImport.getClinicalResults().getOutcomeList().outcome;
        ResultsOutcomeStruct results = find(outcomes, new Predicate<ResultsOutcomeStruct>() {
            public boolean evaluate(ResultsOutcomeStruct object) {
                return object.getTitle().equals(outcome.getMeasure());
            }
        });
        importMeasurements(som, wt, results.measureList.measure, results.getGroupList().group);
    }

    private void importMeasurements(StudyOutcomeMeasure<? extends Variable> som, WhenTaken wt,
            List<MeasureStruct> measurements, List<GroupStruct> groups) {
        for (GroupStruct xmlArm : groups) {
            // Fails for multiple epochs since we treat them as categorical variables (seems to be the default)

            MeasureStruct total = measurements.get(0);
            MeasureStruct second = measurements.get(1);
            List<MeasureCategoryStruct> categories = second.getCategoryList().getCategory();
            if (categories.size() == 1) {
                if (total.getParam().equals("Number") && second.getParam().equals("Number")) {
                    addBasicRateMeasurement(d_study, som, wt, xmlArm, measurements);
                }
                if (total.getParam().equals("Number") && !second.getParam().equals("Number")) {
                    addContinuousMeasurement(d_study, som, wt, xmlArm, measurements);
                }
            } else if (categories.size() > 1) { // Categorical variable
                addFrequencyMeasurement(d_study, som, wt, xmlArm, second);
            }
        }
    }

    private void importAdverseEvents() {
        ReportedEventsStruct reportedEvents = d_studyImport.clinicalResults.reportedEvents;
        for (EventCategoryStruct sae : reportedEvents.seriousEvents.categoryList.category) {
            importEvents(reportedEvents, sae);
        }

        for (EventCategoryStruct ae : reportedEvents.otherEvents.categoryList.category) {
            importEvents(reportedEvents, ae);
        }
    }

    private void importEvents(ReportedEventsStruct reportedEvents, EventCategoryStruct categories) {
        for (EventStruct event : categories.getEventList().event) {
            StudyOutcomeMeasure<AdverseEvent> som = new StudyOutcomeMeasure<AdverseEvent>(AdverseEvent.class);
            String noteStr = event.getSubTitle().value + " (" + categories.title + ")";
            noteStr = addIfAny(noteStr, "Description", event.description);
            noteStr = addIfAny(noteStr, "Assessment", event.assessment);

            WhenTaken wt = createDefaultWhenTaken(som);
            d_study.getAdverseEvents().add(som);

            som.getNotes().add(new Note(Source.CLINICALTRIALS, noteStr));
            for (final EventCountsStruct counts : event.getCounts()) {
                GroupStruct xmlArm = find(reportedEvents.groupList.group, new Predicate<GroupStruct>() {
                    public boolean evaluate(GroupStruct object) {
                        return object.getGroupId().equalsIgnoreCase(counts.groupId);
                    }
                });
                Arm arm = findArmWithName(d_study, xmlArm.getTitle());
                if (arm == null && !EqualsUtil.equal(xmlArm.getTitle(), "Total")) {
                    continue;
                }
                BasicRateMeasurement m = buildRateMeasurement(counts.subjectsAtRisk, counts.subjectsAffected,
                        false);
                som.getValue().setVariableType(new RateVariableType());
                d_study.setMeasurement(som, arm, wt, m);
            }
        }
    }

    private void importPopulationCharacteristics() {
        BaselineStruct baseline = d_studyImport.getClinicalResults().getBaseline();

        List<MeasureStruct> measureList = baseline.getMeasureList().measure;
        for (MeasureStruct popchar : measureList.subList(1, measureList.size())) {
            StudyOutcomeMeasure<PopulationCharacteristic> som = new StudyOutcomeMeasure<PopulationCharacteristic>(
                    PopulationCharacteristic.class);
            d_study.getPopulationChars().add(som);

            StringBuilder builder = new StringBuilder(popchar.getTitle());
            builder.append(formatIfAny("Description", popchar.getDescription(), "\n"));
            builder.append(formatIfAny("Units", popchar.getUnits(), "\n"));

            som.getNotes().add(new Note(Source.CLINICALTRIALS, builder.toString()));
            // Baseline measurements: at start of treatment
            WhenTaken wt = new WhenTaken(EntityUtil.createDuration("P0D"), RelativeTo.FROM_EPOCH_START,
                    d_mainEpoch);
            wt.commit();
            som.getWhenTaken().add(wt);
            importMeasurements(som, wt, Arrays.asList(measureList.get(0), popchar), baseline.getGroupList().group);
        }
    }

    private static ObjectWithNotes<Object> objectWithNote(Object val, String note) {
        ObjectWithNotes<Object> obj = new ObjectWithNotes<Object>(val);
        obj.getNotes().add(new Note(Source.CLINICALTRIALS, note != null ? note : "N/A"));
        return obj;
    }

    /**
     * Remove indentation and text wrapping from a text field.
     * All leading and trailing whitespace is removed from each line of input.
     * Single newlines are removed, double newlines are retained.
     */
    private static String deindent(String textblock) {
        BufferedReader bufferedReader = new BufferedReader(new StringReader(textblock.trim()));
        StringBuilder builder = new StringBuilder();
        try {
            boolean first = true;
            for (String line = bufferedReader.readLine(); line != null; line = bufferedReader.readLine()) {
                line = line.trim();
                if (!line.isEmpty()) {
                    builder.append((first ? "" : " ") + line);
                    first = false;
                } else {
                    builder.append("\n\n");
                    first = true;
                }
            }
            bufferedReader.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return builder.toString();
    }

    private static void addFrequencyMeasurement(Study study, StudyOutcomeMeasure<? extends Variable> som,
            WhenTaken wt, GroupStruct xmlArm, MeasureStruct measurement) {
        final Arm arm = findArmWithName(study, xmlArm.getTitle());
        if (arm == null && !EqualsUtil.equal(xmlArm.getTitle(), "Total")) {
            return;
        }
        /*
        List<MeasureCategoryStruct> categories = measurement.getCategoryList().getCategory();
        List<String> categoryNames = new LinkedList<String>();
        Map<String, Integer> frequencies = new HashMap<String, Integer>();
        for (int i = 0; i < categories.size(); i++) {
           MeasureCategoryStruct category = categories.get(i);
           String name = category.subTitle;
           categoryNames.add(name);
           int frequency = Integer.parseInt(getMeasurementForArm(xmlArm.groupId, i, measurement).getValueAttribute());
           frequencies.put(name, frequency);
        }
        som.getValue().setVariableType(new CategoricalVariableType(categoryNames));
        study.setMeasurement(som, arm, wt, new FrequencyMeasurement(categoryNames, frequencies));
        */
    }

    private static void addBasicRateMeasurement(final Study study,
            final StudyOutcomeMeasure<? extends Variable> som, final WhenTaken wt, GroupStruct xmlArm,
            List<MeasureStruct> measurements) {
        final Arm arm = findArmWithName(study, xmlArm.getTitle());
        if (arm == null && !EqualsUtil.equal(xmlArm.getTitle(), "Total")) {
            return;
        }
        final String xmlArmId = xmlArm.groupId;
        BasicMeasurement meas = createBasicRateMeasurement(getMeasurementForArm(xmlArmId, 0, measurements.get(0)), // Total number of participants
                getMeasurementForArm(xmlArmId, 0, measurements.get(1)), // Number of responders
                measurements.get(1));
        som.getValue().setVariableType(new RateVariableType());
        study.setMeasurement(som, arm, wt, meas);
    }

    private static void addContinuousMeasurement(final Study study,
            final StudyOutcomeMeasure<? extends Variable> som, final WhenTaken wt, GroupStruct xmlArm,
            List<MeasureStruct> measurements) {
        final Arm arm = findArmWithName(study, xmlArm.getTitle());
        if (arm == null && !EqualsUtil.equal(xmlArm.getTitle(), "Total")) {
            return;
        }

        final String xmlArmId = xmlArm.groupId;
        MeasureStruct measure = measurements.get(1);

        if (!(measure.param.equalsIgnoreCase("Mean") || measure.param.equalsIgnoreCase("Least Squares Mean"))) {
            System.err
                    .println(("Cannot import mean, not of type Mean or Least Squares Mean, but " + measure.param));
            return;
        }
        BasicMeasurement meas = createBasicContinuousMeasurement(
                getMeasurementForArm(xmlArmId, 0, measurements.get(0)), // Total number of participants
                getMeasurementForArm(xmlArmId, 0, measurements.get(1)), // Mean and std.dev
                measure);
        som.getValue().setVariableType(new ContinuousVariableType());
        study.setMeasurement(som, arm, wt, meas);
    }

    private static BasicMeasurement createBasicContinuousMeasurement(MeasurementStruct totalStruct,
            MeasurementStruct measurementStruct, MeasureStruct measure) {
        int total = Integer.parseInt(totalStruct.valueAttribute);

        Double mean = convertToDouble(measurementStruct.valueAttribute);
        Double stdDev = convertToDouble(measurementStruct.spread);

        if (measure.dispersion.equals("Standard Error") && stdDev != null) {
            stdDev = stdDev * Math.sqrt(total);
        } else if (!measure.dispersion.equals("Standard Deviation")) {
            System.err.println("Cannot convert dispersion in " + measure.title + " of type" + measure.dispersion);
            return null;
        }
        return new BasicContinuousMeasurement(mean, stdDev, total);
    }

    private static BasicMeasurement createBasicRateMeasurement(MeasurementStruct totalStruct,
            MeasurementStruct rateStruct, MeasureStruct rateMeasure) {
        return buildRateMeasurement(totalStruct.valueAttribute, rateStruct.valueAttribute,
                StringUtils.containsIgnoreCase(rateMeasure.units, "Percentage"));
    }

    private static BasicRateMeasurement buildRateMeasurement(String total, String rate, boolean isPercentage) {
        Double totalValue = total == null ? null : convertToDouble(total);
        Double rateValue = rate == null ? null : convertToDouble(rate);
        if (totalValue == null && rateValue != null) {
            return new BasicRateMeasurement((int) Math.round(rateValue), null);
        } else if (totalValue != null && rateValue == null) {
            return new BasicRateMeasurement(null, (int) Math.round(totalValue));
        } else if (rateValue != null && totalValue != null) {
            return new BasicRateMeasurement(
                    (int) Math.round((isPercentage ? ((rateValue / 100) * totalValue) : rateValue)),
                    (int) Math.round(totalValue));
        }
        return new BasicRateMeasurement();
    }

    private static Double convertToDouble(String text) {
        return (text != null && !text.toLowerCase().contains("na")) ? Double.parseDouble(text) : null;
    }

    private static Integer convertToInteger(String text) {
        return (text != null && !text.toLowerCase().contains("na")) ? Integer.parseInt(text) : null;
    }

    private static MeasurementStruct getMeasurementForArm(final String xmlArmId, int categoryIdx,
            MeasureStruct measure) {
        List<MeasurementStruct> measureMeasurements = measure.getCategoryList().getCategory()
                .get(categoryIdx).measurementList.measurement;
        return findMeasurement(xmlArmId, measureMeasurements);
    }

    private static MeasurementStruct findMeasurement(final String xmlArmId, List<MeasurementStruct> measurements) {
        return find(measurements, new Predicate<MeasurementStruct>() {
            public boolean evaluate(MeasurementStruct object) {
                return object.getGroupId().equalsIgnoreCase(xmlArmId);
            }
        });
    }

    private static Arm findArmWithName(final Study study, final String armName) {
        return find(study.getArms(), new Predicate<Arm>() {
            public boolean evaluate(Arm object) {
                return object.getName().equalsIgnoreCase(armName);
            }
        });
    }

    private static String formatIfAny(String fieldName, String value, String separator) {
        if (value != null && !value.equals("")) {
            return separator + fieldName + ": " + value;
        }
        return "";
    }

    private static String addIfAny(String noteStr, String fieldName, String value) {
        return noteStr + formatIfAny(fieldName, value, "\n\n");
    }

    private static void uniqueify(List<String> names) {
        for (int i = 0; i < names.size() - 1; ++i) {
            List<String> sublist = names.subList(i + 1, names.size());
            String name = names.get(i);
            if (sublist.contains(name)) {
                names.set(i, name + " " + i);
                for (int idx = sublist.indexOf(name); idx > -1; idx = sublist.indexOf(name)) {
                    sublist.set(idx, name + " " + (i + 1 + idx));
                }
            }
        }
    }

    private static String guessExclusion(String criteria) {
        int exclusionStart = criteria.toLowerCase().indexOf(EXCLUSION_CRITERIA) + EXCLUSION_CRITERIA.length() + 1;
        String exclusion = null;
        if (criteria.toLowerCase().indexOf(EXCLUSION_CRITERIA) != -1)
            exclusion = criteria.substring(exclusionStart).trim();
        return exclusion;
    }

    private static String guessInclusionCriteria(String criteria) {
        int inclusionStart = criteria.toLowerCase().indexOf(INCLUSION_CRITERIA) + INCLUSION_CRITERIA.length() + 1;
        int inclusionEnd = criteria.toLowerCase().indexOf(EXCLUSION_CRITERIA);

        if (inclusionEnd == -1)
            inclusionEnd = criteria.length() - 1;

        String inclusion = null;
        if (criteria.toLowerCase().indexOf(INCLUSION_CRITERIA) != -1)
            inclusion = criteria.substring(inclusionStart, inclusionEnd).trim();
        return inclusion;
    }

    private static BasicStudyCharacteristic.Status guessStatus(ClinicalStudy studyImport) {
        BasicStudyCharacteristic.Status status = BasicStudyCharacteristic.Status.UNKNOWN;
        if (studyImport.getOverallStatus().toLowerCase().contains("recruiting"))
            status = BasicStudyCharacteristic.Status.RECRUITING;
        else if (studyImport.getOverallStatus().contains("Enrolling"))
            status = BasicStudyCharacteristic.Status.RECRUITING;
        else if (studyImport.getOverallStatus().contains("Active"))
            status = BasicStudyCharacteristic.Status.ACTIVE;
        else if (studyImport.getOverallStatus().contains("Completed"))
            status = BasicStudyCharacteristic.Status.COMPLETED;
        else if (studyImport.getOverallStatus().contains("Available"))
            status = BasicStudyCharacteristic.Status.COMPLETED;
        return status;
    }

    private static Date guessDate(DateStruct startDate2) {
        Date startDate = null;
        SimpleDateFormat sdf = new SimpleDateFormat("MMM yyyy");
        try {
            if (startDate2 != null)
                startDate = sdf.parse(startDate2.getContent());
        } catch (ParseException e) {
            System.err.println("ClinicalTrialsImporter:: Couldn't parse date. Left empty.");
        }
        return startDate;
    }

    private static String createIndicationNote(ClinicalStudy studyImport) {
        String out = "";
        for (String s : studyImport.getCondition()) {
            out = out + s + "\n";
        }
        out = out.trim();
        return out;
    }

    private static BasicStudyCharacteristic.Blinding guessBlinding(ClinicalStudy studyImport) {
        BasicStudyCharacteristic.Blinding blinding = Blinding.UNKNOWN;
        if (designContains(studyImport, "open label"))
            blinding = BasicStudyCharacteristic.Blinding.OPEN;
        else if (designContains(studyImport, "single blind"))
            blinding = BasicStudyCharacteristic.Blinding.SINGLE_BLIND;
        else if (designContains(studyImport, "double blind"))
            blinding = BasicStudyCharacteristic.Blinding.DOUBLE_BLIND;
        else if (designContains(studyImport, "triple blind"))
            blinding = BasicStudyCharacteristic.Blinding.TRIPLE_BLIND;
        return blinding;
    }

    private static BasicStudyCharacteristic.Allocation guessAllocation(ClinicalStudy studyImport) {
        Allocation allocation = Allocation.UNKNOWN;
        if (designContains(studyImport, "non-randomized"))
            allocation = Allocation.NONRANDOMIZED;
        else if (designContains(studyImport, "randomized"))
            allocation = Allocation.RANDOMIZED;
        return allocation;
    }

    private static String createCentersNote(ClinicalStudy studyImport) {
        StringBuilder noteBuilder = new StringBuilder();
        for (LocationStruct l : studyImport.getLocation()) {
            FacilityStruct f = l.getFacility();
            AddressStruct a = f.getAddress();
            List<String> fields = new ArrayList<String>(Arrays
                    .asList(new String[] { f.getName(), a.getZip(), a.getCity(), a.getState(), a.getCountry() }));
            CollectionUtils.filter(fields, PredicateUtils.notNullPredicate());
            noteBuilder.append(StringUtils.join(fields, ", "));
            noteBuilder.append('\n');
        }
        return noteBuilder.toString();
    }

    private static String createTitleNote(ClinicalStudy studyImport) {
        StringBuilder titleNote = new StringBuilder();
        titleNote.append("Brief title: ");
        if (studyImport.getBriefTitle() != null) {
            titleNote.append(studyImport.getBriefTitle().trim());
        } else {
            titleNote.append("N/A");
        }
        titleNote.append("\n\n");
        titleNote.append("Official title: ");
        if (studyImport.getOfficialTitle() != null) {
            titleNote.append(studyImport.getOfficialTitle().trim());
        } else {
            titleNote.append("N/A");
        }
        return titleNote.toString();
    }

    private static boolean designContains(ClinicalStudy studyImport, String contains) {
        return studyImport.getStudyDesign().toLowerCase().contains(contains)
                || studyImport.getStudyDesign().toLowerCase().contains(contains.replace(' ', '-'));
    }
}