gov.nih.nci.cabig.caaers.domain.report.Report.java Source code

Java tutorial

Introduction

Here is the source code for gov.nih.nci.cabig.caaers.domain.report.Report.java

Source

/*******************************************************************************
 * Copyright SemanticBits, Northwestern University and Akaza Research
 * 
 * Distributed under the OSI-approved BSD 3-Clause License.
 * See http://ncip.github.com/caaers/LICENSE.txt for details.
 ******************************************************************************/
package gov.nih.nci.cabig.caaers.domain.report;

import gov.nih.nci.cabig.caaers.domain.AdverseEvent;
import gov.nih.nci.cabig.caaers.domain.ExpeditedAdverseEventReport;
import gov.nih.nci.cabig.caaers.domain.Physician;
import gov.nih.nci.cabig.caaers.domain.ReportStatus;
import gov.nih.nci.cabig.caaers.domain.Reporter;
import gov.nih.nci.cabig.caaers.domain.ReviewStatus;
import gov.nih.nci.cabig.caaers.domain.Submitter;
import gov.nih.nci.cabig.caaers.domain.workflow.ReportReviewComment;
import gov.nih.nci.cabig.caaers.domain.workflow.WorkflowAware;
import gov.nih.nci.cabig.caaers.tools.configuration.Configuration;
import gov.nih.nci.cabig.caaers.utils.DateUtils;
import gov.nih.nci.cabig.ctms.domain.AbstractMutableDomainObject;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.IndexColumn;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.Type;

/**
 * A report sending schedule for an adverse event. The RuleExecutionService, evaluates pre-defined
 * set of rules over the attributes of an AdverseEvent, and creates a Report.
 * 
 * @author Biju Joseph
 * 
 */
@Entity
@Table(name = "REPORT_SCHEDULES")
@GenericGenerator(name = "id-generator", strategy = "native", parameters = {
        @Parameter(name = "sequence", value = "seq_report_schedules_id") })
public class Report extends AbstractMutableDomainObject implements WorkflowAware, Serializable {

    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = 4001323963140432224L;

    /** The required. */
    private boolean required;

    /** The ae report. */
    private ExpeditedAdverseEventReport aeReport;

    /** The report definition. */
    private ReportDefinition reportDefinition;

    /** The notifications. */
    private List<ScheduledNotification> notifications;

    /** The report versions. */
    private List<ReportVersion> reportVersions;

    /** The deliveries. */
    private List<ReportDelivery> deliveries;

    /** The manually selected. */
    private boolean manuallySelected;

    /** The external system. */
    private boolean externalSystem;

    /** The adeers report type indicator. */
    private String adeersReportTypeIndicator;

    /** The email addresses. */
    private List<String> emailAddresses;

    /** The review status. */
    private ReviewStatus reviewStatus;

    /** The workflow id. */
    private Integer workflowId;

    /** The review comments. */
    private List<ReportReviewComment> reviewComments;

    /** The mandatory fields. */
    private List<ReportMandatoryField> mandatoryFields;

    /** The _ regula r_ report. */
    private String _REGULAR_REPORT = "Regular report";

    /** The _24 h r_ notification. */
    private String _24HR_NOTIFICATION = "24-hr notification";

    /** The _24 h r_ notificatio n_ complete. */
    private String _24HR_NOTIFICATION_COMPLETE = "24-hr notification complete";

    /** The _24 h r_ amendment. */
    private String _24HR_AMENDMENT = "24-hr amendment";

    /** The _24 h r_ amendmen t_ complete. */
    private String _24HR_AMENDMENT_COMPLETE = "24-hr amendment complete";

    /** The _ regula r_ amendment. */
    private String _REGULAR_AMENDMENT = "Regular amendment";

    // dummy field to be used in serialized XML to check the status of the delivery for FDA
    /** The submitted to fda. */
    private String submittedToFDA = "No";

    private String caseNumber;

    private String metaData;

    /**
      * Instantiates a new report.
      */
    public Report() {
        //for hibernate
    }

    // //// LOGIC

    public String getCaseNumber() {
        return caseNumber;
    }

    public void setCaseNumber(String caseNumber) {
        this.caseNumber = caseNumber;
    }

    /**
      * Adds the report version.
      *
      * @param reportVersion the report version
      */
    public void addReportVersion(ReportVersion reportVersion) {
        if (reportVersions == null)
            reportVersions = new ArrayList<ReportVersion>();
        reportVersion.setReport(this);
        reportVersions.add(reportVersion);
    }

    /**
     * Adds the scheduled notification.
     *
     * @param nf the nf
     */
    public void addScheduledNotification(ScheduledNotification nf) {
        if (notifications == null)
            notifications = new ArrayList<ScheduledNotification>();
        notifications.add(nf);
    }

    /**
     * Adds the report delivery.
     *
     * @param rd the rd
     */
    public void addReportDelivery(ReportDelivery rd) {
        if (this.deliveries == null)
            deliveries = new ArrayList<ReportDelivery>();
        deliveries.add(rd);
        rd.setReport(this);
    }

    /**
     * Checks for scheduled notifications.
     *
     * @return true, if successful
     */
    public boolean hasScheduledNotifications() {
        return (notifications != null) && (!notifications.isEmpty());
    }

    /**
     * This method will loop through the delivery defs,to see if there is an endpoint of type url.
     *
     * @return true, if successful
     */
    public boolean hasSystemDeliveries() {
        if (deliveries == null)
            return false;

        for (ReportDelivery rDelivery : deliveries) {
            if (rDelivery.isSystemType())
                return true;
        }

        return false;
    }

    /**
     * Returns the notification having the supplied Id.
     *
     * @param nfId the nf id
     * @return the scheduled notification
     */
    public ScheduledNotification fetchScheduledNotification(Integer nfId) {
        if (notifications == null)
            return null;
        for (ScheduledNotification nf : notifications) {
            if (nf.getId().equals(nfId))
                return nf;
        }
        return null;
    }

    /**
     * Gets the last version.
     *
     * @return the last version
     */
    @Transient
    public ReportVersion getLastVersion() {
        if (reportVersions == null || reportVersions.isEmpty()) {
            ReportVersion defaultVersion = new ReportVersion();
            addReportVersion(defaultVersion);
        }
        return reportVersions.get(reportVersions.size() - 1);
    }

    // //// BEAN PROPERTIES
    /**
     * Gets the created on.
     *
     * @return the created on
     */
    @Transient
    public Date getCreatedOn() {
        return getLastVersion().getCreatedOn();
    }

    /**
     * Sets the created on.
     *
     * @param createdOn the new created on
     */
    public void setCreatedOn(Date createdOn) {
        getLastVersion().setCreatedOn(createdOn);
    }

    /**
     * Gets the due on.
     *
     * @return the due on
     */
    @Transient
    public Date getDueOn() {
        return getLastVersion().getDueOn();
    }

    /**
     * Sets the due on.
     *
     * @param dueOn the new due on
     */
    public void setDueOn(Date dueOn) {
        this.getLastVersion().setDueOn(dueOn);
    }

    /**
     * Gets the submitted on.
     *
     * @return the submitted on
     */
    @Transient
    public Date getSubmittedOn() {
        return getLastVersion().getSubmittedOn();
    }

    /**
     * Sets the submitted on.
     *
     * @param submittedOn the new submitted on
     */
    public void setSubmittedOn(Date submittedOn) {
        getLastVersion().setSubmittedOn(submittedOn);
    }

    /**
     * Gets the withdrawn on.
     *
     * @return the withdrawn on
     */
    @Transient
    public Date getWithdrawnOn() {
        return getLastVersion().getWithdrawnOn();
    }

    /**
     * Sets the withdrawn on.
     *
     * @param withdrawnOn the new withdrawn on
     */
    public void setWithdrawnOn(Date withdrawnOn) {
        getLastVersion().setWithdrawnOn(withdrawnOn);
    }

    /**
     * Gets the status.
     *
     * @return the status
     */
    @Transient
    public ReportStatus getStatus() {
        return getLastVersion().getReportStatus();
    }

    /**
     * Sets the status.
     *
     * @param status the new status
     */
    public void setStatus(ReportStatus status) {
        this.getLastVersion().setReportStatus(status);
    }

    /**
     * Gets the assigned identifer.
     *
     * @return the assigned identifer
     */
    @Transient
    public String getAssignedIdentifer() {
        return getLastVersion().getAssignedIdentifer();
    }

    /**
     * Sets the assigned identifer.
     *
     * @param assignedIdentifer the new assigned identifer
     */
    public void setAssignedIdentifer(String assignedIdentifer) {
        this.getLastVersion().setAssignedIdentifer(assignedIdentifer);
    }

    /**
     * Gets the submission message.
     *
     * @return the submission message
     */
    @Transient
    public String getSubmissionMessage() {
        return getLastVersion().getSubmissionMessage();
    }

    /**
     * Sets the submission message.
     *
     * @param submissionMessage the new submission message
     */
    public void setSubmissionMessage(String submissionMessage) {
        getLastVersion().setSubmissionMessage(submissionMessage);
    }

    /**
     * Gets the submission url.
     *
     * @return the submission url
     */
    @Transient
    public String getSubmissionUrl() {
        return getLastVersion().getSubmissionMessage();
    }

    /**
     * Sets the submission url.
     *
     * @param submissionUrl the new submission url
     */
    public void setSubmissionUrl(String submissionUrl) {
        this.getLastVersion().setSubmissionUrl(submissionUrl);
    }

    /**
     * Gets the amended on.
     *
     * @return the amended on
     */
    @Transient
    public Date getAmendedOn() {
        return this.getLastVersion().getAmendedOn();
    }

    /**
     * Sets the amended on.
     *
     * @param amendedOn the new amended on
     */
    public void setAmendedOn(Date amendedOn) {
        this.getLastVersion().setAmendedOn(amendedOn);
    }

    /**
     * Gets the report definition.
     *
     * @return the report definition
     */
    @OneToOne
    @JoinColumn(name = "rct_id")
    @Cascade({ CascadeType.LOCK })
    public ReportDefinition getReportDefinition() {
        return reportDefinition;
    }

    /**
     * Sets the report definition.
     *
     * @param reportDefinition the new report definition
     */
    public void setReportDefinition(ReportDefinition reportDefinition) {
        this.reportDefinition = reportDefinition;
    }

    /**
     * Gets the scheduled notifications.
     *
     * @return the scheduled notifications
     */
    @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true)
    @JoinColumn(name = "rpsh_id", nullable = false)
    @Cascade(value = { CascadeType.ALL })
    @Fetch(value = org.hibernate.annotations.FetchMode.SUBSELECT)
    public List<ScheduledNotification> getScheduledNotifications() {
        return notifications;
    }

    /**
     * Sets the scheduled notifications.
     *
     * @param notifications the new scheduled notifications
     */
    public void setScheduledNotifications(List<ScheduledNotification> notifications) {
        this.notifications = notifications;
    }

    /**
     * Gets the ae report.
     *
     * @return the ae report
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "report_id")
    public ExpeditedAdverseEventReport getAeReport() {
        return aeReport;
    }

    /**
     * Sets the ae report.
     *
     * @param aeReport the new ae report
     */
    public void setAeReport(ExpeditedAdverseEventReport aeReport) {
        this.aeReport = aeReport;
    }

    /**
     * Gets the name.
     *
     * @return the name
     */
    @Transient
    public String getName() {
        return reportDefinition.getName();
    }

    /**
     * Gets the label.
     *
     * @return the label
     */
    @Transient
    public String getLabel() {
        return reportDefinition.getLabel();
    }

    /**
     * Checks if is required.
     *
     * @return true, if is required
     */
    public boolean isRequired() {
        return required;
    }

    /**
     * Sets the required.
     *
     * @param required the new required
     */
    public void setRequired(boolean required) {
        this.required = required;
    }

    /**
     * Gets the report deliveries.
     *
     * @return the report deliveries
     */
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "report", orphanRemoval = true)
    @Cascade(value = { CascadeType.ALL })
    @Fetch(value = org.hibernate.annotations.FetchMode.SUBSELECT)
    public List<ReportDelivery> getReportDeliveries() {
        return deliveries;
    }

    /**
     * Sets the report deliveries.
     *
     * @param deliveries the new report deliveries
     */
    public void setReportDeliveries(List<ReportDelivery> deliveries) {
        this.deliveries = deliveries;
    }

    /**
     * Gets the physician signoff.
     *
     * @return the physician signoff
     */
    @Transient
    public Boolean getPhysicianSignoff() {
        return getLastVersion().getPhysicianSignoff();
    }

    /**
     * Sets the physician signoff.
     *
     * @param physicianSignoff the new physician signoff
     */
    public void setPhysicianSignoff(Boolean physicianSignoff) {
        getLastVersion().setPhysicianSignoff(physicianSignoff);
    }

    /**
     * Find email address by role.
     *
     * @param roleName the role name
     * @return the list
     */
    public List<String> findEmailAddressByRole(String roleName) {
        final List<String> emails = new ArrayList<String>();
        if (StringUtils.equals(roleName, "REP")) {
            if (getReporter() != null) {
                String email = getReporter().getEmailAddress();
                if (StringUtils.isNotEmpty(email))
                    emails.add(email);

                final String altMail = getReporter().getAlternateEmailAddress();
                if (altMail != null) {
                    for (String alt : altMail.split("[,;]")) {
                        emails.add(alt.trim());
                    }
                }
            }
        } else if (StringUtils.equals(roleName, "SUB")) {
            if (getSubmitter() != null) {
                String email = getSubmitter().getEmailAddress();
                if (StringUtils.isNotEmpty(email))
                    emails.add(email);
            }
        } else if (StringUtils.equals(roleName, "PHY")) {
            if (getPhysician() != null) {
                String email = getPhysician().getEmailAddress();
                if (StringUtils.isNotEmpty(email))
                    emails.add(email);
            }
        }

        return emails;
    }

    /**
     * This method will return the list of email recipients associated with this report.
     * - Email recipients from deliveries
     * - CC Emails from ReportVersion (Last version)
     *
     * @return the email recipients
     */
    @Transient
    public List<String> getEmailRecipients() {
        List<String> emailAddressesTemp = new ArrayList<String>();
        if (deliveries != null) {
            for (ReportDelivery rd : deliveries) {
                if (rd.isEmailType()) {
                    emailAddressesTemp.add(rd.getEndPoint().trim());
                }
            }
        }
        //now include the CC emails.
        ReportVersion lastVersion = getLastVersion();
        if (lastVersion != null) {
            lastVersion.getCcEmails();
            String[] ccEmails = lastVersion.getEmailAsArray();
            if (ccEmails != null) {
                for (String ccEmail : ccEmails) {
                    String email = ccEmail.trim();
                    if (StringUtils.isNotEmpty(email))
                        emailAddressesTemp.add(email);
                }
            }
        }

        return emailAddressesTemp;
    }

    /**
     * Gets the email addresses.
     *
     * @return the email addresses
     */
    @Transient
    public List<String> getEmailAddresses() {
        return emailAddresses;
    }

    /**
     * Sets the email addresses.
     *
     * @param emailAddresses the new email addresses
     */
    public void setEmailAddresses(List<String> emailAddresses) {
        this.emailAddresses = emailAddresses;
    }

    /**
     * Gets the external system deliveries.
     *
     * @return the external system deliveries
     */
    @Transient
    public List<ReportDelivery> getExternalSystemDeliveries() {
        List<ReportDelivery> externalDeliveries = new ArrayList<ReportDelivery>();
        if (deliveries != null) {
            for (ReportDelivery rd : deliveries) {
                if (rd.isSystemType())
                    externalDeliveries.add(rd);
            }
        }
        return externalDeliveries;
    }

    /**
     * Gets the report versions.
     *
     * @return the report versions
     */
    @OneToMany(orphanRemoval = true)
    @JoinColumn(name = "report_id", nullable = false)
    @IndexColumn(name = "list_index")
    @Cascade(value = { CascadeType.ALL })
    @Fetch(value = org.hibernate.annotations.FetchMode.SUBSELECT)
    public List<ReportVersion> getReportVersions() {
        return reportVersions;
    }

    /**
     * Sets the report versions.
     *
     * @param reportVersions the new report versions
     */
    public void setReportVersions(List<ReportVersion> reportVersions) {
        this.reportVersions = reportVersions;
    }

    /**
     * Checks if is manually selected.
     *
     * @return true, if is manually selected
     */
    public boolean isManuallySelected() {
        return manuallySelected;
    }

    /**
     * Sets the manually selected.
     *
     * @param manuallySelected the new manually selected
     */
    public void setManuallySelected(boolean manuallySelected) {
        this.manuallySelected = manuallySelected;
    }

    public String getMetaData() {
        return metaData;
    }

    public void setMetaData(String metaData) {
        this.metaData = metaData;
    }

    @Transient
    public String[] getCorrelationIds() {
        return StringUtils.splitByWholeSeparator(getMetaDataAsMap().get("correlationId"), ",");
    }

    public void addToCorrelationId(String correlationId) {
        String[] existing = getCorrelationIds();
        if (ArrayUtils.isEmpty(existing)) {
            addToMetaData("correlationId", correlationId);
            addToMetaData(correlationId, DateUtils.formatDate(new Date(), DateUtils.DATE_WITH_HYPHENS));
        } else if (!ArrayUtils.contains(existing, correlationId)) {
            addToMetaData("correlationId", StringUtils.join(existing, ',') + "," + correlationId);
            addToMetaData(correlationId, DateUtils.formatDate(new Date(), DateUtils.DATE_WITH_HYPHENS));
        }
    }

    @Transient
    public LinkedHashMap<String, String> getMetaDataAsMap() {
        LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
        String[] kvs = StringUtils.splitByWholeSeparator(getMetaData(), "|$");
        if (kvs != null) {
            for (String kv : kvs) {
                int i = kv.indexOf(":~");
                map.put(kv.substring(0, i), kv.substring(i + 2));
            }
        }
        return map;
    }

    public void addToMetaData(String k, String v) {
        if (StringUtils.isEmpty(k) || StringUtils.isEmpty(v))
            return;
        LinkedHashMap<String, String> map = getMetaDataAsMap();
        StringBuilder sb = new StringBuilder();
        map.put(k, v);
        for (Map.Entry<String, String> e : map.entrySet()) {
            if (sb.length() > 0)
                sb.append("|$");
            sb.append(e.getKey()).append(":~").append(e.getValue());
        }

        setMetaData(sb.toString());

    }

    public void removeFromMetaData(String k) {
        LinkedHashMap<String, String> map = getMetaDataAsMap();
        StringBuilder sb = new StringBuilder();
        map.remove(k);
        for (Map.Entry<String, String> e : map.entrySet()) {
            if (sb.length() > 0)
                sb.append("|~");
            sb.append(e.getKey()).append(":~").append(e.getValue());
        }

        setMetaData(sb.toString());

    }

    // //// OBJECT METHODS

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Report [").append("id : ").append(getId()).append(", name :").append(getName())
                .append(", case :").append(getCaseNumber()).append(", createdOn :")
                .append(String.valueOf(getCreatedOn())).append(", submittedOn :")
                .append(String.valueOf(getSubmittedOn())).append(", dueOn :").append(String.valueOf(getDueOn()));
        sb.append("\r\n notifications :");
        if (notifications != null) {
            for (ScheduledNotification sn : notifications) {
                sb.append("\r\n").append(String.valueOf(sn));
            }
        }
        if (deliveries != null) {
            for (ReportDelivery delivery : deliveries) {
                sb.append("\r\n").append(String.valueOf(delivery));
            }
        }
        sb.append("]");
        return sb.toString();
    }

    /**
     * Gets the context variables.
     *
     * @return the context variables
     */
    @Transient
    public Map<Object, Object> getContextVariables() {
        //TODO : properly populate the following....
        //TODO: add appropriate null-checks
        Map<Object, Object> map = new HashMap<Object, Object>();

        String primaryIdentifier = getAeReport().getAssignment().getParticipant().getPrimaryIdentifierValue();
        map.put("patientId", primaryIdentifier == null ? "xxxx" : primaryIdentifier);//Patient ID
        map.put("reportId", getAeReport().getId());//Report ID
        map.put("reportURL", "/pages/ae/edit?aeReport=" + getAeReport().getId() + "&report=" + getId());//URL To Report
        map.put("report", this);
        map.put("study", getAeReport().getStudy());
        map.put("studyId", getAeReport().getStudy().getPrimaryIdentifierValue());

        //below makes no sense, but this will prevent freemarker errors (see
        map.put("adverseEventID", " ");//external ID
        map.put("adverseEventTerm", " ");//ae term
        map.put("aeStartDate", " ");//start date

        map.put("systemName", Configuration.LAST_LOADED_CONFIGURATION.get(Configuration.SYSTEM_NAME));

        return map;
    }

    /*
    *
    * This will return only the fields marked as mandatory 
    */
    /**
     * Gets the path of non self referenced mandatory fields.
     *
     * @return the path of non self referenced mandatory fields
     */
    @Transient
    public List<String> getPathOfNonSelfReferencedMandatoryFields() {
        List<String> fields = new LinkedList<String>();
        for (ReportMandatoryField mandatoryField : getFieldsByApplicability(Mandatory.MANDATORY)) {
            if (!mandatoryField.isSelfReferenced())
                fields.add(mandatoryField.getFieldPath());
        }
        return fields;
    }

    /*
    *
    * This will return only the fields marked as mandatory
    */
    /**
     * Gets the path of self referenced mandatory fields.
     *
     * @return the path of self referenced mandatory fields
     */
    @Transient
    public List<String> getPathOfSelfReferencedMandatoryFields() {
        List<String> fields = new LinkedList<String>();
        for (ReportMandatoryField mandatoryField : getFieldsByApplicability(Mandatory.MANDATORY)) {
            if (mandatoryField.isSelfReferenced())
                fields.add(mandatoryField.getFieldPath());
        }
        return fields;
    }

    /**
     * Will list all the fields that are applicable (ie. Mandatory and Optional)
     *
     * @return the path of applicable fields
     */
    @Transient
    public List<String> getPathOfApplicableFields() {
        Set<String> fields = new LinkedHashSet<String>();
        for (ReportMandatoryField mandatoryField : getFieldsByApplicability(Mandatory.MANDATORY,
                Mandatory.OPTIONAL)) {
            fields.add(mandatoryField.getFieldPath().replaceAll("(\\[\\d+\\])", ""));
        }
        return new ArrayList<String>(fields);
    }

    /**
     * Will return the path of fields which are Not Applicable.
     *
     * @return the path of not applicable fields
     */
    @Transient
    public List<String> getPathOfNotApplicableFields() {
        List<String> fields = new LinkedList<String>();
        for (ReportMandatoryField mandatoryField : getFieldsByApplicability(Mandatory.NA)) {
            fields.add(mandatoryField.getFieldPath());
        }
        return fields;
    }

    /*
    * Will find the list of mandatory fields, having the same Mandatory flag, mentioned
    * in mandatory types. 
    */
    /**
     * Gets the fields by applicability.
     *
     * @param mandatoryTypes the mandatory types
     * @return the fields by applicability
     */
    @Transient
    public List<ReportMandatoryField> getFieldsByApplicability(final Mandatory... mandatoryTypes) {
        ArrayList<ReportMandatoryField> reportMandatoryFields = new ArrayList<ReportMandatoryField>();
        for (ReportMandatoryField mf : getMandatoryFields()) {
            if (ArrayUtils.contains(mandatoryTypes, mf.getMandatory())) {
                reportMandatoryFields.add(mf);
            }
        }
        return reportMandatoryFields;
    }

    /**
     * Checks if is sponsor report.
     *
     * @param nciInstituteCode the nci institute code
     * @return the boolean
     */
    @Transient
    public Boolean isSponsorReport(String nciInstituteCode) {
        if (reportDefinition.getOrganization().getNciInstituteCode().equals(nciInstituteCode))
            return true;
        return false;
    }

    /**
     * This method returns true if the last reportVersion is in Submitted state.
     *
     * @return the boolean
     */
    @Transient
    public Boolean isSubmitted() {
        if (this.getLastVersion() != null && this.getLastVersion().getReportStatus() == ReportStatus.COMPLETED)
            return true;
        return false;
    }

    /**
     * This method returns true if the last reportVersion is in Amended state.
     *
     * @return the boolean
     */
    @Transient
    public Boolean isAmended() {
        if (this.getLastVersion() != null && this.getLastVersion().getReportStatus() == ReportStatus.AMENDED)
            return true;
        return false;
    }

    /**
     * All the reports, which can be submitted is considered active.
     * The reports in {@link ReportStatus#WITHDRAWN} or {@link ReportStatus#REPLACED} or {@link ReportStatus#COMPLETED} or {@link ReportStatus#AMENDED}are considered inactive.
     *
     * @return true, if is active
     */
    @Transient
    public boolean isActive() {
        return !isHavingStatus(ReportStatus.WITHDRAWN, ReportStatus.REPLACED, ReportStatus.AMENDED,
                ReportStatus.COMPLETED);
    }

    /**
     * Returns the attribution required flag, associated to the {@link ReportDefinition}.
     *
     * @return true, if is attribution required
     */
    @Transient
    public boolean isAttributionRequired() {
        return reportDefinition.getAttributionRequired();
    }

    /**
     * Returns true, if the status of this report is any of the input reportStatus.
     *
     * @param reportStatus the report status
     * @return true, if is having status
     */
    @Transient
    public boolean isHavingStatus(ReportStatus... reportStatus) {
        boolean retVal = false;
        ReportStatus status = getStatus();
        for (ReportStatus rpStatus : reportStatus) {
            retVal = retVal || rpStatus.equals(status);
        }
        return retVal;
    }

    /**
     * True, if the report is overdue,ie. the dueOn is passed.
     *
     * @return true, if is overdue
     */
    @Transient
    public boolean isOverdue() {
        ReportStatus status = getStatus();
        Date dueOn = getDueOn();

        if (status != ReportStatus.PENDING || status != ReportStatus.INPROCESS)
            return false;
        return (dueOn != null && new Date().getTime() > dueOn.getTime());
    }

    /**
     * Will return true the report definition says that it can be amended.
     *
     * @return true, if is amendable
     */
    @Transient
    public boolean isAmendable() {
        return reportDefinition.getAmendable();
    }

    /**
     * Checks if is of same organization and type.
     *
     * @param rd the rd
     * @return true, if is of same organization and type
     */
    @Transient
    public boolean isOfSameOrganizationAndType(ReportDefinition rd) {
        return getReportDefinition().isOfSameReportTypeAndOrganization(rd);
    }

    /**
     * This method will return true, if the adverse event is reported in this report.
     *
     * @param ae the ae
     * @return true, if is reported
     */
    @Transient
    public boolean isReported(AdverseEvent ae) {
        if (BooleanUtils.isTrue(ae.getReported())) {
            List<ReportedAdverseEvent> reportedAdverseEvents = getLastVersion().getReportedAdversEvents();
            if (reportedAdverseEvents != null) {
                for (ReportedAdverseEvent reportedAe : reportedAdverseEvents) {
                    if (ae.getId().equals(reportedAe.getAdverseEvent().getId())) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * Derive adeers report type indicator.
     *
     * @return the string
     */
    public String deriveAdeersReportTypeIndicator() {
        //return this._REGULAR_REPORT;

        ReportType reportType = getReportDefinition().getReportType();
        //Get Reports that are completed and amended.
        List<Report> reportList = getAeReport().listReportsHavingStatus(ReportStatus.AMENDED,
                ReportStatus.COMPLETED);
        //Filter above reports to get reports of same Group(example:AdEERS ) and Organization of the report.
        List<Report> reportListOfSameGroupAndOrg = new ArrayList<Report>();
        //Notification reports Count.
        int ReportsWithTypeNotificationCnt = 0;
        for (Report rep : reportList) {
            if (isOfSameOrganizationAndType(rep.getReportDefinition())) {
                reportListOfSameGroupAndOrg.add(rep);
                if (rep.getReportDefinition().getReportType().equals(ReportType.NOTIFICATION)) {
                    ReportsWithTypeNotificationCnt++;
                }
            }
        }
        //find last submitted report from above list 
        Report lastSubmittedReport = findLastSubmittedReport(reportListOfSameGroupAndOrg);
        // if type is notification 
        if (reportType.equals(ReportType.NOTIFICATION)) {
            if (reportListOfSameGroupAndOrg.size() == 0) {
                return _24HR_NOTIFICATION;
            }
            setAssignedIdentifer(lastSubmittedReport.getAssignedIdentifer());
            return _24HR_AMENDMENT;
        }
        // if type is report 
        if (reportType.equals(ReportType.REPORT)) {
            if (reportListOfSameGroupAndOrg.size() == 0) {
                return _REGULAR_REPORT;
            }
            // if last submitted report is REPORT 
            if (lastSubmittedReport != null
                    && lastSubmittedReport.getReportDefinition().getReportType().equals(ReportType.REPORT)) {
                setAssignedIdentifer(lastSubmittedReport.getAssignedIdentifer());
                return _REGULAR_AMENDMENT;
                // if last submitted report is NOTIFICATION
            } else if (lastSubmittedReport != null
                    && lastSubmittedReport.getReportDefinition().getReportType().equals(ReportType.NOTIFICATION)) {
                String reportVersionIdStr = lastSubmittedReport.getReportVersions().get(0).getReportVersionId();
                int reportVersionId = Integer.parseInt(reportVersionIdStr);
                //  COMPLETE the notofication if the only NOTIFICATION is 24-HR Notification (not AMEND of a Regular Report).
                if (ReportsWithTypeNotificationCnt == 1 && reportVersionId == 0) {
                    setAssignedIdentifer(lastSubmittedReport.getAssignedIdentifer());
                    return _24HR_NOTIFICATION_COMPLETE;
                }
                // amend  the notofication if the only NOTIFICATION  is AMEND of a Regular Report (24-HR amend)
                if (ReportsWithTypeNotificationCnt == 1 && reportVersionId > 0) {
                    setAssignedIdentifer(lastSubmittedReport.getAssignedIdentifer());
                    return _24HR_AMENDMENT_COMPLETE;
                }

                //  AMEND the COMPLETEd report 
                if (ReportsWithTypeNotificationCnt > 1) {
                    setAssignedIdentifer(lastSubmittedReport.getAssignedIdentifer());
                    return _24HR_AMENDMENT_COMPLETE;
                }
            }
        }
        return null;
    }

    /**
     * Reverse the comments so that it will return the reversed list.
     *
     * @return the review comments
     */
    @Transient
    public List<ReportReviewComment> getReviewComments() {
        ArrayList<ReportReviewComment> comments = new ArrayList<ReportReviewComment>(getReviewCommentsInternal());
        Collections.reverse(comments);
        return comments;
    }

    /**
     * Sets the review comments.
     *
     * @param reviewComments the new review comments
     */
    public void setReviewComments(List<ReportReviewComment> reviewComments) {
        setReviewCommentsInternal(reviewComments);
    }

    //http://opensource.atlassian.com/projects/hibernate/browse/HHH-2802
    /**
     * Gets the review comments internal.
     *
     * @return the review comments internal
     */
    @OneToMany(orphanRemoval = true)
    @JoinColumn(name = "report_id", nullable = true)
    @IndexColumn(name = "list_index", nullable = false)
    @Cascade(value = { CascadeType.ALL })
    @Fetch(value = org.hibernate.annotations.FetchMode.SUBSELECT)
    public List<ReportReviewComment> getReviewCommentsInternal() {
        if (reviewComments == null)
            reviewComments = new ArrayList<ReportReviewComment>();
        return reviewComments;
    }

    /**
     * Sets the review comments internal.
     *
     * @param reviewComments the new review comments internal
     */
    public void setReviewCommentsInternal(List<ReportReviewComment> reviewComments) {
        this.reviewComments = reviewComments;
    }

    /**
     * This method will find the recently submitted report.
     *
     * @param reports the reports
     * @return the report
     */
    private Report findLastSubmittedReport(List<Report> reports) {
        Report theReport = null;
        for (Report report : reports) {
            if (theReport == null) {
                theReport = report;
            } else {
                if (DateUtils.compateDateAndTime(theReport.getSubmittedOn(), report.getSubmittedOn()) < 0) {
                    theReport = report;
                }
            }
        }
        return theReport;
    }

    /**
     * Gets the adeers report type indicator.
     *
     * @return the adeers report type indicator
     */
    @Transient
    public String getAdeersReportTypeIndicator() {
        return adeersReportTypeIndicator;
    }

    /**
     * Sets the adeers report type indicator.
     *
     * @param adeersReportTypeIndicator the new adeers report type indicator
     */
    public void setAdeersReportTypeIndicator(String adeersReportTypeIndicator) {
        this.adeersReportTypeIndicator = adeersReportTypeIndicator;
    }

    /**
     * Gets the external system.
     *
     * @return the external system
     */
    @Transient
    public boolean getExternalSystem() {
        externalSystem = hasSystemDeliveries();
        return externalSystem;
    }

    /**
     * Gets the reporter.
     *
     * @return the reporter
     */
    @Transient
    public Reporter getReporter() {
        return aeReport.getReporter();
    }

    /**
     * Gets the submitter.
     *
     * @return the submitter
     */
    @Transient
    public Submitter getSubmitter() {
        return getLastVersion().getSubmitter();
    }

    /**
     * Gets the physician.
     *
     * @return the physician
     */
    @Transient
    public Physician getPhysician() {
        return aeReport.getPhysician();
    }

    /**
     * Sets the submitter.
     *
     * @param submitter the new submitter
     */
    public void setSubmitter(Submitter submitter) {
        getLastVersion().setSubmitter(submitter);
    }

    /* (non-Javadoc)
     * @see gov.nih.nci.cabig.caaers.domain.workflow.WorkflowAware#getWorkflowId()
     */
    public Integer getWorkflowId() {
        return workflowId;
    }

    /* (non-Javadoc)
     * @see gov.nih.nci.cabig.caaers.domain.workflow.WorkflowAware#setWorkflowId(java.lang.Integer)
     */
    public void setWorkflowId(Integer workflowId) {
        this.workflowId = workflowId;
    }

    /* (non-Javadoc)
     * @see gov.nih.nci.cabig.caaers.domain.workflow.WorkflowAware#getReviewStatus()
     */
    @Column(name = "review_status_code")
    @Type(type = "reviewStatus")
    public ReviewStatus getReviewStatus() {
        return reviewStatus;
    }

    /* (non-Javadoc)
     * @see gov.nih.nci.cabig.caaers.domain.workflow.WorkflowAware#setReviewStatus(gov.nih.nci.cabig.caaers.domain.ReviewStatus)
     */
    public void setReviewStatus(ReviewStatus reviewStatus) {
        this.reviewStatus = reviewStatus;
    }

    /**
     * Gets the mandatory fields.
     *
     * @return the mandatory fields
     */
    @Transient
    public List<ReportMandatoryField> getMandatoryFields() {
        return mandatoryFields;
    }

    /**
     * Sets the mandatory fields.
     *
     * @param mandatoryFields the new mandatory fields
     */
    public void setMandatoryFields(List<ReportMandatoryField> mandatoryFields) {
        this.mandatoryFields = mandatoryFields;
    }

    /**
     * Checks if is workflow enabled.
     *
     * @return true, if is workflow enabled
     */
    @Transient
    public boolean isWorkflowEnabled() {
        if (getReportDefinition() != null) {
            return (getReportDefinition().getWorkflowEnabled() != null
                    && getReportDefinition().getWorkflowEnabled()) && getWorkflowId() != null;
        }
        return false;
    }

    /**
     * Gets the submitted to fda.
     *
     * @return the submitted to fda
     */
    @Transient
    public String getSubmittedToFDA() {
        return submittedToFDA;
    }

    /**
     * Sets the submitted to fda.
     *
     * @param submittedToFDA the new submitted to fda
     */
    public void setSubmittedToFDA(String submittedToFDA) {
        this.submittedToFDA = submittedToFDA;
    }

    /**
     * Copy the Report Details from Input to Output.
     *
     * @param src
     */
    public void copy(Report src) {
        if (src.getReviewStatus() != null)
            setReviewStatus(src.getReviewStatus());
        if (src.getPhysicianSignoff() != null)
            setPhysicianSignoff(src.getPhysicianSignoff());
        if (src.getCaseNumber() != null)
            setCaseNumber(src.getCaseNumber());
        if (src.getMetaData() != null)
            setMetaData(src.getMetaData());
        if (src.getEmailAddresses() != null && !src.getEmailAddresses().isEmpty())
            setEmailAddresses(src.getEmailAddresses());
        if (src.getAssignedIdentifer() != null)
            setAssignedIdentifer(src.getAssignedIdentifer()); //ticket number (if any)
        if (src.getLastVersion().getCcEmails() != null)
            getLastVersion().setCcEmails(src.getLastVersion().getCcEmails());
        if (src.getLastVersion().getWithdrawnOn() != null)
            getLastVersion().setWithdrawnOn(src.getLastVersion().getWithdrawnOn());
        if (src.getSubmitter() == null)
            return;
        if (getSubmitter() == null)
            getLastVersion().addSubmitter();
        getSubmitter().copy(src.getSubmitter());
    }

    @Transient
    public Boolean isSameReportByCaseNumberOrReportDefinition(Report report) {

        // check if case number is same
        if (this.getCaseNumber() != null && this.getCaseNumber().equalsIgnoreCase(report.getCaseNumber())) {
            return true;
        }

        //check if they belong to the same report definition. 
        if (this.getReportDefinition().getName().equals(report.getReportDefinition().getName())) {
            return true;
        }

        return false;
    }
}