/*******************************************************************************
 * 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.billing.ejb.entity.beans;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.regex.Pattern;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
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.utils.InvoiceModifiedStatus;
import lu.tudor.santec.gecamed.billing.utils.InvoiceWorkflow;
import lu.tudor.santec.gecamed.billing.utils.rules.ActsChangedListener;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.GECAMedEntityBean;
import lu.tudor.santec.gecamed.core.utils.GECAMedUtils;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Hospitalisation;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.HospitalisationClass;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Insurance;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser;

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

/**
 * The Invoice class is the center piece of the billing module. It provides a 
 * record of the services a patient has received and for which he or a third party
 * payer will have to make a payment.
 * @author nico.mack@tudor.lu
 */

@Entity
@Table(name = "invoice", schema = "billing")
@javax.persistence.NamedQueries({
		@NamedQuery(name = Invoice.c_InvoiceById, query = "SELECT OBJECT(o) FROM Invoice o WHERE o.id = :id"),
		@NamedQuery(name = Invoice.c_InvoicesByPatient, query = "SELECT OBJECT(o) FROM Invoice o WHERE o.patient = :patient ORDER BY o.invoiceDate"),
		@NamedQuery(name = Invoice.c_InvoicesByPatientAndPhysician, query = "SELECT OBJECT(o) FROM Invoice o WHERE o.patient = :patient AND o.physician = :physician ORDER BY o.invoiceDate"),
		@NamedQuery(name = Invoice.c_InvoicesByPatientAndPhysicianOfToday, query = "SELECT OBJECT(o) FROM Invoice o WHERE o.patient = :patient AND o.physician = :physician AND o.invoiceDate = :date"),
		@NamedQuery(name = Invoice.c_InvoicesByActInTimeSpan, query = "SELECT OBJECT(i) FROM Invoice i, Act a WHERE a.invoiceId = i.id AND a.code = :code " +
				"AND i.patient = :patient AND i.physician = :physician AND i.invoiceDate >= :fromDate " +
				"AND i.invoiceDate <= :toDate AND i.id <> :exclude ORDER BY i.invoiceDate DESC"),
		@NamedQuery(name = Invoice.c_InvoicesByHospitalisation, query = "SELECT OBJECT(o) FROM Invoice o WHERE o.hospitalisation = :hospitalisation ORDER BY o.invoiceDate"),
		@NamedQuery(name = Invoice.c_InvoicesByAccident, query = "SELECT OBJECT(o) FROM Invoice o WHERE o.patient = :patient AND o.accidentNumber = :accidentNumber AND o.accidentDate = :accidentDate ORDER BY o.invoiceDate"),
		@NamedQuery(name = Invoice.c_InvoicesByAccidentDate, query = "SELECT OBJECT(o) FROM Invoice o WHERE o.patient = :patient AND o.accidentDate = :accidentDate ORDER BY o.invoiceDate"),
		@NamedQuery(name = Invoice.c_OpenInvoicesByHospitalisation, query = "SELECT OBJECT(o) FROM Invoice o WHERE o.hospitalisation = :hospitalisation AND o.state <= " + InvoiceWorkflow.c_VerifiedState + " ORDER BY o.invoiceDate"),
		@NamedQuery(name = Invoice.c_InvoicesByStatement, query = "SELECT OBJECT(o) FROM Invoice o WHERE o.statement = :statement ORDER BY o.patient.surName ASC, o.patient.firstName ASC"),
		@NamedQuery(name = Invoice.c_InvoiceCountByStatement, query = "SELECT COUNT(o)  FROM Invoice o WHERE o.statement = :statement"),
		@NamedQuery(name = Invoice.c_SettledInvoiceCountByStatement, query = "SELECT COUNT(o)  FROM Invoice o WHERE o.statement = :statement AND o.balance = 0d"),
		@NamedQuery(name = Invoice.c_InvoiceCountBySettlement, query = "SELECT COUNT(o)  FROM Invoice o WHERE o.settlement = :settlement"),
		@NamedQuery(name = Invoice.c_InvoicesEligibleForThirdParty, query = "SELECT OBJECT(o) FROM Invoice o WHERE o.hospitalisationClass <> :ambulatory" +
				" AND o.state <= " + InvoiceWorkflow.c_VerifiedState +
				" AND (o.thirdPartyPayer IS NULL OR o.thirdPartyPayer.id = 0) " +
				" AND o.invoiceDate = :fourDaysAgo")
})
public class Invoice extends GECAMedEntityBean implements Serializable
{
	/* ======================================== */
	// CONSTANTS
	/* ======================================== */
	
	private static final long								serialVersionUID						= 1L;
	
	
	/* ======================================== */
	// MEMBERS
	/* ======================================== */
	
	/** the logger Object for this class */
//	private static Logger									logger									= Logger.getLogger(Invoice.class.getName());
	
	private Patient											m_Patient;
	private Physician										m_Physician;
	private Hospitalisation									m_Hospitalisation;
	private HospitalisationClass							m_HospitalisationClass;
	private Insurance										m_HealthInsurance;
	private Insurance										m_ThirdPartyPayer;
	private GecamedUser										m_Closer;
	private Date											m_ClosureDate;
	private GecamedUser										m_Modifier;
	private Date											m_ModificationDate;
//	private String					m_InvoiceNumber;
	private Boolean											m_FirstClassRequired;
	private Date											m_InvoiceDate;
	private Date											m_DueDate;
	private Date											m_PrintDate;
	private Integer											m_State;
	private Integer											m_OldState;
	private String											m_AccidentNumber;
	private Date											m_AccidentDate;
	private Integer											m_Reminders;
	private Date											m_ReminderDate;
	private Double											m_Amount;
	private Double											m_Payment;
	private Double											m_Deduction;
	private Double											m_Balance;
	private Double											m_Majoration;
	private Settlement										m_Settlement;
	private Date											m_SettlementDate;
	private Statement										m_Statement;
	private Integer											m_SiteId;
	
	private Set<Act>										m_Acts;
	private Set<Memo>										m_Memos;
	
	private boolean											m_UseShortNumbers						= false;
	private boolean											m_UseLeadingZeros						= true;
	
	private String											m_FormatedDate							= "";
	private String											m_FormatedReminderDate					= "";
	
	private String											m_MedTrans								= null;
	
//	private boolean											m_RoundToSingleDecimal;
	
	private transient InvoiceModifiedStatus					modifiedStatus;
	
	private transient Collection<ActsChangedListener>		actsChangedListener;


	private String ruleLog;
	
	private static transient Integer						m_ExpiryPeriod							= Integer.valueOf(30);
	
	private static transient Hashtable<String, Insurance>	m_Insurances						= null;
	
//	private static transient Date							m_Today									= null;
	
//***************************************************************************
//* Class Constants                                                         *
//***************************************************************************
	
	public static final transient boolean					c_ShortFormat							= true;
	public static final transient boolean					c_LongFormat							= false;
	
	public static final transient int						c_NoCommonPhysician						= -1;
	
	public static final transient Double					c_DefaultMajoration						= new Double(1.0);
	
	public static final transient String					c_InvoiceById							= "getInvoiceById";
	public static final transient String					c_InvoicesByPatient						= "getInvoicesByPatient";
	public static final transient String					c_InvoicesByPatientAndPhysician			= "getInvoicesByPatientAndPhysician";
	public static final transient String					c_InvoicesByPatientAndPhysicianOfToday	= "getInvoicesByPatientAndPhysicianOfToday";
	public static final transient String					c_InvoicesByActInTimeSpan				= "getInvoicesByActInTimeSpan";
	public static final transient String					c_InvoicesByHospitalisation				= "getInvoicesByHospitalisation";
	public static final transient String					c_InvoicesByAccident					= "getInvoicesByAccident";
	public static final transient String					c_InvoicesByAccidentDate				= "getInvoicesByAccidentDate";
	public static final transient String					c_OpenInvoicesByHospitalisation			= "getOpenInvoicesByHospitalisation";
	public static final transient String					c_InvoicesByStatement					= "getInvoicesByStatement";
	public static final transient String					c_InvoiceCountByStatement				= "getInvoiceCountByStatement";
	public static final transient String					c_SettledInvoiceCountByStatement		= "getSettledInvoiceCountByStatement";
	public static final transient String					c_InvoiceCountBySettlement				= "getInvoiceCountBySettlement";
	public static final transient String					c_InvoicesEligibleForThirdParty			= "getInvoicesEligibleForThirdParty";
	
	public static final transient String					c_IdParameter							= "id";
	public static final transient String					c_PatientParameter						= "patient";
	public static final transient String					c_PhysicianParameter					= "physician";
	public static final transient String					c_HospitalisationParameter				= "hospitalisation";
	public static final transient String					c_AccidentNumberParameter				= "accidentNumber";
	public static final transient String					c_AccidentDateParameter					= "accidentDate";
	public static final transient String					c_StatementParameter					= "statement";
	public static final transient String					c_SettlementParameter					= "settlement";
	public static final transient String					c_AmbulatoryParameter					= "ambulatory";
	public static final transient String					c_FourDaysAgoParameter					= "fourDaysAgo";
	
	
	//=== PRIVATE ===========================================================
	
	private static final transient DecimalFormat			m_InvoiceIDFormat						= new DecimalFormat("0000000");
	private static final transient DecimalFormat			m_PatientIDFormat						= new DecimalFormat("000000");
	private static final transient DecimalFormat			m_PhysicianIDFormat						= new DecimalFormat("00");
	
	private static final transient Integer					c_Zero									= Integer.valueOf(0);
	
	public static Pattern									c_InvoiceNumberPattern					= Pattern.compile("^(\\d{2})\\/(\\d{6})-(\\d{7})$", Pattern.CASE_INSENSITIVE);
	
	
//***************************************************************************
//* Constructor(s)                                                          *
//***************************************************************************	
	
	public Invoice ()
	{
		m_FirstClassRequired = Boolean.valueOf(false);
		m_State = Integer.valueOf(0);
		m_OldState = Integer.valueOf(0);
		m_Reminders = Integer.valueOf(0);
		m_Amount = new Double(0);
		m_Payment = new Double(0);
		m_Deduction = new Double(0);
		m_Balance = new Double(0);
		m_Majoration = Invoice.c_DefaultMajoration;
		
//		m_RoundToSingleDecimal = true;
		
		m_SiteId = null;
	}
	
	
//---------------------------------------------------------------------------
//***************************************************************************
//* Primitives                                       						*
//***************************************************************************
//---------------------------------------------------------------------------
	/**
	 * The Invoice class defines a static Lookup table, intended to hold the
	 * all the insurances for invoices. The
	 * static setInsurances method should MUST be called at least once to set
	 * this lookup table. 
	 * @param p_Insurances specifies all the defined third party paying
	 * insurances.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public static void setInsurances (Collection<Insurance> p_Insurances)
	{
		Iterator<Insurance> l_PayerIterator;
		Insurance l_Payer;
		
		if (p_Insurances != null)
		{
			m_Insurances = new Hashtable<String, Insurance>();
			l_PayerIterator = p_Insurances.iterator();
			while (l_PayerIterator.hasNext())
			{
				l_Payer = l_PayerIterator.next();
				m_Insurances.put(l_Payer.getAcronym(), l_Payer);
			}
		}
		else
			m_Insurances = null;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Method allows to check whether insurances have already been set by calling
	 * setInsurances() method or not.
	 * @return <code>true</code> if insurances have NOT been set yet, 
	 * <code>false</code> if they have already been set.
	 * @see #setInsurances (Collection <Insurance>)
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public static Boolean insurancesNotSet ()
	{
		return (m_Insurances == null);
	}
	
	/**
	 * we need to keep this one as used in printing templates....
	 * @return
	 */
	@Transient
	public static Boolean thirdPartyPayersNotSet ()
	{
		return (m_Insurances == null);
	}
	
	
////---------------------------------------------------------------------------
//	/**
//	 * Rounds the specified value either to single or dual decimals. In single
//	 * decimal mode, the method rounds a value according to the rules stipulated 
//	 * by Article 4 of UCM Rules. This article states that monetary values are to 
//	 * be rounded to one decimal position. Value will be rounded to next higher value 
//	 * if second decimal is greater or equal than 5. Otherwise value will be round 
//	 * to next lower value. For instance a value of 1.15 will be rounded to 1.20 
//	 * whereas a value of 1.14 will be rounded to 1.10.
//	 * Dual decimal mode will only be used for rates not being managed by the UCM.
//	 * Value will be rounded to next higher value if third decimal is greater or equal 
//	 * than 5. 
//	 * @param: p_Value specifies the value to be rounded
//	 * @param: p_SingleDecimal specifies single decimal rounding mode or dual decimal
//	 * rounding mode should be used. Specify <code>true</code> from single decimal
//	 * mode, <code>false</code> otherwise.
//	 * @return: returns the rounded value.
//	 */
////---------------------------------------------------------------------------
//	
//	@Transient
//	private double round (double p_Value, boolean p_SingleDecimal)
//	{
//		int l_Decimator;
//		long l_Rounder;
//		
//		
//		l_Decimator = p_SingleDecimal ? 10 : 100;
//		
//		l_Rounder = (long) ((p_Value * l_Decimator) + (p_Value < 0 ? (-0.5) : 0.5));
//		p_Value = ((double) l_Rounder / l_Decimator);
//		
//		return p_Value;
//	}
//	
//	
////---------------------------------------------------------------------------
//	/**
//	 * Rounds the specified value either to single or dual decimals.
//	 * @param: p_Value specifies the value to be rounded
//	 * @return: returns the rounded value.
//	 * @see round (double p_Value, boolean p_SingleDecimal)
//	 */
////---------------------------------------------------------------------------
//	
//	@Transient
//	private double round (double p_Value)
//	{
//		return this.round(p_Value, m_RoundToSingleDecimal);
//	}
	
	
//---------------------------------------------------------------------------
	/**
	 * the formatInvoiceNumber formates the invoice number either as a short
	 * number or as a long number. Short format only uses invoice ID to generate
	 * number whereas long format includes ID of physician and patient as well.
	 * Default short format is : <code>xxxxxxx</code> where x stands for digits of invoice id.
	 * Default long format is : <code>zz/yyyyyy-xxxxxxx</code> where z stands for physician id,
	 * y stands for digits of patient id and x stands for digits of invoice id.
	 * In both cases, unused position will be returned as 0.
	 * @param p_InvoiceId specifies the ID of the invoice.
	 * @param p_PhysicianId specifies the ID of the physician.
	 * @param p_PatientId specifies the ID of the patient.
	 * @param p_Short specifies whether short format should be used for invoice
	 * number or long format. Specify <code>true</code> for short format, <code>
	 * false</code> for long format.
	 * @return the formatted invoice number.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public static String formatInvoiceNumber (Integer p_InvoiceId, Integer p_PhysicianId, Integer p_PatientId, boolean p_Short, boolean p_LeadingZeros)
	{
		String l_InvoiceNumber;
		String l_PhysicianNumber;
		String l_PatientNumber;
		
		if (p_InvoiceId != null)
			if (p_LeadingZeros)
				l_InvoiceNumber = m_InvoiceIDFormat.format(p_InvoiceId.longValue());
			else
				l_InvoiceNumber = String.valueOf(p_InvoiceId.longValue());
		else
			l_InvoiceNumber = m_InvoiceIDFormat.format(0);
		
		if (p_Short)
			return l_InvoiceNumber;
		
		if (p_PhysicianId != null)
			l_PhysicianNumber = m_PhysicianIDFormat.format(p_PhysicianId.longValue());
		else
			l_PhysicianNumber = m_PhysicianIDFormat.format(0);
		
		if (p_PatientId != null)
			l_PatientNumber = m_PatientIDFormat.format(p_PatientId.longValue());
		else
			l_PatientNumber = m_PatientIDFormat.format(0);
		
		return (l_PhysicianNumber + "/" + l_PatientNumber + "-" + l_InvoiceNumber);
	}
	
	
	/**
	 * This was used before and might be used by a private iReport print template. Therefore 
	 * the method needs to stay.
	 * 
	 * @param p_Short shell the invoice number be short or long
	 * @return The invoice number as String
	 */
	@Transient
	@Deprecated
	public String formatInvoiceNumber (boolean p_Short)
	{
		return formatInvoiceNumber(p_Short, true);
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * the formatInvoiceNumber formates the invoice number either as a short
	 * number or as a long number. 
	 * @param p_Short specifies whether short format should be used for invoice
	 * number or long format. Specify <code>true</code> for short format, <code>
	 * false</code> for long format.
	 * @return the formatted invoice number.
	 * @see #formatInvoiceNumber (Integer,Integer,Integer,boolean)
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public String formatInvoiceNumber (boolean p_Short, boolean p_LeadingZeros)
	{
		Integer l_PhysicianId = null;
		Integer l_PatientId = null;
		
		l_PhysicianId = (this.getPhysician() != null) ? this.getPhysician().getId() : null;
		l_PatientId = (this.getPatient() != null) ? this.getPatient().getId() : null;
		
		return formatInvoiceNumber(this.getId(), l_PhysicianId, l_PatientId, p_Short, p_LeadingZeros);
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Generates an invoice key for this invoice
	 * @param p_SplitBilling specifies whether physician UCM code will be part
	 * of key or not. Setting the parameter to <code>true</code> will include
	 * the UCM code, setting it to <code>false</code> will omit the UCM code.
	 * @return a String holding the key build using the invoices properties.
	 * @see #generateInvoiceKey (HospitalisationClass,Physician,Date)
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public String generateInvoiceKey (boolean p_SplitBilling)
	{
		Physician l_Physician = null;
		
		if (p_SplitBilling)
			l_Physician = this.getPhysician();
		
		return generateInvoiceKey(this.getHospitalisationClass(),
				l_Physician,
				this.getInvoiceDate());
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Given a hospitalisation class, a physician and an invoice date, the method 
	 * generates a key of the form [A12]_UCMCODE_MM_YYYY. 
	 * First Letter represents the hospitalisation class. It can be either A (Ambulatory), 
	 * 1 (First Class) or 2 (Second Class). The second position labeled UCMCODE 
	 * represents the UCM (Union des Caisses de Maladie) code of the physician.
	 * UCM codes are 8 digit codes in the form of XXXXXX-CC, Xs standing for the
	 * actual code and Cs for the codes checksum. Next position, labeled MM stands
	 * for the month of the invoice date. Possible values for MM are from 1 to 12.
	 * Last position, titled YYYY stands for the year of the invoice date.
	 * @param p_Class specifies the hospitalisation class
	 * @param p_Physician specifies the physician class
	 * @param p_InvoiceDate specifies the date of the invoice
	 * @return a String holding the key build using the specified properties.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public static String generateInvoiceKey (HospitalisationClass p_Class,
			Physician p_Physician,
			Date p_InvoiceDate)
	{
		String l_Key;
		GregorianCalendar l_InvoiceDate;
		
		if ((p_Class == null)
				|| (p_InvoiceDate == null))
			return "";
		
		l_InvoiceDate = new GregorianCalendar();
		l_InvoiceDate.setTime(p_InvoiceDate);
		
		l_Key = p_Class.getAcronym() + "_";
		if (p_Class.getAcronym().equals(HospitalisationClass.c_Ambulant))
			l_Key += l_InvoiceDate.get(Calendar.DAY_OF_MONTH) + "_";
		
		if (p_Physician != null)
			l_Key += p_Physician.getUcmCode() + "_";
		
		l_Key += l_InvoiceDate.get(Calendar.MONTH) + "_" + l_InvoiceDate.get(Calendar.YEAR);
		
		return l_Key;
	}
	
	
	/**
	 * The invoice class defines a static variable to hold the default expiry
	 * period for invoices. The setExpiryPeriod method sets this variable. The
	 * setExpiryPeriod should be called at least once. Not calling the method will
	 * result in expiry period being set to a default value.
	 * @param p_NumberOfDays specifies the invoice expiry period in days.
	 */
	@Transient
	public static void setExpiryPeriod (Integer p_NumberOfDays)
	{
		m_ExpiryPeriod = p_NumberOfDays;
	}
	
	/**
	 * Given an invoice creation date, the method will return the invoice's
	 * due date, i.e. the date the invoice will expire. Please note that the
	 * setExpiryPeriod should have been called before to set expiry period to
	 * desired number of days.
	 * @param originalDate specifies the original invoice date.
	 * @return the due date for the given invoice date.
	 * @see #setExpiryPeriod (Integer)
	 */
	@Transient
	public static Date getDueDate (Date originalDate)
	{
		return getDueDate(originalDate, true);
	}
	
	
	/**
	 * The due date is set, depending on the state of the invoice.
	 * 
	 * @param revoke Whether or not the last reminder of this invoice is revoked.
	 */
	@Transient
	public void setDueDate (boolean revoke)
	{
		Date				originalDate;
		boolean				addDays	= true;
		
		if (getPrintDate() != null && (getNumberOfReminders() == null || getNumberOfReminders().intValue() == 0)) {
			originalDate = getPrintDate();
		} else {
			if (revoke)	{
				originalDate = getDueDate();
				if (revoke)
					// remove the days, instead of adding them
					addDays = false;
			} else {
				originalDate = new Date();
			}
		}
		
		setDueDate(getDueDate(originalDate, addDays));
	}
	
	@Transient
	private static Date getDueDate (Date originalDate, boolean addDays)
	{
		return getLaterDate(originalDate, (addDays ? 1 : -1) * m_ExpiryPeriod.intValue());
	}
	
//---------------------------------------------------------------------------
	/**
	 * Given a date and a number of days, the method will return a date
	 * the specified number of days later then the original date.
	 * @param p_OriginalDate specifies the original date
	 * @param p_NumberOfDays specifies the number of days to go forward in time.
	 * @return a date, p_NumberOfDays later than p_OriginalDate.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public static Date getLaterDate (Date p_OriginalDate, Integer p_NumberOfDays)
	{
		GregorianCalendar l_LaterDate;
		
		if (p_OriginalDate == null)
			return null;
		
		l_LaterDate = new GregorianCalendar();
		l_LaterDate.setTime(p_OriginalDate);
		l_LaterDate.add(Calendar.DAY_OF_MONTH, p_NumberOfDays);
		
		return l_LaterDate.getTime();
	}
	
//---------------------------------------------------------------------------
	/**
	 * The method checks whether the invoice whose state has been specified can still 
	 * be modified or not. 
	 * @param p_State specifies the state of the invoice whose lock state we'd like to have.
	 * @return <code>true</code> if invoice is still open an can be modified,
	 * <code>false</code> otherwise.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public static boolean isLocked (Integer p_State)
	{
		return ((p_State != null) && (p_State.intValue() >= InvoiceWorkflow.c_ClosedState));
	}
	
//---------------------------------------------------------------------------
	/**
	 * The method checks whether this invoice can still be modified or not. 
	 * @return <code>true</code> if invoice is still open an can be modified,
	 * <code>false</code> otherwise.
	 * @see #isLocked (Integer)
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public boolean isLocked ()
	{
		return isLocked(m_State);
	}
	
//---------------------------------------------------------------------------
	/**
	 * The method checks whether the invoice whose state, balance and due date
	 * has been specified has expired, i.e. its due date is in the past or not. 
	 * The state of the invoice also influences the result of this method.
	 * @return <code>true</code> if invoice has expired, <code>false</code> otherwise.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public static boolean isExpired (Date p_DueDate, Integer p_State, Double p_Balance)
	{
		boolean l_IsExpired = false;
		
//		if (m_Today == null)
//			Invoice.setToday();
		
		if (p_DueDate != null)
		{
			l_IsExpired = ((p_State <= InvoiceWorkflow.c_RemindedState)
					|| ((p_State == InvoiceWorkflow.c_PaidState)
					&& (p_Balance > 0d))
					)
					&& (GECAMedUtils.stripTime(new Date()).compareTo(p_DueDate) >= 0);
		}
		
		return l_IsExpired;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * The method checks whether this invoice has expired, i.e. its due date is
	 * in the past or not. The state of the invoice also influences the result
	 * of this method.
	 * @return <code>true</code> if invoice has expired, <code>false</code> otherwise.
	 * @see #isExpired (Date,Integer,Double)
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public boolean isExpired ()
	{
		return isExpired(this.getDueDate(), this.getState(), this.getBalance());
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * The method checks whether this invoice has already been printed or not
	 * @return <code>true</code> if invoice has already been printed, 
	 * <code>false</code> otherwise.
	  */
//---------------------------------------------------------------------------
	
	@Transient
	public boolean alreadyPrinted ()
	{
		return (this.getPrintDate() != null);
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * The method checks whether this invoice has been settled, i.e. its balance is
	 * down to 0.
	 * @return <code>true</code> if invoice has been fully settled, <code>false</code> 
	 * otherwise.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public boolean isSettled ()
	{
		boolean l_IsSettled = false;
		
		if (this.receivedPayment())
		{
			l_IsSettled = (this.getBalance() == 0d);
		}
		
		return l_IsSettled;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * The method checks whether this invoice has already received some kind of
	 * payment or not. Please note that this method does not check whether invoice
	 * bas been fully settled or not. For an invoice that received a down payment,
	 * this method will return <code>true</code>, but the isSettled method will
	 * return <code>false</code> because there's still a balance left.
	 * @return <code>true</code> if invoice has received payment, <code>false</code> 
	 * otherwise.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public boolean receivedPayment ()
	{
		return (this.getSettlement() != null);
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Checks whether all acts on this invoice have their verified flag set or
	 * not.
	 * @return <code>true</code> if all acts on invoice have their verified flag
	 * set, <code>false</code> otherwise.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public boolean allActsVerified ()
	{
		Set<Act> l_Acts;
		Iterator<Act> l_ActIterator;
		boolean l_AllVerified = true;
		
		l_Acts = this.getActs();
		if ((l_Acts == null) || (l_Acts.size() == 0))
			return false;
		
		l_ActIterator = l_Acts.iterator();
		while (l_ActIterator.hasNext() && l_AllVerified)
		{
			l_AllVerified &= l_ActIterator.next().getVerified();
		}
		
		return l_AllVerified;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Computes the total amount of all acts on invoice, and taking into account
	 * already paid amounts and applicable deductions, computes the still open
	 * balance for this invoice.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public void monetize ()
	{
		Iterator<Act> l_ActIterator = null;
		Act l_Act = null;
		
		double l_Total = 0;
		double l_Payment = 0;
		double l_Deduction = 0;
		double l_Balance = 0;
		
		if ((m_Acts == null) || Act.factorsNotSet())
			return;
		
//		m_RoundToSingleDecimal = true;
		
		l_ActIterator = m_Acts.iterator();
		while (l_ActIterator.hasNext())
		{
			l_Act = l_ActIterator.next();
			l_Total += l_Act.monetize();
			
//			if (!l_Act.roundedToSingleDecimal()
//					|| l_Act.getFixAmount() != null)
//				m_RoundToSingleDecimal = false;
		}
		
//		l_Total = this.round(l_Total);
		this.setAmount(new Double(l_Total));
		
		l_Payment = this.getPayment().doubleValue();
		l_Deduction = this.getDeduction().doubleValue();
		
		// We have to round the Balance always to two digits because
		// payment maybe in cents.
		l_Balance = this.round2Cent(l_Total - l_Payment - l_Deduction);
		
//		l_Balance = l_Total - l_Payment - l_Deduction;
		
		this.setBalance(new Double(l_Balance));
	}
	
	
	/**
	 * rounds the given value to 2 decimal places.
	 * @param value
	 * @return
	 */
	public double round2Cent(double value) {
	    BigDecimal bd = new BigDecimal(value);
	    bd = bd.setScale(2, RoundingMode.HALF_UP);
	    return bd.doubleValue();
	}
	
//---------------------------------------------------------------------------
	/**
	 * The getCommonPhysicianId returns the ID of the physician shared by all
	 * acts on invoice. If Invoice contains acts of different physicians, the
	 * method will return value c_NoCommonPhysician.
	 * @return : The ID of the physician shared by all Acts on invoice, 
	 * c_NoCommonPhysician if invoice either contains no Acts or acts of different 
	 * physicians
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public Integer getCommonPhysicianId ()
	{
		Iterator<Act> l_ActIterator;
		Act l_Act;
		int l_CommonId = c_NoCommonPhysician;
		boolean l_isSinglePhysicianInvoice = true;
		
		if (this.getActs() != null)
		{
			l_ActIterator = this.getActs().iterator();
			while (l_ActIterator.hasNext() && l_isSinglePhysicianInvoice)
			{
				l_Act = l_ActIterator.next();
				
				if (l_CommonId == c_NoCommonPhysician)
				{
					l_CommonId = l_Act.getPhysicianId();
				}
				else
					l_isSinglePhysicianInvoice = (l_CommonId == l_Act.getPhysicianId());
			}
		}
		
		if (!l_isSinglePhysicianInvoice)
			l_CommonId = c_NoCommonPhysician;
		
		return Integer.valueOf(l_CommonId);
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * given a collection of Invoices, this method returns a collection
	 * holding the IDs of all the invoices included in the specified collection.
	 * @param p_Invoices specifies the collection of Invoices to get IDs of.
	 * @return A collection holding the IDs of the invoices contained in the
	 * specified collection.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public static Collection<Integer> getInvoiceIDs (Collection<Invoice> p_Invoices)
	{
		Collection<Integer> l_InvoiceIDs;
		Iterator<Invoice> l_InvoiceIterator;
		Invoice l_Invoice;
		
		l_InvoiceIDs = new LinkedHashSet<Integer>();
		
		if (p_Invoices == null)
			return l_InvoiceIDs;
		
		l_InvoiceIterator = p_Invoices.iterator();
		while (l_InvoiceIterator.hasNext())
		{
			l_Invoice = l_InvoiceIterator.next();
			l_InvoiceIDs.add(l_Invoice.getId());
		}
		
		return l_InvoiceIDs;
	}
	
	
//***************************************************************************
//* Class Body                                                              *
//***************************************************************************
//---------------------------------------------------------------------------
	/**
	 * Returns the patient associated with this invoice.
	 * @return The patient associated with this invoice.
	 */
//---------------------------------------------------------------------------
	
	@ManyToOne(fetch = javax.persistence.FetchType.LAZY)
	@JoinColumn(name = "patient_id")
	public Patient getPatient ()
	{
		return m_Patient;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Associates the specified patient with this invoice
	 * @param p_Patient specifies the patient to be associated with this
	 * invoice
	 */
//---------------------------------------------------------------------------
	
	public void setPatient (Patient p_Patient)
	{
		m_Patient = p_Patient;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the physician associated with this invoice
	 * @return The physician associated with this invoice
	 */
//---------------------------------------------------------------------------
	
	@ManyToOne(fetch = javax.persistence.FetchType.EAGER)
	@JoinColumn(name = "physician_id")
	public Physician getPhysician ()
	{
		return m_Physician;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Associates the specified physician with this invoice
	 * @param p_Physician specifies the physician to be associated with this
	 * invoice
	 */
//---------------------------------------------------------------------------
	
	public void setPhysician (Physician p_Physician)
	{
		m_Physician = p_Physician;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the hospitalisation associated with this invoice
	 * @return The hospitalisation associated with this invoice
	 */
//---------------------------------------------------------------------------
	
	@ManyToOne(fetch = javax.persistence.FetchType.LAZY)
	@JoinColumn(name = "hospitalisation_id")
	public Hospitalisation getHospitalisation ()
	{
		return m_Hospitalisation;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Associates the specified hospitalisation with this invoice
	 * @param p_Hospitalisation specifies the hospitalisation to be associated with
	 * this invoice
	 */
//---------------------------------------------------------------------------
	
	public void setHospitalisation (Hospitalisation p_Hospitalisation)
	{
		m_Hospitalisation = p_Hospitalisation;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the patients' hospitalisation class associated with this invoice
	 * @return The patients' hospitalisation class
	 */
//---------------------------------------------------------------------------
	
	@ManyToOne(fetch = javax.persistence.FetchType.EAGER)
	@JoinColumn(name = "class_id")
	public HospitalisationClass getHospitalisationClass ()
	{
		return m_HospitalisationClass;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Associates the specified hospitalisation class with this invoice
	 * @param p_HospitalisationClass specifies the hospitalisation class to be 
	 * associated with this invoice
	 */
//---------------------------------------------------------------------------
	
	public void setHospitalisationClass (HospitalisationClass p_HospitalisationClass)
	{
		m_HospitalisationClass = p_HospitalisationClass;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the patients' health insurance associated with this invoice
	 * @return The patients' health insurance
	 */
//---------------------------------------------------------------------------
	
	@ManyToOne(fetch = javax.persistence.FetchType.EAGER)
	@JoinColumn(name = "insurance_id")
	public Insurance getHealthInsurance ()
	{
		return m_HealthInsurance;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Associates the specified health insurance with this invoice
	 * @param p_HealthInsurance specifies the health insurance to be 
	 * associated with this invoice
	 */
//---------------------------------------------------------------------------
	
	public void setHealthInsurance (Insurance p_HealthInsurance)
	{
		m_HealthInsurance = p_HealthInsurance;
	}
	
	//---------------------------------------------------------------------------
		/**
		 * Sets the insurance of this invoice via the acronym.
		 * For the method to work as expected, the static setInsurances should have 
		 * been called at least once beforehand.
		 * @param p_Acronym specifies the acronym of the insurance
		 * to take over charges of this invoice.
		 */
	//---------------------------------------------------------------------------
		
	@Transient
	public void setHealthInsurance (String p_Acronym)
	{
		Insurance l_Insurance;

		if ((m_Insurances == null) || (p_Acronym == null))
			return;

		if (m_Insurances.containsKey(p_Acronym))
		{
			l_Insurance = m_Insurances.get(p_Acronym);
			this.setHealthInsurance(l_Insurance);
		}
		else
			this.setHealthInsurance((Insurance) null);
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the third party paying insurance covering this invoices' due amount
	 * @return The third party paying insurance associated with this invoice
	 */
//---------------------------------------------------------------------------
	
	@ManyToOne(fetch = javax.persistence.FetchType.EAGER)
	@JoinColumn(name = "third_party_id")
	public Insurance getThirdPartyPayer ()
	{
		return m_ThirdPartyPayer;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the specified insurance as the third party payer for this invoices'
	 * due amount
	 * @param p_ThirdPartyPayer specifies the third party paying insurance to be
	 * associated with this invoice
	 */
//---------------------------------------------------------------------------
	
	public void setThirdPartyPayer (Insurance p_ThirdPartyPayer)
	{
		m_ThirdPartyPayer = p_ThirdPartyPayer;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the user who closed this invoice
	 * @return The closing user
	 */
//---------------------------------------------------------------------------
	
	@ManyToOne(fetch = javax.persistence.FetchType.LAZY)
	@JoinColumn(name = "closer_id")
	public GecamedUser getCloser ()
	{
		return m_Closer;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the user who closed this invoice
	  * @param p_Closer specifies the closing user
	 */
//---------------------------------------------------------------------------
	
	public void setCloser (GecamedUser p_Closer)
	{
		m_Closer = p_Closer;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns this invoices' closure date
	 * @return Invoice closure date
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "closure_date")
	public Date getClosureDate ()
	{
		return m_ClosureDate;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the specified date as this invoices' closure date
	 * @param p_ClosureDate specifies the new invoice closure date
	 */
//---------------------------------------------------------------------------
	
	public void setClosureDate (Date p_ClosureDate)
	{
		m_ClosureDate = (p_ClosureDate != null) ? new Date(p_ClosureDate.getTime()) : null;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the user who last modified this invoice
	 * @return The modifying user
	 */
//---------------------------------------------------------------------------
	
	@ManyToOne(fetch = javax.persistence.FetchType.LAZY)
	@JoinColumn(name = "modifier_id")
	public GecamedUser getModifier ()
	{
		return m_Modifier;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the user who last modified this invoice
	  * @param p_Modifier specifies the modifying user
	 */
//---------------------------------------------------------------------------
	
	public void setModifier (GecamedUser p_Modifier)
	{
		m_Modifier = p_Modifier;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns this invoices' modification date
	 * @return Invoice modification date
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "modification_date")
	public Date getModificationDate ()
	{
		return m_ModificationDate;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the specified date as this invoices' modification date
	 * @param p_ModificationDate specifies the new invoice modification date
	 */
//---------------------------------------------------------------------------
	
	public void setModificationDate (Date p_ModificationDate)
	{
		m_ModificationDate = (p_ModificationDate != null) ? new Date(p_ModificationDate.getTime()) : null;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Checks whether this invoice refers to a hospitalisation requiring a
	 * first class. The requesting physician must provide a certificat.
	 * @return <code>true</code> if this invoice refers to a required first 
	 * class hospitalistion, <code>false</code> otherwise.
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "first_class_required")
	public Boolean getFirstClassRequired ()
	{
		return m_FirstClassRequired;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Specifies whether this invoice refers to a hospitalisation requiring a
	 * first class.
	 * @param p_FirstClassRequired set to <code>true</code> indicates that the 
	 * hospitalisation this invoice refers to requires a first class.
	 */
//---------------------------------------------------------------------------
	
	public void setFirstClassRequired (Boolean p_FirstClassRequired)
	{
		m_FirstClassRequired = p_FirstClassRequired;
	}
	
	
	public void updateFirstClassRequired ()
	{
		if (m_Acts != null)
		{
			for (Act act : m_Acts)
				act.setFirstClassRequired(m_FirstClassRequired);
		}
	}
	
//---------------------------------------------------------------------------
	/**
	 * Returns this invoices' creation date
	 * @return Invoice creation date
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "created")
	public Date getInvoiceDate ()
	{
		return m_InvoiceDate;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the specified date as this invoices' creation date
	 * @param p_InvoiceDate specifies the new invoice creation date
	 */
//---------------------------------------------------------------------------
	
	public void setInvoiceDate (Date p_InvoiceDate)
	{
		m_InvoiceDate = (p_InvoiceDate != null) ? new Date(p_InvoiceDate.getTime()) : null;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns this invoices' due date
	 * @return Invoice due date
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "due")
	public Date getDueDate ()
	{
		return m_DueDate;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the specified date as this invoices' due date
	 * @param p_DueDate specifies the new invoice due date
	 */
//---------------------------------------------------------------------------
	
	public void setDueDate (Date p_DueDate)
	{
		m_DueDate = (p_DueDate != null) ? new Date(p_DueDate.getTime()) : null;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the date and time this invoice was printed
	 * @return Invoice print date and time
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "printed")
	public Date getPrintDate ()
	{
		return m_PrintDate;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the specified date and time as this invoices' print date and time
	 * @param p_PrintDate specifies the new invoice print date
	 */
//---------------------------------------------------------------------------
	
	public void setPrintDate (Date p_PrintDate)
	{
		m_PrintDate = (p_PrintDate != null) ? new Date(p_PrintDate.getTime()) : null;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the state this invoice is currently in
	 * @return The invoice state
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "state")
	public Integer getState ()
	{
		return (m_State != null) ? m_State : InvoiceWorkflow.c_NewState;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the state this invoice is currently in
	 * @param p_State specifies the new invoice state
	 */
//---------------------------------------------------------------------------
	
	public void setState (Integer p_State)
	{
		m_State = p_State;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the state this invoice was previously in
	 * @return The old invoice state
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "old_state")
	public Integer getOldState ()
	{
		return (m_OldState != null) ? m_OldState : InvoiceWorkflow.c_NewState;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the state this invoice was in
	 * @param p_OldState specifies the old invoice state
	 */
//---------------------------------------------------------------------------
	
	public void setOldState (Integer p_OldState)
	{
		m_OldState = p_OldState;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * In case this invoice is related to an accident, the getAccidentNumber method
	 * will return the corresponding accident number
	 * @return The accident number, if available, <code>null</code> otherwise
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "accident_number")
	public String getAccidentNumber ()
	{
		return m_AccidentNumber;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets this invoices' accident number to the one specified
	 * @param p_AccidentNumber specifies the accident number to be associated 
	 * with this invoice
	 */
//---------------------------------------------------------------------------
	
	public void setAccidentNumber (String p_AccidentNumber)
	{
		m_AccidentNumber = p_AccidentNumber;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * In case this invoice is related to an accident, the getAccidentDate method
	 * will return the date the accident occured
	 * @return The accident date, if available, <code>null</code> otherwise
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "accident_date")
	public Date getAccidentDate ()
	{
		return m_AccidentDate;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the specified date as the accident date
	 * @param p_AccidentDate specifies the new accident date
	 */
//---------------------------------------------------------------------------
	
	public void setAccidentDate (Date p_AccidentDate)
	{
		m_AccidentDate = (p_AccidentDate != null) ? new Date(p_AccidentDate.getTime()) : null;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the number of reminders already issued for this invoice
	 * @return The number of issued reminders.
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "reminders")
	public Integer getNumberOfReminders ()
	{
		return m_Reminders;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the number of already issued reminders
	 * @param p_Reminders specifies the number of issued reminders
	 */
//---------------------------------------------------------------------------
	
	public void setNumberOfReminders (Integer p_Reminders)
	{
		m_Reminders = p_Reminders;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the date the latest reminder was issued
	 * @return Latest reminder date
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "reminder_date")
	public Date getReminderDate ()
	{
		return m_ReminderDate;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the date the latest reminder was issued
	 * @param p_ReminderDate specifies the latest reminder date
	 */
//---------------------------------------------------------------------------
	
	public void setReminderDate (Date p_ReminderDate)
	{
		m_ReminderDate = (p_ReminderDate != null) ? new Date(p_ReminderDate.getTime()) : null;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the value this invoice amounts to
	 * @return The invoice total amount
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "amount")
	public Double getAmount ()
	{
		return m_Amount;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the value this invoice amounts to.
	 * @param p_Amount specifies the total amount for this invoice
	 */
//---------------------------------------------------------------------------
	
	public void setAmount (Double p_Amount)
	{
		m_Amount = p_Amount;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the already paid amount for this invoice
	 * @return The already paid amount
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "payment")
	public Double getPayment ()
	{
		return m_Payment;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the already paid amount
	 * @param p_Payment specifies the amount already paid
	 */
//---------------------------------------------------------------------------
	
	public void setPayment (Double p_Payment)
	{
		m_Payment = p_Payment;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns an eventual deduction applied to this invoice. Deductions may be
	 * applied to invoice to compensate for non-reimbursed amounts.
	 * @return The deduced amount
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "deduction")
	public Double getDeduction ()
	{
		return m_Deduction;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the amount to be deduced from this invoice
	 * @param p_Deduction specifies the amount to be deduced
	 */
//---------------------------------------------------------------------------
	
	public void setDeduction (Double p_Deduction)
	{
		m_Deduction = p_Deduction;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the amount that still needs to be paid to settle this invoice. The
	 * balance is normaly obtained by subtracting payment and deduction from total
	 * invoice amount.
	 * @return The invoice balance
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "balance")
	public Double getBalance ()
	{
		return m_Balance;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the amount that still needs to paid to settle this invoice
	 * @param p_Balance specifies the new balance for this invoice
	 */
//---------------------------------------------------------------------------
	
	public void setBalance (Double p_Balance)
	{
		m_Balance = p_Balance;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Depending on the context of the invoice, the total amount of the invoice
	 * may be subject to a majoration coefficient, i.e. the total amount of the
	 * invoice and thus every position on it will be multiplied it. This method
	 * return the value of this coefficient which defaults to 1.
	 * @return The invoice balance
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "majoration")
	public Double getMajoration ()
	{
		return m_Majoration;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Specifies the majoration coefficient for this invoice. Majoration coefficient
	 * defaults to one. Setting another value entails total amount and thus the amount
	 * of every position on the invoice to be multiplied by the new value.
	 * @param p_Majoration specifies the new majoration coefficient. Please remember
	 * that 66% has to be specified as 1.66.
	 */
//---------------------------------------------------------------------------
	
	public void setMajoration (Double p_Majoration)
	{
		m_Majoration = p_Majoration;
	}
	
	
	/**
	 * returns the transfering physician
	 * @return
	 */
	@Column(name = "med_trans_code")
	public String getMedTrans ()
	{
		return m_MedTrans;
	}
	
	
	/**
	 *  sets the transfering physician
	 * @param m_MedTrans
	 */
	public void setMedTrans (String m_MedTrans)
	{
		this.m_MedTrans = m_MedTrans;
	}
	
	
	@Transient
	public void setAllMajorations (Double p_Majoration)
	{
		m_Majoration = p_Majoration;
		
		if (m_Acts != null)
			for (Act l_Act : m_Acts)
			{
				l_Act.setMajoration(m_Majoration);
			}
		
		notifyActsChanged();
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns this invoice settlement. The returned settlement object holds
	 * information about how this invoice was settled. 
	 * @return This invoices' settlement, if available, <code>null</code> otherwise
	 */
//---------------------------------------------------------------------------
	
	@ManyToOne(fetch = javax.persistence.FetchType.EAGER)
	@JoinColumn(name = "settlement_id")
	public Settlement getSettlement ()
	{
		return m_Settlement;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets this invoices' settlement
	 * @param p_Settlement specifies the settlement for this invoice
	 */
//---------------------------------------------------------------------------
	
	public void setSettlement (Settlement p_Settlement)
	{
		m_Settlement = p_Settlement;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns this invoices' settlement date
	 * @return Invoice settlement date,if available, <code>null</code> otherwise
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "settlement_date")
	public Date getSettlementDate ()
	{
		return m_SettlementDate;
	}
	
//---------------------------------------------------------------------------
	/**
	 * Sets the specified date as this invoices' settlement number
	 * @param p_SettlementDate specifies the new invoice settlement date
	 */
//---------------------------------------------------------------------------
	
	public void setSettlementDate (Date p_SettlementDate)
	{
		m_SettlementDate = (p_SettlementDate != null) ? new Date(p_SettlementDate.getTime()) : null;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the statement this invoice is on
	 * @return The statement this invoice is on, if available, <code>null</code> otherwise
	 */
//---------------------------------------------------------------------------
	
	@ManyToOne(fetch = javax.persistence.FetchType.EAGER)
	@JoinColumn(name = "statement_id")
	public Statement getStatement ()
	{
		return m_Statement;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the statement this invoice is on
	 * @param p_Statement specifies the statement this invoice is on
	 */
//---------------------------------------------------------------------------
	
	public void setStatement (Statement p_Statement)
	{
		m_Statement = p_Statement;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the site ID where this invoice has been created
	 * @return the m_SiteId
	 */
//---------------------------------------------------------------------------
	
	@Column(name = "site_id")
	public Integer getSiteId ()
	{
		return m_SiteId;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the site id where this invoice has been created
	 * @param siteId the site id where this invoice has been created
	 */
//---------------------------------------------------------------------------
	
	public void setSiteId (Integer siteId)
	{
		m_SiteId = siteId;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the acts on this invoice
	 * @return Acts on this invoice
	 */
//---------------------------------------------------------------------------
	
	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@JoinColumn(name = "invoice_id")
	@OrderBy("performedDate, code ASC")
	public Set<Act> getActs ()
	{
		return m_Acts;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the acts for this invoice
	 * @param p_Acts specifies the acts to be put on this invoice
	 */
//---------------------------------------------------------------------------
	
	public void setActs (Set<Act> p_Acts)
	{
		m_Acts = p_Acts;
		notifyActsChanged();
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns all the memos associated with this invoice
	 * @return memos associated with this invoice
	 */
//---------------------------------------------------------------------------
	
	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@JoinColumn(name = "invoice_id")
	@OrderBy("creationDate ASC")
	public Set<Memo> getMemos ()
	{
		return m_Memos;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the memos for this invoice
	 * @param p_Memos specifies the memos to be put on this invoice
	 */
//---------------------------------------------------------------------------
	
	public void setMemos (Set<Memo> p_Memos)
	{
		m_Memos = p_Memos;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the number of acts associated with this invoice
	 * @return The number of acts on invoice
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public Integer getNumberOfActs ()
	{
		if (this.getActs() != null)
			return Integer.valueOf(this.getActs().size());
		else
			return c_Zero;
		
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Returns the number of memos associated with this invoice
	 * @return The number of memos attached to invoice
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public Integer getNumberOfMemos ()
	{
		if (this.getMemos() != null)
			return Integer.valueOf(this.getMemos().size());
		else
			return c_Zero;
	}
	
	
	@Column(name = "rule_log")
	public String getRuleLog() {
		return this.ruleLog;
	}
	
	public void setRuleLog(String ruleLog) {
		this.ruleLog = ruleLog;
	}
	
//---------------------------------------------------------------------------
//***************************************************************************
//* Rule Engine Helpers                                       				*
//***************************************************************************
//---------------------------------------------------------------------------
	/**
	 * the method returns a date representing the first of the month this invoice
	 * was created in.
	 * @return a date representing the first of the month this invoice
	 * was created in if creation date is available, <code>null</code> otherwise.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public Date getFirstOfInvoiceMonth ()
	{
		GregorianCalendar l_InvoiceMonth;
		
		if (m_InvoiceDate != null)
		{
			l_InvoiceMonth = new GregorianCalendar();
			l_InvoiceMonth.setTime(m_InvoiceDate);
			l_InvoiceMonth.set(Calendar.DAY_OF_MONTH, 1);
			l_InvoiceMonth.set(Calendar.HOUR_OF_DAY, 0);
			l_InvoiceMonth.set(Calendar.MINUTE, 0);
			l_InvoiceMonth.set(Calendar.SECOND, 0);
			l_InvoiceMonth.set(Calendar.MILLISECOND, 0);
			return l_InvoiceMonth.getTime();
		}
		else
		{
			return null;
		}
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Sets the third party paying insurance of this invoice via the acronym.
	 * For the method to work as expected, the static setInsurances should have 
	 * been called at least once beforehand.
	 * @param p_Acronym specifies the acronym of the third party paying insurance
	 * to take over charges of this invoice.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public void setThirdPartyPayer (String p_Acronym)
	{
		Insurance l_ThirdPartyPayer;
		
		if ((m_Insurances == null) || (p_Acronym == null))
			return;
		
		if (m_Insurances.containsKey(p_Acronym))
		{
			l_ThirdPartyPayer = m_Insurances.get(p_Acronym);
			this.setThirdPartyPayer(l_ThirdPartyPayer);
		}
		else
			this.setThirdPartyPayer((Insurance) null);
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * checks whether patient's health insurance is affiliated to the UCM
	 * (Union des Caisses de Maladie) or not.
	 * @return <code>true</code> if patient's health insurance is UCM affiliated,
	 * <code>false</code> otherwise.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public Boolean isInsuranceUCMAffiliated ()
	{
		if (this.getHealthInsurance() != null)
			return this.getHealthInsurance().getUcmAffiliated();
		else
			return Boolean.FALSE;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * checks whether patient's health insurance is set to E111. A E111 was a form
	 * entitlingyou to reduced-cost, sometimes free, medical treatment that becomes 
	 * necessary while you're in a European Economic Area (EEA) country or Switzerland.
	 * The E111 form has been replaced by the European Health Insurance Card (EHIC) 
	 * @return <code>true</code> if patient's health insurance is a E111 form or
	 * European Health Insurance Card, <code>false</code> otherwise.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public Boolean isInsuranceE111 ()
	{
		if (this.getHealthInsurance() != null)
			return this.getHealthInsurance().getAcronym().equals("E111");
		else
			return Boolean.FALSE;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Checks whether this invoice is related to an accident or not.
	 * @return <code>true</code> if this invoice is related to an accident,
	 * <code>false</code> otherwise
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public boolean isAccident ()
	{
		boolean l_IsAccident = false;
		
		l_IsAccident |= (m_AccidentDate != null) ? true : false;
		l_IsAccident |= ((m_AccidentNumber != null) && (m_AccidentNumber.length() > 0)) ? true : false;
		
		return l_IsAccident;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Checks whether this invoice has its hospitalisation class set to ambulatory
	 * or not.
	 * @return <code>true</code> if this invoice is ambulatory, <code>false</code> 
	 * otherwise
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public Boolean isAmbulatory ()
	{
		if (this.getHospitalisationClass() != null)
			return (this.getHospitalisationClass().getAcronym().equals(HospitalisationClass.c_Ambulant));
		else
			return Boolean.TRUE;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Checks whether this invoice has its hospitalization class set to first class
	 * or not.
	 * @return <code>true</code> if this invoice is first class, <code>false</code> 
	 * otherwise
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public Boolean isFirstClass ()
	{
		if (this.getHospitalisationClass() != null)
			return (this.getHospitalisationClass().getAcronym().equals(HospitalisationClass.c_FirstClass));
		else
			return Boolean.FALSE;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Checks whether this invoice has is taken in charge by a third party paying
	 * insurance or not.
	 * @return <code>true</code> if this invoice is taken in charge by third party, 
	 * <code>false</code> otherwise.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public Boolean isPaidByThirdParty ()
	{
		if ((this.getThirdPartyPayer() != null) && (this.getThirdPartyPayer().getId() > 0))
			return Boolean.TRUE;
		else
			return Boolean.FALSE;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Checks whether acts on invoice contain specified rate for the specified 
	 * date.
	 * @param p_Rate specifies the rate to look for in invoice acts
	 * @param p_DateOfInterest specifies the date that sought act ought to be
	 * performed on.
	 * @return <code>true</code>if a rate matching specified criteria could be
	 * found, <code>false</code> otherwise.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public Boolean actsIncludeRate (Rate p_Rate, Date p_DateOfInterest)
	{
		Set<Act> l_Acts;
		Iterator<Act> l_ActIterator;
		Act l_Act;
		Date l_DateOfInterest = null;
		Date l_PerformedDate;
		
		boolean l_RateIncluded = false;
		
		if (p_Rate == null)
			return Boolean.FALSE;
		
		if (p_DateOfInterest != null)
			l_DateOfInterest = GECAMedUtils.stripTime(p_DateOfInterest);
		
		l_Acts = this.getActs();
		if (l_Acts != null)
		{
			l_ActIterator = l_Acts.iterator();
			while (l_ActIterator.hasNext() && !l_RateIncluded)
			{
				l_Act = l_ActIterator.next();
				l_RateIncluded = l_Act.getCode().equals(p_Rate.getCode());
				if (l_RateIncluded && (l_DateOfInterest != null))
				{
					l_PerformedDate = GECAMedUtils.stripTime(l_Act.getPerformedDate());
					l_RateIncluded &= l_PerformedDate.equals(l_DateOfInterest);
				}
			}
		}
		
		return l_RateIncluded;
	}
	
	
//---------------------------------------------------------------------------
	/**
	 * Checks whether this invoice contains acts which are part of the specified
	 * section in the nomenclature.
	 * @param p_Index specifies the section of the nomenclature to check invoice
	 * acts against.
	 * @param p_DateOfInterest specifies a specific date that act of interest 
	 * should be performed on to match. Specify <code>null</code> if not required.
	 * @return <code>true</code> if this invoice contains at least one act whose 
	 * rate is listed in the specified section of the nomenclature and whose
	 * performed date matches the specified date of interest.
	 */
//---------------------------------------------------------------------------
	
	@Transient
	public Boolean includesRatesIn (RateIndex p_Index, Date p_DateOfInterest)
	{
		Set<Act> l_Acts;
		Iterator<Act> l_ActIterator;
		Act l_Act;
		Date l_DateOfInterest = null;
		Date l_DateOfAct;
		
		boolean l_RateIncluded = false;
		
		if (p_Index == null)
			return Boolean.FALSE;
		
		if (p_DateOfInterest != null)
			l_DateOfInterest = GECAMedUtils.stripTime(p_DateOfInterest);
		
		l_Acts = this.getActs();
		if (l_Acts != null)
		{
			l_ActIterator = l_Acts.iterator();
			while (l_ActIterator.hasNext() && !l_RateIncluded)
			{
				l_Act = l_ActIterator.next();
				
				l_DateOfAct = GECAMedUtils.stripTime(l_Act.getPerformedDate());
				
				if (p_Index.includesAct(l_Act))
				{
					l_RateIncluded = (l_DateOfInterest != null)
							? l_DateOfAct.equals(l_DateOfInterest)
							: true;
				}
			}
		}
		
		return l_RateIncluded;
	}
	
	
	@Transient
	public void setUseShortNumbers (boolean p_Short)
	{
		m_UseShortNumbers = p_Short;
	}
	
	
	@Transient
	public boolean getUseShortNumbers ()
	{
		return m_UseShortNumbers;
	}
	
	
	@Transient
	public void setUseLeadingZeros (boolean p_LeadingZeros)
	{
		m_UseShortNumbers = p_LeadingZeros;
	}
	
	
	@Transient
	public boolean getUseLeadingZeros ()
	{
		return m_UseLeadingZeros;
	}
	
	
//---------------------------------------------------------------------------
	
	/**
	 * Before using this method, you need to set whether the format should be 
	 * short or not by using the setUseShortNumbers. Default is false.
	 * 
	 * @return
	 */
	@Transient
	public String getInvoiceNumber ()
	{
		return formatInvoiceNumber(m_UseShortNumbers, m_UseLeadingZeros);
	}
	
	
//---------------------------------------------------------------------------
	
	@Transient
	public void setFormatedDate (String p_FormatedDate)
	{
		this.m_FormatedDate = p_FormatedDate;
	}
	
	
//---------------------------------------------------------------------------
	
	@Transient
	public String getFormatedDate ()
	{
		return m_FormatedDate;
	}
	
	
//---------------------------------------------------------------------------
	
	@Transient
	public String getFormatedReminderDate ()
	{
		return m_FormatedReminderDate;
	}
	
	
//---------------------------------------------------------------------------
	
	@Transient
	public void setFormatedReminderDate (String p_FormatedDate)
	{
		this.m_FormatedReminderDate = p_FormatedDate;
	}
	
	
//---------------------------------------------------------------------------
	/**************************************************/
	
//---------------------------------------------------------------------------
	/**
	 *  adds the new act with specified rate and having its peformed date set to
	 *  the specified date.
	 *  @param p_Rate specifies the rate for the act to add.
	 *  @param p_Date specifies the performed date for the act to add.
	 */
//---------------------------------------------------------------------------
	
//	@Transient
//	public Act addRate (Rate p_Rate, Date p_Date, String p_Suffixes)
//	{
//		Set<Act> l_Acts;
//		Act l_Act;
//		
//		if (p_Rate == null)
//			return null;
//		
//		if (p_Suffixes == null)
//			p_Suffixes = "";
//		
//		l_Act = new Act();
//		l_Act.setPerformedDate(p_Date);
//		
//		if (this.getPhysician() != null)
//			l_Act.setPhysicianId(this.getPhysician().getId());
//		
//		p_Rate.initializeAct(l_Act);
//		l_Act.setSuffixes(p_Suffixes);
//		if (getHospitalisationClass() == null || getHospitalisationClass().getAcronym() == null)
//		{
//			l_Act.setHospitalisationClass(HospitalisationClass.c_Ambulant, this);
//		}
//		else
//		{
//			l_Act.setHospitalisationClass(getHospitalisationClass().getAcronym(), this);
//		}
//		
//		l_Acts = this.getActs();
//		if (l_Acts == null)
//			l_Acts = new HashSet<Act>();
//		l_Acts.add(l_Act);
//		this.setActs(l_Acts);
//		
//		return l_Act;
//	}
	
	@Transient
	public Act addAct (Act p_Act, Date p_Date, String p_Suffixes)
	{
		Set<Act> l_Acts;
		
		if (p_Suffixes == null)
			p_Suffixes = "";

		p_Act.setPerformedDate(p_Date);
		
		if (this.getPhysician() != null)
			p_Act.setPhysicianId(this.getPhysician().getId());
		
		p_Act.setSuffixes(p_Suffixes);
		if (getHospitalisationClass() == null || getHospitalisationClass().getAcronym() == null)
		{
			p_Act.setHospitalisationClass(HospitalisationClass.c_Ambulant, this);
		}
		else
		{
			p_Act.setHospitalisationClass(getHospitalisationClass().getAcronym(), this);
		}
		
		l_Acts = this.getActs();
		if (l_Acts == null)
			l_Acts = new HashSet<Act>();
		l_Acts.add(p_Act);
		this.setActs(l_Acts);
		
		return p_Act;
	}
	
	
//---------------------------------------------------------------------------
	
//	@Transient
//public void replaceActWithRate (Act p_Act, Rate p_Rate, boolean onlyReplaceIfActValueNotZero)
//	{
//	Set <Act> l_Acts;
//	
//	
//	if (onlyReplaceIfActValueNotZero)
//	{
//		Double coefficient = p_Rate.getCoefficient();
//		if (coefficient == null || coefficient.doubleValue() == 0)
//			return;
//	}
//	
//	if (p_Act == null) 
//		{
//		log(Level.WARN, "Cannot replace act, because the act is NULL!");
//		return;
//		}
//	
//	l_Acts = this.getActs();
//	if (l_Acts == null) 
//	{
//		log(Level.WARN, "Cannot remove act " + p_Act.getCode() + ", because there are no acts in the invoice!");
//		return;
//	}
//	else if (!l_Acts.remove(p_Act))
//	{
//		log(Level.WARN, "Cannot remove act " + p_Act.getCode() + ", because it doesn't exist in the invoice!");
//		return;
//	}
//	
//	if (p_Rate != null)
//		{
//		p_Rate.initializeAct(p_Act);
//		l_Acts.add(p_Act);
//		}
//	this.setActs(l_Acts);
//	}
		
//---------------------------------------------------------------------------
	
	@Transient
	public void updateAct (Act p_Act)
	{
		Set<Act> l_Acts;
		
		if (p_Act == null)
			return;
		
		l_Acts = this.getActs();
		if (l_Acts.contains(p_Act))
		{
			// this will find the former act with the same ID and remove it
			l_Acts.remove(p_Act);
			l_Acts.add(p_Act);
		}
		
		this.setActs(l_Acts);
	}
	
	
//---------------------------------------------------------------------------
	
//@Transient
//public Integer getDayOfHospitalisation (Act p_Act)
//	{
//	Integer l_Day = new Integer(-1);
//	long 	l_PerformedTime;
//	long 	l_StartTime;
//	long 	l_EndTime;
//	Calendar l_PerformedDay;
//	Calendar l_CompareDay;
//	
//	if (m_Hospitalisation == null)
//		return l_Day;
//	
//	l_PerformedTime = GECAMedUtils.stripTime(p_Act.getPerformedDate()).getTime();
//	
//	for (HospitalisationPeriod l_Period : m_Hospitalisation.getHospitalisationPeriods())
//		{
//		l_StartTime = GECAMedUtils.stripTime(l_Period.getStartDate()).getTime();
//		l_EndTime 	= GECAMedUtils.stripTime(l_Period.getEndDate()).getTime();
//		
//		if (l_PerformedTime >= l_StartTime && l_PerformedTime <= l_EndTime)
//			{
//			// the act is performed in this period
//			l_CompareDay 	= new GregorianCalendar();
//			l_CompareDay.setTimeInMillis(l_StartTime);
//			
//			l_PerformedDay 	= new GregorianCalendar();
//			l_PerformedDay.setTimeInMillis(l_PerformedTime);
//			
//			l_Day = 1;
//			while (l_PerformedDay.compareTo(l_CompareDay) > 0)
//				{
//				l_CompareDay.add(Calendar.DAY_OF_YEAR, 1);
//				l_Day++;
//				}
//			
//			return l_Day;
//			}
//		}
//	
//	return l_Day;
//	}
	
	
//@Transient
//public Boolean isActBeforeHospitalisationDay (Act p_Act, int p_Day)
//	{
//	int l_Day = getDayOfHospitalisation(p_Act);
//	
//	if (l_Day > 0 && l_Day < p_Day)
//		 return Boolean.TRUE;
//	else return Boolean.FALSE;
//	}

//---------------------------------------------------------------------------
	
	@Transient
	public boolean isModified ()
	{
		if (modifiedStatus == null)
			return false;
		
		return modifiedStatus.modified(this);
	}
	
	
//---------------------------------------------------------------------------
	
	@Transient
	public void setUnmodified ()
	{
		if (modifiedStatus == null)
			modifiedStatus = new InvoiceModifiedStatus();
		
		modifiedStatus.saveStatus(this);
	}
	
	
	@Transient
	public boolean hasPrivateActs ()
	{
		for (Act l_Act : m_Acts)
		{
			if (!l_Act.isCnsAct())
				return true;
		}
		return false;
	}
	
	
	@Transient
	public boolean hasCnsActs ()
	{
		for (Act l_Act : m_Acts)
		{
			if (l_Act.isCnsAct())
				return true;
		}
		
		return false;
	}
	
	
	@Transient
	public void addActsChangedListener (ActsChangedListener listener)
	{
		if (actsChangedListener == null)
			actsChangedListener	= new LinkedList<ActsChangedListener>();
		
		actsChangedListener.add(listener);
	}
	
	
	@Transient
	public boolean removeActsChangedListener (ActsChangedListener listener)
	{
		if (actsChangedListener != null)
			return actsChangedListener.remove(listener);
		else 
			return false;
	}
	
	
	@Transient
	public void removeAllActsChangedListener ()
	{
		if (actsChangedListener != null)
			actsChangedListener.clear();
	}
	
	
	@Transient
	private void notifyActsChanged ()
	{
		if (actsChangedListener != null)
		{
			for (ActsChangedListener l : actsChangedListener)
				l.actsChanged(this);
		}
	}
	
	
	public Invoice clone() {
		return this.clone(false);
	}
	
	public Invoice clone(boolean quiet) {
		Invoice newInvoice = (Invoice) super.clone(quiet);
		
		Set<Act> l_ClonedActs = new HashSet<Act>();
		if (m_Acts != null) {
			for (Act act : m_Acts) {
				l_ClonedActs.add((Act) act.clone(quiet));
			}			
		}
		newInvoice.setActs(l_ClonedActs);
		
		Set<Memo> l_ClonedMemos = new HashSet<Memo>();
		if (m_Memos != null) {
			for (Memo memo : m_Memos) {
				l_ClonedMemos.add((Memo) memo.clone(quiet));
			}			
		}
		newInvoice.setMemos(l_ClonedMemos);
		
		return newInvoice;
	}
	
	public String toString() {
		return getId() + " " + getInvoiceDate() + " " + getAmount() + " [" + InvoiceWorkflow.getInvoiceStateName(getState()) + " STM:" + getStatement() + "]";
	}



	
	
//---------------------------------------------------------------------------
	
//	/**
//	 * This is for testing. It is supposed to give an overview about what 
//	 * happens during the rule execution.
//	 * 
//	 * @param text The text to print
//	 */
//	@Transient
//	public static Boolean print (Object text)
//	{
//		if (!RulesObjectsHolder.PRINT_DEBUG_INFOS)
//			return Boolean.TRUE;
//		
//		logger.debug(text);
//		return Boolean.TRUE;
//	}
	
//***************************************************************************
//* End of Class															*
//***************************************************************************
}
