package org.msh.tb.entities;

import org.hibernate.validator.NotNull;
import org.jboss.seam.international.Messages;
import org.msh.etbm.commons.transactionlog.Operation;
import org.msh.etbm.commons.transactionlog.mapping.PropertyLog;
import org.msh.tb.entities.enums.*;
import org.msh.tb.sync.Sync;
import org.msh.utils.date.DateUtils;
import org.msh.utils.date.Period;
import org.msh.validators.InnerValidation;

import javax.persistence.*;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.*;



/**
 * Store information about a case (TB or DR-TB)
 * @author Ricardo Memoria
 *
 */
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "tbcase")
public class TbCase implements Serializable, Transactional, SyncKey {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;

    @Version
    @PropertyLog(ignore=true)
    private Integer version;

    private Integer caseNumber;

    // specific suspect information
    @Column(length=50)
    private String suspectRegistrationCode;
    @PropertyLog(messageKey="CaseClassification")
    private CaseClassification suspectClassification;

    @Column(length=50)
    @PropertyLog(operations={Operation.NEW, Operation.DELETE})
    private String registrationCode;

    private Integer daysTreatPlanned;

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="PATIENT_ID")
    @NotNull
    @PropertyLog(logEntityFields=true)
    @InnerValidation
    @Sync(keyAttribute = true, internalKeyAttribute = "name,gender")
    private Patient patient;

    @Sync(keyAttribute = true)
    private Integer age;

    @NotNull
    @Temporal(TemporalType.DATE)
    @PropertyLog(operations={Operation.NEW, Operation.DELETE})
    @Sync(keyAttribute = true)
    private Date registrationDate;

    @Temporal(TemporalType.DATE)
    @PropertyLog(operations={Operation.NEW, Operation.DELETE})
    private Date diagnosisDate;

    @Temporal(TemporalType.DATE)
    private Date outcomeDate;

    // Treatment information
    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name="iniDate", column=@Column(name="iniTreatmentDate")),
            @AttributeOverride(name="endDate", column=@Column(name="endTreatmentDate"))
    })
    @PropertyLog(logEntityFields=true)
    private Period treatmentPeriod = new Period();

    @Temporal(TemporalType.DATE)
    private Date iniContinuousPhase;

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="REGIMEN_ID")
    private Regimen regimen;

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="REGIMEN_INI_ID")
    private Regimen regimenIni;

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="OWNER_UNIT_ID")
    @NotNull
    @Sync(keyAttribute = true, internalKeyAttribute = "id")
    private Tbunit ownerUnit ;

    @OneToMany(cascade={CascadeType.ALL}, mappedBy="tbcase")
    @PropertyLog(ignore=true)
    @Sync(clearList = true)
    private List<TreatmentHealthUnit> healthUnits = new ArrayList<TreatmentHealthUnit>();

    @OneToMany(cascade={CascadeType.ALL}, mappedBy="tbcase")
    @PropertyLog(ignore=true)
    @Sync(clearList = true)
    private List<PrescribedMedicine> prescribedMedicines = new ArrayList<PrescribedMedicine>();

    @NotNull
    private CaseState state;

    @NotNull
    private ValidationState validationState;

    @PropertyLog(operations = { Operation.NEW, Operation.DELETE })
    private PatientType patientType;

    @PropertyLog(operations = { Operation.NEW, Operation.DELETE })
    private PatientType previouslyTreatedType;

    @PropertyLog(operations = { Operation.NEW, Operation.DELETE })
    private CaseDefinition caseDefinition;

    @PropertyLog(operations={Operation.NEW, Operation.DELETE})
    @Sync(keyAttribute = true)
    private DiagnosisType diagnosisType;

    @PropertyLog(operations={Operation.NEW, Operation.DELETE})
    private DrugResistanceType drugResistanceType;

    @NotNull
    @PropertyLog(operations={Operation.NEW, Operation.DELETE})
    private CaseClassification classification;

    @PropertyLog(messageKey="InfectionSite", operations={Operation.NEW})
    private InfectionSite infectionSite;

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="PULMONARY_ID")
    @PropertyLog(messageKey="TbField.PULMONARY_TYPES")
    private FieldValue pulmonaryType;

    @Embedded
    @AssociationOverrides({ @AssociationOverride(name = "value", joinColumns = @JoinColumn(name = "EXTRAPULMONARY_ID")) })
    @AttributeOverrides({ @AttributeOverride(name = "complement", column = @Column(name = "otherExtrapulmonary")) })
    @PropertyLog(messageKey = "TbField.EXTRAPULMONARY_TYPES")
    private FieldValueComponent extrapulmonaryType;

    @Embedded
    @AssociationOverrides({ @AssociationOverride(name = "value", joinColumns = @JoinColumn(name = "EXTRAPULMONARY2_ID")) })
    @AttributeOverrides({ @AttributeOverride(name = "complement", column = @Column(name = "otherExtrapulmonary2")) })
    @PropertyLog(messageKey = "TbField.EXTRAPULMONARY_TYPES")
    private FieldValueComponent extrapulmonaryType2;

    @Column(length = 100)
    private String patientTypeOther;

    private Nationality nationality;

    @Column(length = 100)
    private String otherOutcome;

    @Column(length = 50)
    @PropertyLog(messageKey = "global.legacyId")
    private String legacyId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "NOTIFICATION_UNIT_ID")
    @PropertyLog(operations = {Operation.NEW, Operation.DELETE})
    @Sync(keyAttribute = true, internalKeyAttribute = "id")
    private Tbunit notificationUnit;

    private boolean notifAddressChanged;

    private boolean tbContact;

    private boolean movedSecondLineTreatment;

    @Column(length = 100)
    private String patientContactName;

    @Lob
    private String comments;

    private TreatmentCategory treatmentCategory;

    private Boolean initialRegimenWithSecondLineDrugs;

    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name="address", column=@Column(name="NOTIF_ADDRESS")),
            @AttributeOverride(name="complement", column=@Column(name="NOTIF_COMPLEMENT")),
            @AttributeOverride(name="localityType", column=@Column(name="NOTIF_LOCALITYTYPE")),
            @AttributeOverride(name="zipCode", column=@Column(name="NOTIF_ZIPCODE")),
    })
    @AssociationOverrides({
            @AssociationOverride(name="adminUnit", joinColumns=@JoinColumn(name="NOTIF_ADMINUNIT_ID"))
    })
    @PropertyLog(messageKey="cases.details.addressnotif", operations={Operation.NEW})
    @InnerValidation
    private Address notifAddress;

    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name="address", column=@Column(name="CURR_ADDRESS")),
            @AttributeOverride(name="complement", column=@Column(name="CURR_COMPLEMENT")),
            @AttributeOverride(name="localityType", column=@Column(name="CURR_LOCALITYTYPE")),
            @AttributeOverride(name="zipCode", column=@Column(name="CURR_ZIPCODE")),
    })
    @AssociationOverrides({
            @AssociationOverride(name="adminUnit", joinColumns=@JoinColumn(name="CURR_ADMINUNIT_ID"))
    })
    @PropertyLog(messageKey="cases.details.addresscurr")
    @InnerValidation
    private Address currentAddress;

    @Column(length=50)
    private String phoneNumber;

    @Column(length=50)
    private String mobileNumber;

    @OneToMany(cascade={CascadeType.ALL}, mappedBy="tbcase", fetch=FetchType.LAZY)
    private List<CaseSideEffect> sideEffects = new ArrayList<CaseSideEffect>();

    @OneToMany(cascade={CascadeType.ALL}, mappedBy="tbcase", fetch=FetchType.LAZY)
    @Sync(clearList = true)
    private List<CaseComorbidity> comorbidities = new ArrayList<CaseComorbidity>();

    @OneToMany(cascade={CascadeType.ALL}, mappedBy="tbcase", fetch=FetchType.LAZY)
    @OrderBy("date desc")
    private List<MedicalExamination> examinations = new ArrayList<MedicalExamination>();

    @OneToMany(cascade={CascadeType.ALL}, mappedBy="tbcase", fetch=FetchType.LAZY)
    private List<ExamXRay> resXRay = new ArrayList<ExamXRay>();

    @OneToMany(cascade={CascadeType.ALL}, mappedBy="tbcase", fetch=FetchType.LAZY)
    private List<TbContact> contacts = new ArrayList<TbContact>();

    @OneToMany(cascade={CascadeType.MERGE, CascadeType.PERSIST}, mappedBy="tbcase", fetch=FetchType.LAZY)
    @Sync(clearList = true)
    private List<TreatmentMonitoring> treatmentMonitoring = new ArrayList<TreatmentMonitoring>();


    /* EXAMS */
    @OneToMany(cascade={CascadeType.ALL}, mappedBy="tbcase", fetch=FetchType.LAZY)
    private List<ExamHIV> resHIV = new ArrayList<ExamHIV>();

    @OneToMany(cascade={CascadeType.ALL}, mappedBy="tbcase", fetch=FetchType.LAZY)
    private List<ExamCulture> examsCulture = new ArrayList<ExamCulture>();

    @OneToMany(cascade = {CascadeType.ALL}, mappedBy="tbcase", fetch=FetchType.LAZY)
    private List<ExamMicroscopy> examsMicroscopy = new ArrayList<ExamMicroscopy>();

    @OneToMany(cascade={CascadeType.ALL}, mappedBy="tbcase", fetch=FetchType.LAZY)
    private List<ExamDST> examsDST = new ArrayList<ExamDST>();

    @OneToMany(cascade={CascadeType.ALL}, mappedBy="tbcase", fetch=FetchType.LAZY)
    private List<ExamXpert> examsXpert = new ArrayList<ExamXpert>();

    @OneToMany(cascade={CascadeType.ALL}, mappedBy="tbcase", fetch=FetchType.LAZY)
    @Sync(clearList = true)
    @PropertyLog(alwaysLog = true)
    private List<PrevTBTreatment> prevTbTreats = new ArrayList<PrevTBTreatment>();

    @PropertyLog(operations={Operation.NEW, Operation.DELETE})
    private SecDrugsReceived secDrugsReceived;

    private int issueCounter;

    @Temporal(TemporalType.DATE)
    @PropertyLog(operations = {Operation.NEW, Operation.DELETE})
    private Date lastBmuDateTbRegister;

    @Column(length = 50)
    @PropertyLog(operations = {Operation.NEW, Operation.DELETE})
    private String lastBmuTbRegistNumber;

    @Transient
    // Ricardo: TEMPORARY UNTIL A SOLUTION IS FOUND. Just to attend a request from the XML data model to
    // map an XML node to a property in the model
    private Integer clientId;

    /**
     * HIV result calculated by the system from hivResult field and HIV exams
     */
    private HIVResult hivResult;

    private Date startedARTdate;

    private Date startedCPTdate;

    private RifResistance rifResistance;

    /**
     * @return
     */
    public Integer getClientId() {
        return clientId;
    }

    /**
     * @param clientId
     */
    public void setClientId(Integer clientId) {
        this.clientId = clientId;
    }

    /**
     * Tags of this case
     */
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "tags_case",
            joinColumns = {@JoinColumn (name = "CASE_ID")},
            inverseJoinColumns = {@JoinColumn (name = "TAG_ID")})
    private List<Tag> tags = new ArrayList<Tag>();


    /**
     * Point to the transaction log that contains information about the last time this entity was changed (updated or created)
     */
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="lastTransaction_ID")
    @PropertyLog(ignore=true)
    private TransactionLog lastTransaction;


    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        String s = getPatient().getFullName();
        String num = getDisplayCaseNumber();
        if (num != null)
            s = "(" + num + ") " + s;

        return s;
    }


    /**
     * Check if the regimen has changed compared to the initial regimen
     * @return
     */
    public boolean isInitialRegimenChanged() {
        if (regimen == regimenIni)
            return false;

        if ((regimen == null) || (regimenIni == null))
            return true;

        return (regimen.getId().equals(regimenIni.getId()));
    }


    /**
     * Update number of days of treatment planned for the patient
     */
    public void updateDaysTreatPlanned() {
        Date dt = getTreatmentPeriod().getIniDate();
        Date dtend = getTreatmentPeriod().getEndDate();

        int num = 0;
        while (!dt.after(dtend)) {
            if (isDayPrescription(dt))
                num++;
            dt = DateUtils.incDays(dt, 1);
        }

        daysTreatPlanned = num;
    }


    /**
     * Returns if the date dt is a day of medicine prescription
     * @param dt - Date
     * @return true - if it's a day of medicine prescription
     */
    public boolean isDayPrescription(Date dt) {
        if ((treatmentPeriod == null) || (treatmentPeriod.isEmpty()))
            return false;

        if (!treatmentPeriod.isDateInside(dt))
            return false;

        for (PrescribedMedicine pm: getPrescribedMedicines()) {
            if (pm.getPeriod().isDateInside(dt)) {
                WeeklyFrequency wf = pm.getWeeklyFrequency();
                if (wf.isDateSet(dt))
                    return true;
            }
        }

        return false;
    }

    /**
     * Return number of month of treatment based on the date
     * @param date
     * @return
     */
    public int getMonthTreatment(Date date) {
        if ((treatmentPeriod == null) || (date == null))
            return -1;

        Date dtTreat = getTreatmentPeriod().getIniDate();
        if ((dtTreat == null) || (date.before(dtTreat)))
            return -1;

        int num = DateUtils.monthsBetween(date, dtTreat) + 1;

        return num;
    }


    /**
     * Return list of treatment health units sorted by period
     * @return
     */
    public List<TreatmentHealthUnit> getSortedTreatmentHealthUnits() {
        // sort the periods
        Collections.sort(healthUnits, new Comparator<TreatmentHealthUnit>() {
            public int compare(TreatmentHealthUnit o1, TreatmentHealthUnit o2) {
                return o1.getPeriod().getIniDate().compareTo(o2.getPeriod().getIniDate());
            }
        });

        return healthUnits;
    }


    /**
     * Return list of prescribed medicines sorted by medicine name and initial date of the period
     * @return
     */
    public List<PrescribedMedicine> getSortedPrescribedMedicines() {
        // sort the periods
        Collections.sort(prescribedMedicines, new Comparator<PrescribedMedicine>() {
            public int compare(PrescribedMedicine pm1, PrescribedMedicine pm2) {
                int val = pm1.getMedicine().getAbbrevName().compareTo(pm2.getMedicine().getAbbrevName());

                return (val != 0? val: pm1.getPeriod().getIniDate().compareTo(pm2.getPeriod().getEndDate()));
            }
        });

        return prescribedMedicines;
    }


    /**
     * Returns if the case is validated or not
     * @return true - if the case is validated, false - otherwise
     */
    public boolean isValidated() {
        return getValidationState() == ValidationState.VALIDATED;
    }

    /**
     * Returns if the case is a pulmonary TB/MDRTB
     * @return - true if it is pulmonary or pulmonary/extrapulmonary
     */
    public boolean isPulmonary() {
        return (getInfectionSite() != null) && ((infectionSite == InfectionSite.PULMONARY) || (infectionSite == InfectionSite.BOTH));
    }


    /**
     * Returns if the case is a extrapulmonary TB/MDRTB
     * @return - true if it is extrapulmonary or pulmonary/extrapulmonary
     */
    public boolean isExtrapulmonary() {
        return (getInfectionSite() != null) && ((infectionSite == InfectionSite.EXTRAPULMONARY) || (infectionSite == InfectionSite.BOTH));
    }

    /**
     * Search for side effect data by the side effect
     * @param sideEffect - FieldValue object representing the side effect
     * @return - CaseSideEffect instance containing side effect data of the case, or null if there is no side effect data
     */
    public CaseSideEffect findSideEffectData(FieldValue sideEffect) {
        for (CaseSideEffect se: getSideEffects()) {
            if (se.getSideEffect().getValue().equals(sideEffect))
                return se;
        }
        return null;
    }


    /**
     * Return the unit that transferred the case in
     * @return instance of {@link TreatmentHealthUnit} containing information about the transfer out
     */
    public TreatmentHealthUnit getTransferInUnit() {
        return (state == CaseState.TRANSFERRING) && (healthUnits.size() > 1) ? healthUnits.get(healthUnits.size()-1): null;
    }


    /**
     * Return the unit that transferred the case out
     * @return instance of {@link TreatmentHealthUnit} containing information about the transfer in
     */
    public TreatmentHealthUnit getTransferOutUnit() {
        return (state == CaseState.TRANSFERRING) && (healthUnits.size() > 1) ? healthUnits.get(healthUnits.size()-2): null;
    }


    /**
     * @return the sideEffects
     */
    public List<CaseSideEffect> getSideEffects() {
        return sideEffects;
    }


    /**
     * @param sideEffects the sideEffects to set
     */
    public void setSideEffects(List<CaseSideEffect> sideEffects) {
        this.sideEffects = sideEffects;
    }


    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;

        if (!(obj instanceof TbCase))
            return false;

        if (((TbCase)obj).getId() == null) {
            return false;
        }

        return ((TbCase)obj).getId().equals(getId());
    }


    /**
     * Returns the case number in a formated way ready for displaying
     * @return
     */
    public String getDisplayCaseNumber() {
        Workspace ws = (getPatient() != null? getPatient().getWorkspace() : null);

        if (ws == null)
            return getId() != null? getId().toString(): "null";

        DisplayCaseNumber dcn;
        if (getDiagnosisType().equals(DiagnosisType.SUSPECT))
            dcn = ws.getSuspectCaseNumber();
        else dcn = ws.getConfirmedCaseNumber();

        switch (dcn) {
            case USER_DEFINED: {
                String code;
                if (getDiagnosisType().equals(DiagnosisType.SUSPECT))
                    code = getSuspectRegistrationCode();
                else code = getRegistrationCode();
                if ((code == null) || (code.isEmpty()))
                    code = Messages.instance().get("cases.nonumber");
                return code;
            }
            case VALIDATION_NUMBER:
                return getDisplayValidationNumber();
            default: {
                String r = getId() != null ? getId().toString() : Messages.instance().get("cases.nonumber");
                if ((getCaseNumber() != null) && (getValidationState() != ValidationState.WAITING_VALIDATION))
                    r += " (" + getDisplayValidationNumber() + ")";
                return r;
            }
        }
    }


    public String getDisplayValidationNumber() {
        if ((getCaseNumber() == null) || (getValidationState() == ValidationState.WAITING_VALIDATION))
            return Messages.instance().get("cases.nonumber");
        else return formatCaseNumber(patient.getRecordNumber(), caseNumber);
    }

    /**
     * Formats the case number to be displayed to the user
     * @param patientNumber - patient record number
     * @param caseNumber - case number associated to the patient
     * @return - formated case number
     */
    static public String formatCaseNumber(int patientNumber, int caseNumber) {
        DecimalFormat df = new DecimalFormat("000");
        String s = df.format(patientNumber);

        if (caseNumber > 1)
            return s + "-" + Integer.toString(caseNumber);
        else return s;
    }


    /**
     * Check if the case is open
     * @return
     */
    public boolean isOpen() {
        return (state != null ? state.ordinal() <=  CaseState.TRANSFERRING.ordinal() : false);
    }


    /**
     * Is case on treatment ?
     * @return
     */
    public boolean isOnTreatment() {
        return (state == CaseState.ONTREATMENT) || (state == CaseState.TRANSFERRING);
    }

    /**
     * Return the treatment period of the intensive phase
     * @return
     */
    public Period getIntensivePhasePeriod() {
        if ((treatmentPeriod == null) || (treatmentPeriod.isEmpty()))
            return null;

        if (iniContinuousPhase != null)
            return new Period(treatmentPeriod.getIniDate(), DateUtils.incDays( iniContinuousPhase, -1 ) );
        else return new Period(treatmentPeriod);
    }


    /**
     * Return the treatment period of the continuous phase
     * @return
     */
    public Period getContinuousPhasePeriod() {
        if ((iniContinuousPhase == null) || (treatmentPeriod == null) || (treatmentPeriod.isEmpty()))
            return null;

        return new Period(iniContinuousPhase, treatmentPeriod.getEndDate());
    }


    /**
     * Returns patient age at the date of the notification
     * @return
     */
    public int getPatientAge() {
        if (age != null)
            return age;

        Patient p = getPatient();
        if (p == null)
            return 0;

        Date dt = p.getBirthDate();
        Date dt2 = diagnosisDate;

        if (dt == null)
            return 0;
        if (dt2 == null)
            dt2 = new Date();
        return DateUtils.yearsBetween(dt, dt2);
    }


    public Integer getCaseNumber() {
        return caseNumber;
    }

    public void setCaseNumber(Integer caseNumber) {
        this.caseNumber = caseNumber;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Patient getPatient() {
        return patient;
    }

    public void setPatient(Patient patient) {
        this.patient = patient;
    }

    public CaseState getState() {
        return state;
    }

    public void setState(CaseState state) {
        this.state = state;
    }

    public List<TreatmentHealthUnit> getHealthUnits() {
        return healthUnits;
    }

    public void setHealthUnits(List<TreatmentHealthUnit> healthUnits) {
        this.healthUnits = healthUnits;
    }



    public List<ExamHIV> getResHIV() {
        return resHIV;
    }


    public void setResHIV(List<ExamHIV> resHIV) {
        this.resHIV = resHIV;
    }


    public List<MedicalExamination> getExaminations() {
        return examinations;
    }


    public void setExaminations(List<MedicalExamination> examinations) {
        this.examinations = examinations;
    }


    public CaseClassification getClassification() {
        return classification;
    }


    public void setClassification(CaseClassification classification) {
        this.classification = classification;
    }


    public InfectionSite getInfectionSite() {
        return infectionSite;
    }


    public void setInfectionSite(InfectionSite infectionSite) {
        this.infectionSite = infectionSite;
    }


    public Address getNotifAddress() {
        if (notifAddress == null)
            notifAddress = new Address();
        return notifAddress;
    }


    public void setNotifAddress(Address notifAddress) {
        this.notifAddress = notifAddress;
    }


    public Address getCurrentAddress() {
        if (currentAddress == null)
            currentAddress = new Address();
        return currentAddress;
    }


    public void setCurrentAddress(Address currentAddress) {
        this.currentAddress = currentAddress;
    }


    public boolean isNotifAddressChanged() {
        return notifAddressChanged;
    }


    public void setNotifAddressChanged(boolean notifAddressChanged) {
        this.notifAddressChanged = notifAddressChanged;
    }


    public String getOtherOutcome() {
        return otherOutcome;
    }


    public void setOtherOutcome(String otherOutcome) {
        this.otherOutcome = otherOutcome;
    }


    public String getLegacyId() {
        return legacyId;
    }


    public void setLegacyId(String legacyId) {
        this.legacyId = legacyId;
    }


    public PatientType getPatientType() {
        return patientType;
    }


    public void setPatientType(PatientType patientType) {
        this.patientType = patientType;
    }


    public Nationality getNationality() {
        return nationality;
    }


    public void setNationality(Nationality nationality) {
        this.nationality = nationality;
    }


    public Tbunit getNotificationUnit() {
        return notificationUnit;
    }


    public void setNotificationUnit(Tbunit notificationUnit) {
        this.notificationUnit = notificationUnit;
    }


    public Date getDiagnosisDate() {
        return diagnosisDate;
    }

    public String getDiagnosisDateFormated() {
        return DateUtils.formatAsLocale(diagnosisDate, false);
    }

    public String getRegistrationDateFormated() {
        return DateUtils.formatAsLocale(registrationDate, false);
    }

    public void setDiagnosisDate(Date diagnosisDate) {
        this.diagnosisDate = diagnosisDate;
    }


    public Date getOutcomeDate() {
        return outcomeDate;
    }


    public void setOutcomeDate(Date outcomeDate) {
        this.outcomeDate = outcomeDate;
    }


    public String getPatientTypeOther() {
        return patientTypeOther;
    }


    public void setPatientTypeOther(String patientTypeOther) {
        this.patientTypeOther = patientTypeOther;
    }


    /**
     * @return the resXRay
     */
    public List<ExamXRay> getResXRay() {
        return resXRay;
    }


    /**
     * @param resXRay the resXRay to set
     */
    public void setResXRay(List<ExamXRay> resXRay) {
        this.resXRay = resXRay;
    }


    /**
     * @return the comorbidities
     */
    public List<CaseComorbidity> getComorbidities() {
        return comorbidities;
    }


    /**
     * @param comorbidities the comorbidities to set
     */
    public void setComorbidities(List<CaseComorbidity> comorbidities) {
        this.comorbidities = comorbidities;
    }


    /**
     * @return the age
     */
    public Integer getAge() {
        return age;
    }


    /**
     * @param age the age to set
     */
    public void setAge(Integer age) {
        this.age = age;
    }


    /**
     * @return the registrationDate
     */
    public Date getRegistrationDate() {
        return registrationDate;
    }

    /**
     * @param registrationDate the registrationDate to set
     */
    public void setRegistrationDate(Date registrationDate) {
        this.registrationDate = registrationDate;
    }


    /**
     * @param diagnosisType the diagnosisType to set
     */
    public void setDiagnosisType(DiagnosisType diagnosisType) {
        this.diagnosisType = diagnosisType;
    }


    /**
     * @return the diagnosisType
     */
    public DiagnosisType getDiagnosisType() {
        return diagnosisType;
    }

    public Boolean getIsSuspect() {
        return DiagnosisType.SUSPECT.equals(this.getDiagnosisType());
    }

    /**
     * @return the registrationCode
     */
    public String getRegistrationCode() {
        return registrationCode;
    }


    /**
     * @param registrationCode the registrationCode to set
     */
    public void setRegistrationCode(String registrationCode) {
        this.registrationCode = registrationCode;
    }


    /**
     * @return the drugResistanceType
     */
    public DrugResistanceType getDrugResistanceType() {
        return drugResistanceType;
    }


    /**
     * @param drugResistanceType the drugResistanceType to set
     */
    public void setDrugResistanceType(DrugResistanceType drugResistanceType) {
        this.drugResistanceType = drugResistanceType;
    }


    /**
     * @return the comments
     */
    public String getComments() {
        return comments;
    }


    /**
     * @param comments the comments to set
     */
    public void setComments(String comments) {
        this.comments = comments;
    }



    /**
     * @return the patientContactName
     */
    public String getPatientContactName() {
        return patientContactName;
    }


    /**
     * @param patientContactName the patientContactName to set
     */
    public void setPatientContactName(String patientContactName) {
        this.patientContactName = patientContactName;
    }


    /**
     * @param tbContact the tbContact to set
     */
    public void setTbContact(boolean tbContact) {
        this.tbContact = tbContact;
    }


    /**
     * @return the tbContact
     */
    public boolean isTbContact() {
        return tbContact;
    }


    /**
     * @return the contacts
     */
    public List<TbContact> getContacts() {
        return contacts;
    }


    /**
     * @param contacts the contacts to set
     */
    public void setContacts(List<TbContact> contacts) {
        this.contacts = contacts;
    }


    /**
     * @return the pulmonaryType
     */
    public FieldValue getPulmonaryType() {
        return pulmonaryType;
    }


    /**
     * @param pulmonaryType the pulmonaryType to set
     */
    public void setPulmonaryType(FieldValue pulmonaryType) {
        this.pulmonaryType = pulmonaryType;
    }


    /**
     * @return the extrapulmonaryType
     */
    public FieldValueComponent getExtrapulmonaryType() {
        if (extrapulmonaryType == null) {
            extrapulmonaryType = new FieldValueComponent();
        }
        return extrapulmonaryType;
    }


    /**
     * @param extrapulmonaryType the extrapulmonaryType to set
     */
    public void setExtrapulmonaryType(FieldValueComponent extrapulmonaryType) {
        this.extrapulmonaryType = extrapulmonaryType;
    }


    /**
     * @return the extrapulmonaryType2
     */
    public FieldValueComponent getExtrapulmonaryType2() {
        if (extrapulmonaryType2 == null) {
            extrapulmonaryType2 = new FieldValueComponent();
        }
        return extrapulmonaryType2;
    }


    /**
     * @param extrapulmonaryType2 the extrapulmonaryType2 to set
     */
    public void setExtrapulmonaryType2(FieldValueComponent extrapulmonaryType2) {
        this.extrapulmonaryType2 = extrapulmonaryType2;
    }


    /**
     * @return the daysTreatPlanned
     */
    public Integer getDaysTreatPlanned() {
        return daysTreatPlanned;
    }


    /**
     * @param daysTreatPlanned the daysTreatPlanned to set
     */
    public void setDaysTreatPlanned(Integer daysTreatPlanned) {
        this.daysTreatPlanned = daysTreatPlanned;
    }


    /**
     * @return the phoneNumber
     */
    public String getPhoneNumber() {
        return phoneNumber;
    }


    /**
     * @param phoneNumber the phoneNumber to set
     */
    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }


    /**
     * @return the mobileNumber
     */
    public String getMobileNumber() {
        return mobileNumber;
    }


    /**
     * @param mobileNumber the mobileNumber to set
     */
    public void setMobileNumber(String mobileNumber) {
        this.mobileNumber = mobileNumber;
    }


    /**
     * @return the validationState
     */
    public ValidationState getValidationState() {
        return validationState;
    }


    /**
     * @param validationState the validationState to set
     */
    public void setValidationState(ValidationState validationState) {
        this.validationState = validationState;
    }


    /**
     * @return the issueCounter
     */
    public int getIssueCounter() {
        return issueCounter;
    }


    /**
     * @param issueCount the issueCounter to set
     */
    public void setIssueCounter(int issueCount) {
        this.issueCounter = issueCount;
    }

    public void incIssueCounter() {
        issueCounter++;
    }


    public void setPrescribedMedicines(List<PrescribedMedicine> prescribedMedicines) {
        this.prescribedMedicines = prescribedMedicines;
    }


    public List<PrescribedMedicine> getPrescribedMedicines() {
        return prescribedMedicines;
    }


    public Period getTreatmentPeriod() {
        return treatmentPeriod;
    }


    public void setTreatmentPeriod(Period treatmentPeriod) {
        this.treatmentPeriod = treatmentPeriod;
    }


    public Integer getVersion() {
        return version;
    }


    public void setVersion(Integer version) {
        this.version = version;
    }


    public List<ExamCulture> getExamsCulture() {
        return examsCulture;
    }


    public void setExamsCulture(List<ExamCulture> examsCulture) {
        this.examsCulture = examsCulture;
    }


    public List<ExamMicroscopy> getExamsMicroscopy() {
        return examsMicroscopy;
    }


    public void setExamsMicroscopy(List<ExamMicroscopy> examsMicroscopy) {
        this.examsMicroscopy = examsMicroscopy;
    }


    public List<ExamDST> getExamsDST() {
        return examsDST;
    }


    public void setExamsDST(List<ExamDST> examsDST) {
        this.examsDST = examsDST;
    }


    /**
     * @return the iniContinuousPhase
     */
    public Date getIniContinuousPhase() {
        return iniContinuousPhase;
    }


    /**
     * @param iniContinuousPhase the iniContinuousPhase to set
     */
    public void setIniContinuousPhase(Date iniContinuousPhase) {
        this.iniContinuousPhase = iniContinuousPhase;
    }


    /**
     * @return the regimen
     */
    public Regimen getRegimen() {
        return regimen;
    }


    /**
     * @param regimen the regimen to set
     */
    public void setRegimen(Regimen regimen) {
        this.regimen = regimen;
    }


    /**
     * @return the ownerUnit
     */
    public Tbunit getOwnerUnit() {
        return ownerUnit;
    }


    /**
     * @param ownerUnit the ownerUnit to set
     */
    public void setOwnerUnit(Tbunit ownerUnit) {
        this.ownerUnit = ownerUnit;
    }


    /**
     * @return the tags
     */
    public List<Tag> getTags() {
        return tags;
    }


    /**
     * @param tags the tags to set
     */
    public void setTags(List<Tag> tags) {
        this.tags = tags;
    }


    /**
     * @return the regimenIni
     */
    public Regimen getRegimenIni() {
        return regimenIni;
    }


    /**
     * @param regimenIni the regimenIni to set
     */
    public void setRegimenIni(Regimen regimenIni) {
        this.regimenIni = regimenIni;
    }

    /**
     * @return the evolution of the case
     */
    public String getCaseEvolution() {
        MedicalExamination lastExam = null;

        if(this.getExaminations() != null && this.getExaminations().size() > 1){//If there is only one examination, the field clinical evolution doesn't make sense
            lastExam = this.getExaminations().get(0); //the list is selected ordered by exam.event_date desc look at the annotation in TbCase

            if(lastExam != null){
                ClinicalEvolution eval = lastExam.getClinicalEvolution(); // for some old cases may be null AK 26/05/2012
                if (eval != null)
                    return lastExam.getClinicalEvolution().getKey();
            }

        }

        return "";
    }

    /**
     * @return the name of the sepervision unit
     */
    public String getSupervisionUnitName() {

        MedicalExamination lastExam = null;

        if(this.getExaminations() != null && this.getExaminations().size() > 1){//If there is only one examination, the field clinical evolution doesn't make sense
            lastExam = this.getExaminations().get(0); //the list is selected ordered by exam.event_date desc look at the annotation in TbCase
        }

        if(lastExam != null
                && lastExam.getSupervisedTreatment() != null
                && lastExam.getSupervisedTreatment().equals(YesNoType.YES)
                && lastExam.getSupervisionUnitName() != null){

            return lastExam.getSupervisionUnitName();
        }

        return "";
    }

    /* (non-Javadoc)
     * @see org.msh.tb.entities.Transactional#getLastTransaction()
     */
    @Override
    public TransactionLog getLastTransaction() {
        return lastTransaction;
    }

    /* (non-Javadoc)
     * @see org.msh.tb.entities.Transactional#setLastTransaction(org.msh.tb.entities.TransactionLog)
     */
    @Override
    public void setLastTransaction(TransactionLog transactionLog) {
        this.lastTransaction = transactionLog;
    }


    /**
     * @return the suspectRegistrationCode
     */
    public String getSuspectRegistrationCode() {
        return suspectRegistrationCode;
    }


    /**
     * @param suspectRegistrationCode the suspectRegistrationCode to set
     */
    public void setSuspectRegistrationCode(String suspectRegistrationCode) {
        this.suspectRegistrationCode = suspectRegistrationCode;
    }


    /**
     * @return the suspectClassification
     */
    public CaseClassification getSuspectClassification() {
        return suspectClassification;
    }


    /**
     * @param suspectClassification the suspectClassification to set
     */
    public void setSuspectClassification(CaseClassification suspectClassification) {
        this.suspectClassification = suspectClassification;
    }

    /**
     * @return the treatmentMonitoring
     */
    public List<TreatmentMonitoring> getTreatmentMonitoring() {
        return treatmentMonitoring;
    }

    /**
     * @param treatmentMonitoring the treatmentMonitoring to set
     */
    public void setTreatmentMonitoring(List<TreatmentMonitoring> treatmentMonitoring) {
        this.treatmentMonitoring = treatmentMonitoring;
    }

    public List<ExamXpert> getExamsXpert() {
        return examsXpert;
    }

    public void setExamsXpert(List<ExamXpert> examsXpert) {
        this.examsXpert = examsXpert;
    }

    public void setSecDrugsReceived(SecDrugsReceived secDrugsReceived) {this.secDrugsReceived = secDrugsReceived;}

    public SecDrugsReceived getSecDrugsReceived(){return this.secDrugsReceived;}

    public PatientType getPreviouslyTreatedType() {
        return previouslyTreatedType;
    }

    public void setPreviouslyTreatedType(PatientType previouslyTreatedType) {
        this.previouslyTreatedType = previouslyTreatedType;
    }

    public CaseDefinition getCaseDefinition() {
        return caseDefinition;
    }

    public void setCaseDefinition(CaseDefinition caseDefinition) {
        this.caseDefinition = caseDefinition;
    }

    public Date getLastBmuDateTbRegister() {
        return lastBmuDateTbRegister;
    }

    public void setLastBmuDateTbRegister(Date lastBmuDateTbRegister) {
        this.lastBmuDateTbRegister = lastBmuDateTbRegister;
    }

    public String getLastBmuTbRegistNumber() {
        return lastBmuTbRegistNumber;
    }

    public void setLastBmuTbRegistNumber(String lastBmuTbRegistNumber) {
        this.lastBmuTbRegistNumber = lastBmuTbRegistNumber;
    }

    public boolean isMovedSecondLineTreatment() {
        return movedSecondLineTreatment;
    }

    public void setMovedSecondLineTreatment(boolean movedSecondLineTreatment) {
        this.movedSecondLineTreatment = movedSecondLineTreatment;
    }

    public TreatmentCategory getTreatmentCategory() {
        return treatmentCategory;
    }

    public void setTreatmentCategory(TreatmentCategory treatmentCategory) {
        this.treatmentCategory = treatmentCategory;
    }

    public Boolean isInitialRegimenWithSecondLineDrugs() {
        return initialRegimenWithSecondLineDrugs;
    }

    public void setInitialRegimenWithSecondLineDrugs(Boolean initialRegimenWithSecondLineDrugs) {
        this.initialRegimenWithSecondLineDrugs = initialRegimenWithSecondLineDrugs;
    }

    public List<LaboratoryExam> getAllLaboratoryExams(){
        List<LaboratoryExam> list = new ArrayList<LaboratoryExam>();

        for (LaboratoryExam l : getExamsCulture())
            list.add(l);
        for (LaboratoryExam l : getExamsDST())
            list.add(l);
        for (LaboratoryExam l : getExamsMicroscopy())
            list.add(l);
        for (LaboratoryExam l : getExamsXpert())
            list.add(l);

        return list;
    }

    public List<PrevTBTreatment> getPrevTbTreats() {
        return prevTbTreats;
    }

    public void setPrevTbTreats(List<PrevTBTreatment> prevTbTreats) {
        this.prevTbTreats = prevTbTreats;
    }

    public HIVResult getHivResult() {
        return hivResult;
    }

    public void setHivResult(HIVResult hivResult) {
        this.hivResult = hivResult;
    }

    public Date getStartedARTdate() {
        return startedARTdate;
    }

    public void setStartedARTdate(Date startedARTdate) {
        this.startedARTdate = startedARTdate;
    }

    public Date getStartedCPTdate() {
        return startedCPTdate;
    }

    public void setStartedCPTdate(Date startedCPTdate) {
        this.startedCPTdate = startedCPTdate;
    }

    public RifResistance getRifResistance() {
        return rifResistance;
    }

    public void setRifResistance(RifResistance rifResistance) {
        this.rifResistance = rifResistance;
    }
}
