/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.patient.ejb.entity.beans;

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import lu.tudor.santec.gecamed.core.ejb.entity.beans.GECAMedEntityBean;

/**
 * Entity Bean that maps the <b>patient.incidents</b> table
 * represents one single incident for a patient

 *
 * @version
 * <br>$Log: Incident.java,v $
 * <br>Revision 1.22  2013-11-15 08:46:42  ferring
 * <br>deleting empty incidents in delete statement instead of getting them via select and removing them one by one
 * <br>
 * <br>Revision 1.21  2013-02-14 08:15:18  ferring
 * <br>incident selection added to new letters and improved for files
 * <br>
 * <br>Revision 1.20  2013-02-13 14:43:35  gbosch
 * <br>Provisionary fix for deployment problem related to MainFrame class.
 * <br>
 * <br>Revision 1.19  2013-02-13 14:01:17  ferring
 * <br>provides now a kind of second toString method
 * <br>
 * <br>Revision 1.18  2013-02-08 15:27:16  ferring
 * <br>Option added for files and letters to attach them to another incident
 * <br>
 * <br>Revision 1.17  2012-01-24 14:38:52  ferring
 * <br>Errors and warnings of Jenkins build corrected
 * <br>
 * <br>Revision 1.16  2012-01-24 10:22:27  ferring
 * <br>Native Queries to Named Queries
 * <br>
 * <br>Revision 1.15.2.1  2012-01-20 09:13:53  ferring
 * <br>BRANCHED VERSION
 * <br>
 * <br>Revision 1.15  2010-09-30 07:02:41  ferring
 * <br>Method added to get an incident between 2 dates
 * <br>
 * <br>Revision 1.14  2010-09-09 15:57:39  troth
 * <br>1. Now all S.O.A.P entries can be deleted
 * <br>2. Now measurements can be deleted
 * <br>3. Bug fix that create a empty entry form type prescription when saving the consultation
 * <br>
 * <br>Revision 1.13  2010-05-26 16:33:34  troth
 * <br>bugfix - change the way to get a new and create a incident. rename the method getRecentIncident() in class PatientPanel to getCurrentIncident()
 * <br>
 * <br>Revision 1.12  2009-02-27 15:25:56  hermen
 * <br>added button to create an empty incident for a patient visit
 * <br>
 * <br>Revision 1.11  2009-02-25 13:26:09  hermen
 * <br>added siteID to incidents and invoices
 * <br>
 * <br>Revision 1.10  2008-09-25 09:43:06  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.9  2008-07-21 15:31:24  mack
 * <br>Removed erronous import
 * <br>
 * <br>Revision 1.8  2008-07-21 14:06:03  hermen
 * <br>implemented toString
 * <br>
 * <br>Revision 1.7  2008-05-27 14:13:08  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.6  2008-03-11 17:17:11  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.5  2008-01-17 09:19:59  hermen
 * <br>updated Javadoc and refactured code
 * <br>
 *
 */
@javax.persistence.NamedQueries
({
@NamedQuery(name = Incident.GET_INCIDENTS_BY_PATIENT_ID,query = "SELECT OBJECT(o) FROM Incident o WHERE o.patientId = :patientID ORDER BY incident_date DESC"),
@NamedQuery(name = Incident.GET_INCIDENT_BY_ID,query 		 = "SELECT OBJECT(o) FROM Incident o WHERE o.id = :id "),
@NamedQuery(name = Incident.DELETE_NULL_INCIDENT, query		 = "SELECT OBJECT(o) FROM Incident o "
															+ "WHERE o.id NOT IN ( "
																+ "SELECT e.incidentId FROM IncidentEntry e " 
															+ ") "
															+ "AND o.isAccident = false"),
@NamedQuery(name = Incident.GET_INCIDENTS_NEWER_THAN_BY_PATIENTID_AND_PHYSICIANID,query  = "SELECT OBJECT(o) FROM Incident o " 
															+ "WHERE o.patientId = :patientID  " 
															+ "AND o.physicianId = :physicianId  " 
															+ "AND o.incidentDate >= :newerThan " 
															+ "AND o.incidentDate <= :olderThan " 
															+ "ORDER BY o.incidentDate DESC"),
@NamedQuery(name = Incident.DELETE_NULL_INCIDENTS_OF_PATIENT, query = 
//															  "SELECT OBJECT(o) FROM Incident o "
															  "DELETE Incident o "
															+ "WHERE o.patientId = :patientId "
															+ "AND o.isAccident = false "
															+ "AND o.incidentEntries IS EMPTY "
															+ "AND o.id NOT IN (select incidentId from Prescription)"),

@NamedQuery(name = Incident.GET_ACCIDENTS_FOR_PATIENT, query = "SELECT OBJECT(o) FROM Incident o "
															+ "WHERE o.patientId = :patientId "
															+ "AND o.isAccident = 'true' "
															+ "AND o.parentAccidentIncidentId = null " 
															+ "ORDER BY o.incidentDate DESC"),
@NamedQuery(name = Incident.GET_CHILD_ACCIDENT_INCIDENT_AMOUNT, query = "SELECT COUNT(o.id) FROM Incident o "
															+ "WHERE o.parentAccidentIncidentId = :incId"),
@NamedQuery(name = Incident.GET_CHILD_ACCIDENT_INCIDENT_AMOUNT, query = "SELECT COUNT(o.id) FROM Incident o "
															+ "WHERE o.parentAccidentIncidentId = :incId"),
@NamedQuery(name = Incident.GET_INCIDENTS_BY_PARENT, query = "SELECT OBJECT(o) FROM Incident o "
															+ "WHERE o.parentAccidentIncidentId = :parentId"),
															//+ " AND o.id != :incidentId"),
@NamedQuery(name = Incident.GET_INCIDENTS_BY_ID_AND_PARENT, query = "SELECT OBJECT(o) FROM Incident o "
															+ "WHERE o.parentAccidentIncidentId = :incidentId "
															+ "AND o.id != :incidentId")
//@NamedQuery(name = Incident.GET_INCIDENTS_WITH_CONSULTATIONS, query = "SELECT COUNT(o.id) FROM Incident o "
//															+ "WHERE o.consultations.size > 0"),
//@NamedQuery(name = Incident.GET_INCIDENTS_WITH_CONSULTATIONS_FOR_PATIENT, query = "SELECT o.id FROM Incident o "
//															+ "WHERE o.patientId = :patientId "
//															+ "AND o.consultations.size > 0"),
})


@Entity
@Table(name = "incidents", schema = "patient")
public class Incident extends GECAMedEntityBean implements Serializable {

	
	/**
	 *
	 */
	private static final long serialVersionUID = 1L;

	public static final String GET_INCIDENTS_NEWER_THAN_BY_PATIENTID_AND_PHYSICIANID = "getIncidentNewerThanByPatientIDAndPhysicianId";
	public static final String DELETE_NULL_INCIDENT 						= "deleteNullIncident";
	public static final String GET_INCIDENTS_BY_PATIENT_ID 					= "getIncidentsByPatientID";
	public static final String GET_INCIDENT_BY_ID 							= "getIncidentByID";
	public static final String GET_INCIDENTS_BY_PARENT 						= "getIncidentsByParent";
	public static final String GET_INCIDENTS_BY_ID_AND_PARENT 				= "getIncidentsByIdAndParent";
	public static final String DELETE_NULL_INCIDENTS_OF_PATIENT				= "deleteNullIncidentsOfPatient";
//	public static final String GET_INCIDENTS_WITH_CONSULTATIONS 			= "getIncidentsWithConsultations";
//	public static final String GET_INCIDENTS_WITH_CONSULTATIONS_FOR_PATIENT = "getIncident";
	
	public static final String GET_ACCIDENTS_FOR_PATIENT 			= "getAccidentsForPatient";
	public static final String GET_CHILD_ACCIDENT_INCIDENT_AMOUNT 	= "getChildAccidentIncidentAmount";
	// Fields


//	private Collection<Consultation> consultations = new ArrayList<Consultation>(0);
	private Date incidentDate;
	private Date created;
	private int createdBy;
	private Date modified;
	private Integer modifiedBy;
	private boolean isVisit;
	private Integer patientId;
	private Integer physicianId;

	private String accidentNr;
	private Date accidentDate;
	private Boolean isAccident = false;
	private Integer parentAccidentIncidentId;
	private Integer siteId;

	private List<IncidentEntry> incidentEntries;
	
	private Set<Incident> children = new HashSet<Incident>(0);

	private Set<MeasurementValue> measurementValues = new HashSet<MeasurementValue>(0);

	private Set<Incident> parents = new HashSet<Incident>(0);

	// Constructors

	/** default constructor */
	public Incident() {

	}
	
	public Incident(Integer patientId, Integer physicianId) {
		/* ================================================== */
		this.patientId = patientId;
		this.physicianId = physicianId;
		/* ================================================== */
	}
	

	// Property accessors
//	@Deprecated
//	@OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
//	@JoinColumn(name = "incident_id")
//	public Collection<Consultation> getConsultations() {
//		return this.consultations;
//	}
//
//	@Deprecated
//	public void setConsultations(Collection<Consultation> consultations) {
//		this.consultations = consultations;
//	}
	
	/**
	 * @return
	 */
	@OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
	@JoinColumn(name = "incident_id")
	public List<IncidentEntry> getIncidentEntries() {
		/* ================================================== */
		return this.incidentEntries;
		/* ================================================== */
	}
	
	
	/**
	 * @param entries
	 */
	public void setIncidentEntries(List<IncidentEntry> entries) {
		/* ================================================== */
		this.incidentEntries = entries;
		/* ================================================== */
	}
	
	
	

	@Column(name = "incident_date", unique = false, nullable = false, insertable = true, updatable = true, length = 8)
	public Date getIncidentDate() {
		return this.incidentDate;
	}

	public void setIncidentDate(Date incidentDate) {
		this.incidentDate = incidentDate;
	}

	/**
	 * @return the created
	 */
	@Column(name="created", nullable = false)
	public Date getCreated() {
		return created;
	}

	/**
	 * @param created the created to set
	 */
	public void setCreated(Date created) {
		this.created = created;
	}

	/**
	 * @return The GECAMed USER who created this incident
	 */
	@Column(name = "created_by", unique = false, nullable = false, insertable = true, updatable = true)
	public int getCreatedBy() {
		return this.createdBy;
	}

	/**
	 * @param createdBy The GECAMed USER who created this incident
	 */
	public void setCreatedBy(int createdBy) {
		this.createdBy = createdBy;
	}

	@Column(name = "modified", unique = false, nullable = true, insertable = true, updatable = true, length = 8)
	public Date getModified() {
		return this.modified;
	}

	/**
	 * @param modified The GECAMed USER who modified this incident
	 */
	public void setModified(Date modified) {
		this.modified = modified;
	}

	/**
	 * @return The GECAMed USER who modified this incident
	 */
	@Column(name = "modified_by", unique = false, nullable = true, insertable = true, updatable = true)
	public Integer getModifiedBy() {
		return this.modifiedBy;
	}

	/**
	 * @param modifiedBy The GECAMed user who modified this incident
	 */
	public void setModifiedBy(Integer modifiedBy) {
		this.modifiedBy = modifiedBy;
	}

	@Column(name = "is_visit", unique = false, nullable = false, insertable = true, updatable = true)
	public Boolean getIsVisit() {
		return this.isVisit;
	}

	public void setIsVisit(Boolean isVisit) {
		this.isVisit = isVisit;
	}
//	@OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY, mappedBy = "incidentsByChildIncidentId")
//	public Set<IncidentRelation> getIncidentRelationsesForChildIncidentId() {
//		return this.incidentRelationsesForChildIncidentId;
//	}
//
//	public void setIncidentRelationsesForChildIncidentId(
//			Set<IncidentRelation> incidentRelationsesForChildIncidentId) {
//		this.incidentRelationsesForChildIncidentId = incidentRelationsesForChildIncidentId;
//	}
	@OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
	@JoinColumn(name="incident_id")
	public Set<MeasurementValue> getMeasurementValues() {
		return this.measurementValues;
	}

	public void setMeasurementValues(Set<MeasurementValue> mValues) {
		this.measurementValues = mValues;
	}
//	@OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY, mappedBy = "incidentsByParentIncidentId")
//	public Set<IncidentRelation> getIncidentRelationsesForParentIncidentId() {
//		return this.incidentRelationsesForParentIncidentId;
//	}
//
//	public void setIncidentRelationsesForParentIncidentId(
//			Set<IncidentRelation> incidentRelationsesForParentIncidentId) {
//		this.incidentRelationsesForParentIncidentId = incidentRelationsesForParentIncidentId;
//	}

	/**
	 * @return the patientId
	 */
	@Column(name = "patient_id")
	public Integer getPatientId() {
		return patientId;
	}

	/**
	 * @param patientId the patientId to set
	 */
	public void setPatientId(Integer patientId) {
		this.patientId = patientId;
	}

	/**
	 * @return the physicianId
	 */
	@Column(name="physician_id")
	public Integer getPhysicianId() {
		return physicianId;
	}

	/**
	 * @param physicianId the physicianId to set
	 */
	public void setPhysicianId(Integer physicianId) {
		this.physicianId = physicianId;
	}


	@Column(name = "accident_nr", unique = false, nullable = true, insertable = true, updatable = true, length = 100)
	public String getAccidentNr() {
		return this.accidentNr;
	}

	public void setAccidentNr(String accidentNr) {
		this.accidentNr = accidentNr;
		/* ------------------------------------------------------ */
		if (this.accidentDate != null
				|| (this.accidentNr != null
					&&	!"".equals(this.accidentNr))) {
			/* ------------------------------------------------------ */
			this.setIsAccident(true);
			/* ------------------------------------------------------ */
		} else
			this.setIsAccident(false);
	}


	@Temporal(TemporalType.DATE)
	@Column(name = "accident_date", unique = false, nullable = true, insertable = true, updatable = true, length = 4)
	public Date getAccidentDate() {
		return this.accidentDate;
	}

	public void setAccidentDate(Date accidentDate) {
		this.accidentDate = accidentDate;
		/* ------------------------------------------------------ */
		if (this.accidentDate != null
				|| (this.accidentNr != null
					&&	!"".equals(this.accidentNr))) {
			/* ------------------------------------------------------ */
			this.setIsAccident(true);
			/* ------------------------------------------------------ */
		} else
			this.setIsAccident(false);
	}

	@Column(name = "is_accident", unique = false, nullable = true, insertable = true, updatable = true)
	public Boolean getIsAccident() {
		return this.isAccident;
	}

	public void setIsAccident(Boolean isAccident) {
		this.isAccident = isAccident;
	}


	@OneToMany(fetch=FetchType.LAZY)
	@JoinTable(name = "incident_relations", schema="patient",
			joinColumns = {@JoinColumn(name="child_incident_id")},
			inverseJoinColumns = {@JoinColumn(name="parent_incident_id")})
	public Set<Incident> getChildren() {
		/* ================================================== */
		return this.children;
		/* ================================================== */
	}

	public void setChildren(Set<Incident> children) {
		/* ================================================== */
		this.children = children;
		/* ================================================== */
	}

	@OneToMany(fetch=FetchType.LAZY)
	@JoinTable(name = "incident_relations", schema="patient",
			joinColumns = {@JoinColumn(name="parent_incident_id")},
			inverseJoinColumns = {@JoinColumn(name="child_incident_id")})
	public Set<Incident> getParents() {
		/* ================================================== */
		return this.parents;
		/* ================================================== */
	}

	public void setParents(Set<Incident> parents) {
		/* ================================================== */
		this.parents = parents;
		/* ================================================== */
	}

	/**
	 * @return the parentAccidentIncidentId
	 */
	@Column(name="parent_accident_incident_id")
	public Integer getParentAccidentIncidentId() {
		return parentAccidentIncidentId;
	}

	/**
	 * @param parentAccidentIncidentId the parentAccidentIncidentId to set
	 */
	public void setParentAccidentIncidentId(Integer parentAccidentIncidentId) {
		this.parentAccidentIncidentId = parentAccidentIncidentId;
	}
	
	/**
	 * @return the siteId
	 */
	@Column(name="site_id")
	public Integer getSiteId() {
		return siteId;
	}

	/**
	 * @param siteId
	 */
	public void setSiteId(Integer siteId) {
		this.siteId = siteId;
	}
	
	
	/**
	 * @param typeId
	 * @return
	 */
	@Transient
	public IncidentEntry getEntry(String typeName) {
		/* ================================================== */
		if (this.incidentEntries == null || typeName == null)
			return null;
		/* ------------------------------------------------------- */
		for (IncidentEntry e : incidentEntries) {
			/* ------------------------------------------------------- */
//			try {
//				if (typeName.equals(e.getProperty(IncidentEntry.ENTRY_NAME)))
//					return e;
//			} catch (Exception e1) {
//			}
			if (e.getEntryType() != null && typeName.equals(e.getEntryType().getName()))
				return e;
			/* ------------------------------------------------------- */
		}
		return null;
		/* ================================================== */
	}
//	@Transient
//	public IncidentEntry getEntry(Integer typeId) {
//		/* ================================================== */
//		if (this.incidentEntries == null || typeId == null)
//			return null;
//		/* ------------------------------------------------------- */
//		for (IncidentEntry e : incidentEntries) {
//			/* ------------------------------------------------------- */
//			if (typeId.equals(e.getEntryTypeId()))
//				return e;
//			/* ------------------------------------------------------- */
//		}
//		return null;
//		/* ================================================== */
//	}
	
	public String toString() {
	    StringBuffer sb = new StringBuffer();
	    sb.append("Date: " + getIncidentDate() + " PatientID:" + getPatientId() + " Accident:" + getAccidentDate() + " " + getAccidentNr() + "\n");
	    if (measurementValues != null) {
		sb.append("measurements: " + measurementValues.size()+ "\n" );
        	    for (MeasurementValue value : measurementValues) {
        		sb.append("\t" + value.toString() + "\n");
        	    }
	    }
	    if (incidentEntries != null) {
		sb.append("entries:" + incidentEntries.size() + "\n");
        	    for (IncidentEntry entry : incidentEntries) {
        		sb.append("\t" + entry.toString() + "\n");
        	    }
	    }
	    return sb.toString();
	}
}
