package gov.nih.nci.cabig.caaers.domain;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.commons.collections.functors.InstantiateFactory;
import org.apache.commons.collections.list.LazyList;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.IndexColumn;
import org.hibernate.annotations.Parameter;
import org.springframework.beans.BeanUtils;

/**
 * This class represents the TreatmentInformation domain object associated with the Adverse event
 * report.
 *
 * @author Rhett Sutphin
 */
@Entity
@Table(name = "treatments")
@GenericGenerator(name = "id-generator", strategy = "native", parameters = {@Parameter(name = "sequence", value = "seq_treatments_id")})
public class TreatmentInformation extends AbstractExpeditedReportSingleChild {
    
    private List<CourseAgent> courseAgentsInternal;
    private List<CourseAgent> courseAgents;
    private Date firstCourseDate;
    private CourseDate adverseEventCourse;
    private Integer totalCourses;
    private TreatmentAssignment treatmentAssignment;
    private String treatmentDescription;

    public TreatmentInformation() {
        setCourseAgentsInternal(new LinkedList<CourseAgent>());
    }

    // //// LOGIC

    @Transient
    public boolean isInvestigationalAgentAdministered() {
        for (CourseAgent courseAgent : getCourseAgents()) {
            Boolean indicator = courseAgent.getStudyAgent().getInvestigationalNewDrugIndicator();
            if (indicator != null && indicator) return true;
        }
        return false;
    }

    public void addCourseAgent(CourseAgent courseAgent) {
        courseAgent.setTreatmentInformation(this);
        getCourseAgents().add(courseAgent);
    }

    /**
     * @return a wrapped list which will never throw an {@link IndexOutOfBoundsException}
     */
    @Transient
    public List<CourseAgent> getCourseAgents() {
        return courseAgents;
    }

    @SuppressWarnings("unchecked")
    private void createLazyCourseAgents() {
        this.courseAgents = LazyList.decorate(getCourseAgentsInternal(), new InstantiateFactory(
                CourseAgent.class));
    }

    // //// BEAN PROPERTIES

    public Date getFirstCourseDate() {
        return firstCourseDate;
    }

    public void setFirstCourseDate(Date firstCourse) {
        this.firstCourseDate = firstCourse;
    }

    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name = "date", column = @Column(name = "adverse_event_course_date")),
            @AttributeOverride(name = "number", column = @Column(name = "adverse_event_course_number"))})
    public CourseDate getAdverseEventCourse() {
        if (adverseEventCourse == null) adverseEventCourse = new CourseDate();
        return adverseEventCourse;
    }

    public void setAdverseEventCourse(CourseDate adverseEventCourse) {
        this.adverseEventCourse = adverseEventCourse;
    }

    // This is annotated this way so that the IndexColumn will work with
    // the bidirectional mapping. See section 2.4.6.2.3 of the hibernate annotations docs.
    @OneToMany
    @JoinColumn(name = "treatment_id", nullable = false)
    @IndexColumn(name = "list_index")
    @Cascade(value = {CascadeType.ALL, CascadeType.DELETE_ORPHAN})
    public List<CourseAgent> getCourseAgentsInternal() {
        return courseAgentsInternal;
    }

    public void setCourseAgentsInternal(List<CourseAgent> courseAgentsInternal) {
        this.courseAgentsInternal = courseAgentsInternal;
        createLazyCourseAgents();
    }

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "treatment_assignment_id")
    @Cascade(value = {CascadeType.LOCK})
    public TreatmentAssignment getTreatmentAssignment() {
        return treatmentAssignment;
    }

    public void setTreatmentAssignment(TreatmentAssignment treatmentAssignment) {
        this.treatmentAssignment = treatmentAssignment;
    }

    public String getTreatmentDescription() {
        return treatmentDescription;
    }

    public void setTreatmentDescription(String treatmentDescription) {
        this.treatmentDescription = treatmentDescription;
    }

    public Integer getTotalCourses() {
        return totalCourses;
    }

    public void setTotalCourses(Integer totalCourses) {
        this.totalCourses = totalCourses;
    }

    @Transient
    public String getTreatmentAssignmentDescription() {
        if (treatmentAssignment != null) return treatmentAssignment.getDescription();
        return null;
    }

    @Transient
    public void setTreatmentAssignmentDescription(String desc) {
        // do nothing.
    }


    public TreatmentInformation copy() {
        TreatmentInformation treatmentInformation = new TreatmentInformation();
        BeanUtils.copyProperties(this, treatmentInformation,
                new String[]{"id", "gridId", "version"
                        , "courseAgentsInternal", "report", "courseAgents"});


        for (CourseAgent courseAgent : getCourseAgentsInternal()) {
            treatmentInformation.addCourseAgent(courseAgent.copy());
        }

        return treatmentInformation;
    }
}

@@ -1610,16 +1610,70 @@
 ription;
+%0A    private Boolean investigationalAgentAdministered;
 %0A%0A    pu
@@ -5677,11 +5677,291 @@
 n;%0A    %7D
+%0A%0A%09public Boolean getInvestigationalAgentAdministered() %7B%0A%09%09return investigationalAgentAdministered;%0A%09%7D%0A%0A%09public void setInvestigationalAgentAdministered(%0A%09%09%09Boolean investigationalAgentAdministered) %7B%0A%09%09this.investigationalAgentAdministered = investigationalAgentAdministered;%0A%09%7D
 %0A%7D%0A

add investigationalAgentAdministered