/*******************************************************************************
 * 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.util.Date;
import java.util.HashMap;
import java.util.TreeSet;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Transient;

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

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

/**
 * The Rate class represents the applicable rates for medical acts as defined
 * by the Nomenclature of the UCM (Union des Caisses de Maladies). A Rate is 
 * defined by the following properties: Every rate is defined by a unique code 
 * which clearly identifies it. A label provides a description of the rate. 
 * The monetary value of a rate is defined on one hand by its coefficient and
 * by the associated key value. The coefficient can only be changed by a review
 * of the nomenclature whereas the key value is linked to the inflation compensating
 * index. The monetary base value of a rate is obtained by multiplying the coefficient
 * and the key value. Rates are grouped in chapters and sections. These chapters and sections 
 * are referred to by the so called rate index.
 * @author nico.mack@tudor.lu
 * @since 06/04/19
 */

@Entity
@Table(name = "rate", schema = "billing")

@NamedQueries 
	({
	@NamedQuery(name = Rate.c_RateByCode, 		   			query = "SELECT OBJECT(o) FROM Rate o WHERE trim(upper(o.code)) = :code ORDER BY o.code, o.applicability DESC"),
	@NamedQuery(name = Rate.c_RatesByCodeFragment, 			query = "SELECT OBJECT(o) FROM Rate o WHERE upper(o.code) LIKE upper(:pattern) ORDER BY o.code, o.applicability DESC"),
	@NamedQuery(name = Rate.c_RateCountByKeyType, 			query = "SELECT COUNT(o)  FROM Rate o WHERE o.keyType = :keyType"),
	@NamedQuery(name = Rate.c_RateByCodeAndPerformedDate,	query = "SELECT OBJECT(o) FROM Rate o WHERE trim(upper(o.code)) = :code AND o.applicability <= :date ORDER BY o.applicability DESC")
	})

public class Rate extends GECAMedEntityBean implements Serializable 
	{
	private static final long serialVersionUID = 1L;

//	private KeyValue	m_KeyValue;
	private Integer		m_KeyType;
	private Integer		m_IndexId;
	private String		m_Code;
	private String		m_Label;
//	private Double		m_OldCoefficient;
	private Date		m_Applicability;
	private Double		m_Coefficient;
	private Integer		m_DefaultAdjustment;
	private Boolean		m_CAT;
	private Boolean  	m_CAC;
	private Boolean  	m_APCM;
	private Boolean  	m_ACM;

	private static transient Date m_Now;
	
//***************************************************************************
//* Constants                                                               *
//***************************************************************************	
	
	public static final transient String c_RateByCode 		   			= "getRateByCode";
	public static final transient String c_RatesByCodeFragment 			= "getRatesByCodeFragment";
	public static final transient String c_RateCountByKeyType 			= "getRateCountByKeyType";
	public static final transient String c_RateByCodeAndPerformedDate	= "getRateByCodeAndPerformedDate";
	
	public static transient HashMap<Integer, TreeSet<KeyValue>> c_KEYVALSSORTED = null;
	
//***************************************************************************
//* Constructor(s)                                                          *
//***************************************************************************	

public Rate ()
	{
	m_Code			= new String ();
	m_Label			= new String ();
	m_CAT			= Boolean.valueOf (false);
	m_CAC			= Boolean.valueOf (false);
	m_APCM			= Boolean.valueOf (false);
	m_ACM			= Boolean.valueOf (false);
	
//	m_OldCoefficient= Double.valueOf  (0d);
	m_Coefficient	= Double.valueOf  (0d);	
	m_Applicability = new Date ();
	}
	
//***************************************************************************
//* Primitives				                                                *
//***************************************************************************	

public static void initKeyValsSorted(HashMap<Integer, TreeSet<KeyValue>> sortedKeyVals) {
	c_KEYVALSSORTED = sortedKeyVals;
}

@Transient
public Date now ()
	{
	if (m_Now == null) 
		{
		m_Now = new Date ();
		}
	else
		{
		m_Now.setTime(System.currentTimeMillis());
		}

	return m_Now;
	}

////---------------------------------------------------------------------------
///**
// * Returns the coefficient associated with this rate
// * @param p_DateOfInterest specifies the date to get value of rate's coefficient
// * for. If p_DateOfInterest is null, method returns value of old coefficient
// * @return this rate's coefficient as its defined for the specified date
// */
////---------------------------------------------------------------------------
//
//@Transient
//public Double getCoefficient (Date p_DateOfInterest) 
//	{
//	if (p_DateOfInterest == null) return this.getOldCoefficient();
//	
//	if (p_DateOfInterest.before (this.getApplicability()))
//		 return this.getOldCoefficient();
//	else return this.getNewCoefficient();			
//	}

//---------------------------------------------------------------------------
/**
 * Returns the monetary value of this Rate. 
 * @return The monetary value of this rate.
 * @see #Act.monetize()
 */	
//---------------------------------------------------------------------------
public double monetize (KeyValue keyValue)
{	
	Act		l_Act;
	Date	l_Today; 	
	
	if (keyValue == null) {
		return Double.valueOf(0.0);
	}

	l_Act   = new Act ();
	l_Today = new Date ();

	l_Act.setPerformedDate	(l_Today);
	l_Act.setCode			(this.m_Code.toUpperCase());
	l_Act.setLabel			(this.m_Label);
	l_Act.setCAT			(this.m_CAT);
	l_Act.setCAC			(this.m_CAC);
	l_Act.setAPCM			(this.m_APCM);
	l_Act.setACM			(this.m_ACM);
	l_Act.setQuantity		(Integer.valueOf (1));
	l_Act.setKeyValue		(keyValue.getValue(), keyValue.getFractionDigits());
	l_Act.setCoefficient	(this.getCoefficient());
	l_Act.setAdjustment		(this.getDefaultAdjustment());
	
	return l_Act.monetize();
}


//public double monetize ()
//	{	
//   	Act		l_Act;
//	Date	l_Today; 	
//	
//	l_Act   = new Act ();
//   	l_Today = new Date ();
//
//   	l_Act.setPerformedDate(l_Today);
//	this.initializeAct(l_Act);
//   	
//	return l_Act.monetize();
//	}

////---------------------------------------------------------------------------
///**
// * Initializes the specified act using the properties of this rate.
// * @param p_Act specifies the act to initialize. Specified act should already
// * have its performed date set. If not, act is supposed to have been performed
// * today.
// */
////---------------------------------------------------------------------------
//
//public void initializeAct (Act p_Act)
//	{
//	Date	l_Now;
//	
//	l_Now = this.now();
//	
//	p_Act.setCode 		 (this.m_Code.toUpperCase());
//	p_Act.setLabel		 (this.m_Label);
//	p_Act.setCAT         (this.m_CAT);
//	p_Act.setCAC         (this.m_CAC);
//	p_Act.setAPCM        (this.m_APCM);
//	p_Act.setACM         (this.m_ACM);
//	p_Act.setQuantity    (Integer.valueOf (1));
//	
//	// init keyValue
//	if (this.m_KeyValue == null) {
//		
//	}
//	
//	if (this.m_KeyValue != null)
//		{
//		if (p_Act.getPerformedDate() == null) p_Act.setPerformedDate(l_Now);
//		
//		p_Act.setKeyValue (m_KeyValue.getValue (p_Act.getPerformedDate()));
//		p_Act.setCoefficient (this.getCoefficient (p_Act.getPerformedDate()));
//		}
//	}

//***************************************************************************
//* Getter and Setter Methods	                                            *
//***************************************************************************	
//---------------------------------------------------------------------------
///**
// * Returns the key value associated with this rate
// * @return rate key value
// */
////---------------------------------------------------------------------------
//
//@Transient
//public KeyValue getKeyValue() 
//	{
//	return m_KeyValue;
//	}
//
////---------------------------------------------------------------------------
///**
// * Sets this rate's key value
// * @param p_KeyValue
// */
////---------------------------------------------------------------------------
//
//@Transient
//public void setKeyValue (KeyValue p_KeyValue) 
//	{
//	m_KeyValue = p_KeyValue;
//	}


//---------------------------------------------------------------------------
/**
* Returns the key type associated with this rate
* @return rate key type
*/
//---------------------------------------------------------------------------

@Column(name = "key_type")
public Integer getKeyType() 
	{
	return m_KeyType;
	}

//---------------------------------------------------------------------------
/**
* Sets this rate's key type
* @param p_KeyType
*/
//---------------------------------------------------------------------------

public void setKeyType (Integer p_KeyType) 
	{
	m_KeyType = p_KeyType;
	}

//---------------------------------------------------------------------------
/**
 * Returns the ID of the rate index this rate belongs to
 * @return ID of the rate index entry this rate is part of
 */
//---------------------------------------------------------------------------

@javax.persistence.Column(name = "index_id")
public Integer getIndexId() 
	{
	return m_IndexId;
	}

//---------------------------------------------------------------------------
/**
 * Sets the ID of the rate index this rate should be part of.
 * @param p_IndexId specifies the ID of the rate index entry to link this
 * rate to.
 */
//---------------------------------------------------------------------------

public void setIndexId (Integer p_IndexId)
	{
	m_IndexId = p_IndexId;
	}

//---------------------------------------------------------------------------
/**
 * Returns the unique code associated with this rate
 * @return rate code
 */
//---------------------------------------------------------------------------

@Column (name ="code")

public String getCode() 
	{
	return m_Code;
	}

//---------------------------------------------------------------------------
/**
 * Sets this rate's unique code
 * @param p_Code specifies the new unique code for this rate
 */
//---------------------------------------------------------------------------

public void setCode(String p_Code) 
	{
	m_Code = p_Code;
	}

//---------------------------------------------------------------------------
/**
 * Returns the descriptive label of this rate
 * @return rate label
 */
//---------------------------------------------------------------------------

@Column (name ="label")

public String getLabel() 
	{
	return m_Label;
	}

//---------------------------------------------------------------------------
/**
 * Sets this rate's descriptive label
 * @param p_Label specifies the new descriptive label for this rate
 */
//---------------------------------------------------------------------------

public void setLabel(String p_Label) 
	{
	m_Label = p_Label;
	}

//---------------------------------------------------------------------------
/**
 * Returns the coefficient associated with this rate
 * @return rate coefficient
 */
//---------------------------------------------------------------------------

//@Column (name ="coefficient")
//
//public Double getCoefficient() 
//	{
//	return m_Coefficient;
//	}

//---------------------------------------------------------------------------
/**
 * Sets the value of this rate's coefficient
 * @param p_Coefficient specifies the new value for this rates coefficient.
 */
//---------------------------------------------------------------------------

//public void setCoefficient (Double p_Coefficient) 
//	{
//	m_Coefficient = p_Coefficient;
//	}

////---------------------------------------------------------------------------
///**
// * Returns the old coefficient associated with this rate, i.e the coefficient
// * that is to be applied before the applicability date.
// * @return old coefficient of rate
// */
////---------------------------------------------------------------------------
//
//@Column (name ="old_coefficient")
//
//public Double getOldCoefficient() 
//	{
//	return m_OldCoefficient;
//	}
//
////---------------------------------------------------------------------------
///**
// * Sets the value of this rate's old coefficient
// * @param p_OldCoefficient specifies the new value for this rates old coefficient.
// */
////---------------------------------------------------------------------------
//
//public void setOldCoefficient (Double p_OldCoefficient) 
//	{
//	m_OldCoefficient = p_OldCoefficient;
//	}

//---------------------------------------------------------------------------
/**
 * @return Returns the date as of which this rate's new coefficient value is 
 * applicable
 */
//---------------------------------------------------------------------------	
	
@Column (name ="applicability")

public Date getApplicability() 
	{
	return m_Applicability;
	}
	
//---------------------------------------------------------------------------
/**
 * Sets this key rate's application date for the new coefficient value
 * @param p_Applicability specifies the application date for rate's new 
 * coefficient value.
 */
//---------------------------------------------------------------------------

public void setApplicability (Date p_Applicability) 
	{
	m_Applicability = (p_Applicability != null) ? new Date (p_Applicability.getTime()) : null;
	}

//---------------------------------------------------------------------------
/**
 * Returns the coefficient associated with this rate, i.e the coefficient
 * that is to be applied as of applicability date.
 * @return new coefficient of rate
 */
//---------------------------------------------------------------------------

@Column (name ="coefficient")

public Double getCoefficient() 
	{
	return m_Coefficient;
	}

//---------------------------------------------------------------------------
/**
 * Sets the value of this rate's coefficient
 * @param p_Coefficient specifies the new value for this rates coefficient.
 */
//---------------------------------------------------------------------------

public void setCoefficient (Double p_NewCoefficient) 
	{
	m_Coefficient = p_NewCoefficient;
	}


/**
 * @return the m_DefaultAdjustment
 */
@Column(name = "default_adjustment")
public Integer getDefaultAdjustment ()
	{
	return m_DefaultAdjustment;
	}


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

//---------------------------------------------------------------------------
/**
 * Returns the state of the CAT (Cumulable A plein Tarif) flag of this rate
 * @return <b>true</b> if CAT is applicable, <b>false</b> otherwise
 */
//---------------------------------------------------------------------------

@Column (name ="cat")

public Boolean getCAT() 
	{
	return m_CAT;
	}

//---------------------------------------------------------------------------
/**
 * Sets set state of the CAT flag
 * @param p_CAT specifies state to set CAT flag to
 */
//---------------------------------------------------------------------------

public void setCAT(Boolean p_CAT) 
	{
	m_CAT = p_CAT;
	}

//---------------------------------------------------------------------------
/**
 * Returns the state of the CAC (Cumulable Avec Consultation) flag of this rate
 * @return <b>true</b> if CAC is applicable, <b>false</b> otherwise
 */
//---------------------------------------------------------------------------

@Column (name ="cac")

public Boolean getCAC () 
	{
	return m_CAC;
	}

//---------------------------------------------------------------------------
/**
 * Sets set state of the CAC flag
 * @param p_CAC specifies state to set CAC flag to
 */
//---------------------------------------------------------------------------

public void setCAC (Boolean p_CAC) 
	{
	m_CAC = p_CAC;
	}

//---------------------------------------------------------------------------
/**
 * Returns the state of the APCM (Accord Pr�alable du Conseil M�dical) flag of this rate
 * @return <b>true</b> if APCM is required, <b>false</b> otherwise
 */
//---------------------------------------------------------------------------

@Column (name ="apcm")

public Boolean getAPCM () 
	{
	return m_APCM;
	}

//---------------------------------------------------------------------------
/**
 * Sets set state of the APCM flag
 * @param p_APCM specifies state to set APCM flag to
 */
//---------------------------------------------------------------------------

public void setAPCM (Boolean p_APCM) 
	{
	m_APCM = p_APCM;
	}


//---------------------------------------------------------------------------
/**
 * Returns the state of the ACM (Accord du Conseil M�dical) flag of this rate
 * @return <b>true</b> if ACM is required, <b>false</b> otherwise
 */
//---------------------------------------------------------------------------

@Column (name ="acm")

public Boolean getACM () 
	{
	return m_ACM;
	}

//---------------------------------------------------------------------------
/**
 * Sets set state of the ACM flag
 * @param p_ACM specifies state to set ACM flag to
 */
//---------------------------------------------------------------------------

public void setACM (Boolean p_ACM) 
	{
	m_ACM = p_ACM;
	}

////---------------------------------------------------------------------------
///**
// * Returns the monetary value of this rate
// * @return Monetary value of this rate
// * @see Rate.monetize ()
// */
////---------------------------------------------------------------------------
//
//@Transient
//public Double getValue() 
//	{
//	return monetize();
//	}

//---------------------------------------------------------------------------
/**
 * Empty method to satisfy bean specifications of getter and setter pairs.
 * Calling the method has no effect.
 */
//---------------------------------------------------------------------------

@Transient
public void setValue(Double value) 
	{
	}


@Override
public String toString ()
{
	return new StringBuilder(getCode())
			.append(" - ")
			.append(GECAMedUtils.getDateFormatter("yyyy-MM-dd").format(getApplicability()))
			.toString();
}
//---------------------------------------------------------------------------
//***************************************************************************
//* End of Class															*
//***************************************************************************
}
