/*******************************************************************************
 * 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.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;

import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Act;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Invoice;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.RateIndex;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.GECAMedEntityBean;
import lu.tudor.santec.gecamed.core.utils.GECAMedUtils;

//***************************************************************************
//* Class Definition and Members                                            *
//***************************************************************************

/**
 * Entity Bean that maps the <b>patient.hospitalisation</b> table
 * represents one single hospitalisation for a patient
 *
 * @author Johannes Hermen johannes.hermen(at)tudor.lu
 *
 * @version
 * <br>$Log: Hospitalisation.java,v $
 * <br>Revision 1.18  2011-11-28 06:15:19  ferring
 * <br>Billing rules update for cardio: Cumulation in hospitalisation period
 * <br>
 * <br>Revision 1.17  2010-04-27 15:08:47  mack
 * <br>Removed an obsolete method
 * <br>
 * <br>Revision 1.16  2008-09-25 09:43:06  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.15  2008-01-15 15:11:43  hermen
 * <br>updated Javadoc and refactured code
 * <br>
 *
 */
@Entity
@Table(name = "hospitalisation", schema = "patient")
@javax.persistence.NamedQueries( {
		@NamedQuery(name = "getAllHospitalisations", query = "SELECT OBJECT(o) FROM Hospitalisation o"),
		@NamedQuery(name = "getHospitalisationByPassageId", query = "SELECT OBJECT(o) FROM Hospitalisation o WHERE o.pasID = :passageid"),
		@NamedQuery(name = Hospitalisation.QUERY_GET_HOSPITALISATIONS_FOR_PATIENT_ID,
				query = "SELECT OBJECT(o) FROM Hospitalisation o WHERE o.patientId = :patientId")
})
public class Hospitalisation extends GECAMedEntityBean implements Serializable {
	
	private static final long serialVersionUID = 1L;

	public static final String QUERY_GET_HOSPITALISATIONS_FOR_PATIENT_ID ="findAllHospitalisationByPatientId";
	
	
	private String pasID;

	private Integer patientId;
	
	private Boolean isWorkAccident;

	private String workAccidentNumber;

	private Date workAccidentDate;

	private Set<HospitalisationPeriod> hospitalisationPeriods;
	
	private static final long c_MillisPerDay = 24L * 60L * 60L * 1000L;
	
	// ***************************************************************************
	// * Constructor(s) *
	// ***************************************************************************

	// ***************************************************************************
	// * Getter and Setter Methods *
	// ***************************************************************************

	
	/**
	 * @return Returns the pasID.
	 */
	@Column(name = "pas_id")
	public String getPasID() {
		return pasID;
	}

	/**
	 * @param pasID
	 *            The pasID to set.
	 */
	public void setPasID(String pasID) {
		this.pasID = pasID;
	}

	/**
	 * @return Returns the workAccidentNumber.
	 */
	@Column(name = "accident_nr")
	public String getWorkAccidentNumber() {
		return workAccidentNumber;
	}

	/**
	 * @param workAccidentNumber
	 *            The workAccidentNumber to set.
	 */
	public void setWorkAccidentNumber(String workAccidentNumber) {
		this.workAccidentNumber = workAccidentNumber;
	}

	@Column(name ="patient_id")
	public Integer getPatientId() {
		return this.patientId;
	}
	
	public void setPatientId(Integer patientId) {
		this.patientId = patientId;
	}
	

	/**
	 * @return Returns the isWorkAccident.
	 */
	@Column(name = "isaccident")
	public Boolean getIsWorkAccident() {
		if (isWorkAccident == null) {
			isWorkAccident = false;
		}
		return isWorkAccident;
	}

	/**
	 * @param isWorkAccident
	 *            The isWorkAccident to set.
	 */
	public void setIsWorkAccident(Boolean isWorkAccident) {
		this.isWorkAccident = isWorkAccident;
	}

	/**
	 * @return Returns the workAccidentDate.
	 */
	@Column(name = "accident_date")
	public Date getWorkAccidentDate() {
		return workAccidentDate;
	}

	/**
	 * @param workAccidentDate
	 *            The workAccidentDate to set.
	 */
	public void setWorkAccidentDate(Date workAccidentDate) {
		this.workAccidentDate = workAccidentDate;
	}

	/**
	 * @return Returns the hospitalisationPeriods.
	 */
	@OneToMany(cascade = javax.persistence.CascadeType.ALL, fetch = javax.persistence.FetchType.EAGER)
	@JoinColumn(name = "hospitalisation_id")
	@OrderBy("startDate DESC, hospitalisationClass DESC")
	public Set<HospitalisationPeriod> getHospitalisationPeriods() {
		return hospitalisationPeriods;
	}

	/**
	 * @param hospitalisationPeriods
	 *            The hospitalisationPeriods to set.
	 */
	public void setHospitalisationPeriods(
			Set<HospitalisationPeriod> hospitalisationPeriods) {
		this.hospitalisationPeriods = hospitalisationPeriods;
	}

//---------------------------------------------------------------------------

@Transient
public Integer getLengthOfStay ()
	{
	Iterator <HospitalisationPeriod> 	l_PeriodsIterator;
	HospitalisationPeriod				l_Period;
	HospitalisationPeriod				l_FirstPeriod	= null;
	HospitalisationPeriod				l_LastPeriod	= null;
	Date								l_InDate		= null;
	Date								l_OutDate		= null;

	GregorianCalendar	l_InDay;					
	GregorianCalendar	l_OutDay;					
	Long				l_Interval;
	Long				l_LengthOfStay = 0L;
	
	if (this.hospitalisationPeriods != null)
		{
		l_PeriodsIterator = this.hospitalisationPeriods.iterator();
		while (l_PeriodsIterator.hasNext())
			{
			l_Period = l_PeriodsIterator.next();
			
			if (l_FirstPeriod == null) l_FirstPeriod = l_Period;
			else if (l_Period.getStartDate().before(l_FirstPeriod.getStartDate()))	
				l_FirstPeriod = l_Period;
				
			if (l_LastPeriod == null) l_LastPeriod = l_Period;
			else if (l_Period.getStartDate().after (l_LastPeriod.getStartDate()))
				{
				l_LastPeriod = l_Period;
				}
			}
		
		if ((l_FirstPeriod != null) && (l_LastPeriod != null))
			{
			l_InDate  = l_FirstPeriod.getStartDate ();
			l_OutDate = l_LastPeriod.getEndDate ();
		
			if (l_OutDate == null) l_OutDate = new Date ();
		
			l_InDay = new GregorianCalendar();
			l_InDay.setTime(l_InDate);
			l_InDay.set(Calendar.HOUR_OF_DAY, 0);
			l_InDay.set(Calendar.MINUTE, 0);
			l_InDay.set(Calendar.SECOND, 0);
			l_InDay.set(Calendar.MILLISECOND, 0);
		
			l_OutDay = new GregorianCalendar();
			l_OutDay.setTime(l_OutDate);
		
			l_Interval = l_OutDay.getTimeInMillis() - l_InDay.getTimeInMillis();
		
			l_LengthOfStay = (l_Interval / c_MillisPerDay);
			}
		}
	
	return l_LengthOfStay.intValue();
	}
	
//---------------------------------------------------------------------------

@Transient
public Date getStartDate ()
	{
	Iterator <HospitalisationPeriod> 	l_PeriodsIterator;
	HospitalisationPeriod				l_Period;
	Date	l_InDate	= null;

	if (this.hospitalisationPeriods != null)
		{
		l_PeriodsIterator = this.hospitalisationPeriods.iterator();
		while (l_PeriodsIterator.hasNext())
			{
			l_Period = l_PeriodsIterator.next();
			
			if (l_InDate == null) 
				l_InDate = l_Period.getStartDate();
			else if (l_Period.getStartDate().before(l_InDate))
				l_InDate = l_Period.getStartDate();		
			}
		}
	return l_InDate;
	}

//---------------------------------------------------------------------------

@Transient
public Date getEndDate ()
	{
	Iterator <HospitalisationPeriod> 	l_PeriodsIterator;
	HospitalisationPeriod				l_Period;
	Date	l_OutDate	= null;

	if (this.hospitalisationPeriods != null)
		{
		l_PeriodsIterator = this.hospitalisationPeriods.iterator();
		while (l_PeriodsIterator.hasNext())
			{
			l_Period = l_PeriodsIterator.next();
			
			if (l_OutDate == null) 
				l_OutDate = l_Period.getEndDate();
			else if (l_Period.getEndDate().after(l_OutDate))
				l_OutDate = l_Period.getEndDate();		
			}
		}
	return l_OutDate;
	}


@Transient
public static void createHospitalisationForInvoice (Invoice p_Invoice)
	{
	RateIndex 				l_Index;
	HospitalisationPeriod 	l_Period;
	Hospitalisation 		l_Hospitalisation;
	boolean 				l_NewPeriod;
	Date 					l_CurrentDay;
	Calendar 				l_NextDay;
	Date 					l_LastDay;
	
	TreeMap<Date, Act> 				l_Acts;
	TreeSet<HospitalisationPeriod> 	l_Periods;
	
	if (p_Invoice.isAmbulatory()
			|| p_Invoice.getHospitalisation() != null)
		return;
	
	l_Index = RateIndex.loadRateIndexByLabel("G_4");
	l_Acts 	= new TreeMap<Date, Act>();
	
	for (Act l_Act : p_Invoice.getActs())
		{
		if (l_Index.includesAct(l_Act))
			l_Acts.put(GECAMedUtils.stripTime(l_Act.getPerformedDate()), l_Act);
		}
	
	if (l_Acts.isEmpty())
		// no hospitalization acts available
		return;
	
	l_Periods = new TreeSet<HospitalisationPeriod>();
	l_LastDay = null;
	
	// prepare the hospitalisation
	l_Hospitalisation = new Hospitalisation();
	l_Hospitalisation.setPatientId(p_Invoice.getPatient().getId());
	l_Hospitalisation.setWorkAccidentNumber(p_Invoice.getAccidentNumber());
	l_Hospitalisation.setWorkAccidentDate(p_Invoice.getAccidentDate());
	l_Hospitalisation.setIsWorkAccident(p_Invoice.isAccident());
	l_Hospitalisation.setHospitalisationPeriods(l_Periods);
	
	// prepare the first hospitalisation period, as there must be at least one
	l_Period = new HospitalisationPeriod();
	l_Period.setHospitalisationClass(p_Invoice.getHospitalisationClass());
	l_Period.setHospitalisation(l_Hospitalisation);
	
	for (Act l_Act : l_Acts.values())
		{
		l_CurrentDay 	= GECAMedUtils.stripTime(l_Act.getPerformedDate());
		
		if (l_LastDay == null)
			{
			l_Period.setStartDate(l_CurrentDay);
			l_NewPeriod = false;
			}
		else // if (l_LastDay != null)
			{
			l_NextDay 	= new GregorianCalendar();
			l_NextDay.setTime(l_LastDay);
			l_NextDay.add(Calendar.DAY_OF_YEAR, 1);
			
			l_NewPeriod = l_CurrentDay.after(l_NextDay.getTime());
			}
		
		if (l_NewPeriod)
			{
			l_Period.setEndDate(l_LastDay);
			l_Periods.add(l_Period);
			l_Period = new HospitalisationPeriod();
			l_Period.setHospitalisationClass(p_Invoice.getHospitalisationClass());
			l_Period.setHospitalisation(l_Hospitalisation);
			l_Period.setStartDate(l_CurrentDay);
			}
		
		l_LastDay = l_CurrentDay;
		}
	
	l_Period.setEndDate(l_LastDay);
	l_Periods.add(l_Period);
	
	
	p_Invoice.setHospitalisation(l_Hospitalisation);
	}
	
//***************************************************************************
//* End of Class															*
//***************************************************************************
}
