/*******************************************************************************
 * 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.session.beans;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.PostConstruct;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.NoResultException;
import javax.persistence.Query;

import lu.tudor.santec.gecamed.address.ejb.entity.beans.Country;
import lu.tudor.santec.gecamed.address.ejb.entity.beans.Locality;
import lu.tudor.santec.gecamed.address.ejb.entity.beans.Municipality;
import lu.tudor.santec.gecamed.address.ejb.session.interfaces.AddressManagerInterface;
import lu.tudor.santec.gecamed.address.utils.AddressFormatter;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Account;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Act;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Activity;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Bailiff;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.BailiffRate;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Invoice;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.InvoiceStub;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Settlement;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Statement;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Transaction;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.AccountingInterface;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.BillingPrinterInterface;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.InvoiceInterface;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.SettlementInterface;
import lu.tudor.santec.gecamed.billing.utils.ActReportField;
import lu.tudor.santec.gecamed.billing.utils.BillingAdminSettings;
import lu.tudor.santec.gecamed.billing.utils.InvoiceReportField;
import lu.tudor.santec.gecamed.billing.utils.InvoiceWorkflow;
import lu.tudor.santec.gecamed.billing.utils.StatementReportField;
import lu.tudor.santec.gecamed.billing.utils.TimeSpan;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.Template;
import lu.tudor.santec.gecamed.core.ejb.session.beans.GECAMedSessionBean;
import lu.tudor.santec.gecamed.core.ejb.session.interfaces.ListManagerInterface;
import lu.tudor.santec.gecamed.core.ejb.session.interfaces.TemplateManagerInterface;
import lu.tudor.santec.gecamed.core.utils.AccidentNumberFormatter;
import lu.tudor.santec.gecamed.core.utils.JasperTemplateBean;
import lu.tudor.santec.gecamed.core.utils.PrintParameter;
import lu.tudor.santec.gecamed.core.utils.printing.ireport.UtilFormatter;
import lu.tudor.santec.gecamed.core.utils.printing.ireport.UtilSettings;
import lu.tudor.santec.gecamed.core.utils.querybuilder.Group;
import lu.tudor.santec.gecamed.core.utils.querybuilder.HibernateCondition;
import lu.tudor.santec.gecamed.core.utils.querybuilder.HibernateOperator;
import lu.tudor.santec.gecamed.core.utils.querybuilder.HibernateProperty;
import lu.tudor.santec.gecamed.core.utils.querybuilder.HibernateQueryFactory;
import lu.tudor.santec.gecamed.core.utils.querybuilder.WhereClause;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Office;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.office.ejb.session.interfaces.OfficeManagerInterface;
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.patient.ejb.entity.beans.PatientAddress;
import lu.tudor.santec.gecamed.patient.utils.PatientNameFormatter;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface;
import lu.tudor.santec.i18n.Relocalizable;
import lu.tudor.santec.i18n.Translatrix;
import lu.tudor.santec.numberwriter.NumberWriter;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;
import net.sf.jasperreports.engine.JRPrintPage;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.query.JRJpaQueryExecuterFactory;

import org.apache.log4j.Level;

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

@Remote( { BillingPrinterInterface.class })
@Stateless
public class BillingPrinterBean extends GECAMedSessionBean implements
	BillingPrinterInterface, Relocalizable {
    @EJB
    InvoiceInterface m_InvoiceInterface;

    @EJB
    TemplateManagerInterface m_TemplateManager;

    @EJB
    OfficeManagerInterface m_OfficeManager;

    @EJB
    LoginInterface m_LoginBean;

    @EJB
    SettlementInterface m_SettlementBean;

    @EJB
    AccountingInterface m_AccountingBean;
    
    @EJB
    AddressManagerInterface m_AddressManager;
    
    @EJB
    ListManagerInterface m_ListManager;
    
    private DateFormat m_DateFormat = null;

    private NumberFormat m_NumberFormat = null;

    private Office m_MedicalOffice = null;

    private Collection<BailiffRate> m_BailiffRates = null;

    private Collection<Settlement> m_Settlements = null;

    private Collection<GecamedUser> m_Users = null;

    private HashMap<Integer, GecamedUser> m_UserLookup = null;

//    private Collection<Physician> m_Physicians = null;

    private HashMap<Integer, String> m_PhysicianLookup = null;

    private List<Account> m_Accounts = null;

    private HashMap<Integer, String> m_InvoiceStates = null;

    private Boolean m_MaidenIsMarriedName = null;

    private Boolean m_SplitBilling = null;

    private Boolean m_ShortInvoiceNumbers = null;

    private Boolean m_UseLeadingZeros = null;

    private Integer m_AddressStyle = null;

    private static HashMap <String,JasperReport> m_CompiledReports;
    
    
    // ***************************************************************************
    // * Constants *
    // ***************************************************************************
    
    public static final int c_PrintInvoice = 0;
    
    public static final int c_PrintFirstNotice = 1;

    public static final int c_PrintLastNotice = 2;
    
    public static final int c_PrintPaymentOrder = 3;
    
    public final static String c_FirstNoticeTemplateType = "first_notice";
    
    public final static String c_SecondNoticeTemplateType = "second_notice";
    
    public static final String c_NotAvailable = "inconnu";

    public static final String c_CRLF = "\r\n";

    private static final int c_AllSettlements = 0;

    private static final int c_OnlyPayments = 1;

    private static final int c_OnlyTransfers = 2;

//    private final static String c_InvoiceTemplateName = "invoice";
//
//    private final static String c_DemandOfPaymentTemplateName = "payment_order";
//
//    private final static String c_ThirdPartyStatementTemplateName = "3rd_party_stmnt";
//
//    /**
//     * the standard packaged templates
//     */
//
////    private final static String TEMPLATE_PATH = "/lu/tudor/santec/gecamed/billing/templates/";
//
//    private final static String c_InvoiceTemplate = "invoice_single_doctor.jrxml";
//
//    private final static String c_FirstNoticeTemplateFileName = "first_reminder.jrxml";
//
//    private final static String c_SecondNoticeTemplateFileName = "second_reminder.jrxml";
//
//    private final static String c_DemandOfPaymentTemplate = "payment_order.jrxml";
//
//    private final static String c_ReminderList = "reminder_list.jrxml";
//
//    private final static String c_InvoiceList = "invoice_list.jrxml";
//
//    private final static String c_StatementCover = "statement_cover.jrxml";
//
//    private final static String c_StatementList = "statement_list.jrxml";
//
//    private final static String c_ActivityList = "activity_list.jrxml";
//
//    private final static String c_TransactionList = "transaction_list.jrxml";
//
//    private final static String c_IssuedInvoiceList = "issued_invoice_list.jrxml";
    
    private final static String[] c_ImportantReportFields = new String[] {"invoiceNumber", "formatedDate", "balance"};


    private static Pattern
    	c_ZipPattern = Pattern.compile("(\\d{4})$", Pattern.CASE_INSENSITIVE);

    static 
    	{
    	Translatrix.loadSupportedLocales("lu.tudor.santec.gecamed.billing.utils.resources.supportedLocales");
    	Translatrix.addBundle("lu.tudor.santec.gecamed.billing.utils.resources.ServerResources");
    	}

	private UtilFormatter m_Formatter;

	private HashMap<Integer, String> m_InsuranceLookup;
    
    
//***************************************************************************
//* Constructor(s) 															*
//***************************************************************************
//---------------------------------------------------------------------------
/**
 * The postConstruct method is an EJB life cycle callback method. The method
 * will be invoked after the class has been instantiated.
 */
//---------------------------------------------------------------------------

@PostConstruct
public void postConstruct() 
	{
	// super.postConstruct();

	if (m_DateFormat == null)
	    m_DateFormat = new SimpleDateFormat("dd/MM/yyyy", Translatrix.getLocale());

	if (m_NumberFormat == null) 
		{
	    m_NumberFormat = NumberFormat.getNumberInstance();
	    m_NumberFormat.setMaximumFractionDigits(2);
	    m_NumberFormat.setMinimumFractionDigits(2);
		}

	if (m_CompiledReports == null)
		m_CompiledReports = new HashMap <String,JasperReport> ();
	
	m_Formatter = new UtilFormatter (m_AddressManager);
	m_Formatter.initTranslations();
	
	this.relocalize();
    }

//***************************************************************************
//* Class Primitives 														*
//***************************************************************************
//---------------------------------------------------------------------------
/**
 * parse the specified 4 digit ZIP code string an returns it as an Integer.
 * 
 * @param p_ZIP specifies the zip code as a string.
 * @return the specified ZIP code as an integer if specified ZIP code string
 *         could be parsed, <code>0</code> otherwise.
 */
//---------------------------------------------------------------------------

private Integer parseZipCode(String p_ZIP) 
	{
	Integer l_ZipCode;
	Matcher l_ZipMatcher;

	l_ZipCode = Integer.valueOf(0);
	l_ZipMatcher = c_ZipPattern.matcher(p_ZIP);

	if (l_ZipMatcher.matches()) {
	    try {
		l_ZipCode = Integer.parseInt(l_ZipMatcher.group(1));
	    } catch (NumberFormatException p_Exception) {
		l_ZipCode = Integer.valueOf(0);
	    }
	}
	return l_ZipCode;
    }

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

private Collection<Transaction> filterEffectiveTransactions( Collection<Transaction> p_Transactions) 
	{
	ArrayList<Transaction> l_Transactions;
	Transaction l_Transaction;
	Transaction l_Candidate;
	int l_CurrentIndex;
	int l_LookAheadIndex;
	boolean l_Break = false;

	if (p_Transactions == null) return null;

	l_Transactions = new ArrayList<Transaction>();
	l_Transactions.addAll(p_Transactions);

	for (l_CurrentIndex = 0; l_CurrentIndex < l_Transactions.size(); l_CurrentIndex++) 
		{
	    l_Transaction = l_Transactions.get(l_CurrentIndex);
	    l_Break = false;
	    for (l_LookAheadIndex = l_CurrentIndex + 1; (l_LookAheadIndex < l_Transactions.size())&& !l_Break; l_LookAheadIndex++) 
	    	{
	    	l_Candidate = l_Transactions.get(l_LookAheadIndex);
	    	if (   (l_Candidate.getSettlementId().equals(l_Transaction.getSettlementId()))
	    		&& (l_Candidate.getSettlementDate().equals(l_Transaction.getSettlementDate()))) 
	    		{
	    		if (l_Transaction.canceledBy(l_Candidate)) 
	    			{
	    			l_Transactions.remove(l_LookAheadIndex--);
	    			l_Transactions.remove(l_CurrentIndex--);
	    			l_Break = true;
	    			}
	    		} 
	    	else l_Break = true;
	    	}
		}
	
	return l_Transactions;
    }

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

private JasperReport getStandardReport (String p_TemplateBeanName)
	{
	return m_TemplateManager.findTemplate(p_TemplateBeanName);
//	JasperReport 	l_Report = null;
//	JasperDesign	l_Design;
//	String			l_Path;
//	
//	if (m_CompiledReports.containsKey(p_ReportFile))
//		{
//		l_Report = m_CompiledReports.get(p_ReportFile);
//		}
//	else
//		{
//		l_Path = TEMPLATE_PATH + p_ReportFile;
//		
//		try	{
//			l_Design = (JasperDesign)JRXmlLoader.load(BillingPrinterBean.class.getResourceAsStream(l_Path));
//			if (l_Design != null)
//				{
//				l_Report = m_TemplateManager.compileReport(l_Design);
//				m_CompiledReports.put(p_ReportFile, l_Report);
//				}
//			}
//		catch (JRException p_Exception)
//			{
//			this.log(Level.FATAL, "Failed to load template " + l_Path,p_Exception);
//			}
//		catch (Exception p_Exception)
//			{
//			this.log(Level.FATAL, "Failed to compile template " + l_Path,p_Exception);
//			}
//		}	
//	
//	return l_Report;
	}

//---------------------------------------------------------------------------
//===========================================================================
//= Fetcher Methods
//===========================================================================
//---------------------------------------------------------------------------
/**
 * Fetches the medical office from the database.
 * 
 * @return The medical office defined in the database, <code>null</code> if
 *         none could be found or if an error occured.
 */
//---------------------------------------------------------------------------

private Office fetchMedicalOffice() 
	{
	Office l_MedicalOffice = null;

	try {
		l_MedicalOffice = m_OfficeManager.getOffice(Integer.valueOf(1));
		}
	catch (NoResultException p_Exception) 
		{
	    l_MedicalOffice = null;
		}
	catch (Exception p_Exception) 
		{
	    l_MedicalOffice = null;
	    this.log(Level.ERROR, "Failed to fetch Medical Office!",p_Exception);
		}

	return l_MedicalOffice;
    }

//---------------------------------------------------------------------------
/**
 * Fetches all bailiff rates from the database.
 * 
 * @return A collection holding all bailiff rates defined in the database,
 *         <code>null</code> if none could be found or if an error occured.
 */
//---------------------------------------------------------------------------

@SuppressWarnings("unchecked")
private Collection<BailiffRate> fetchBailiffRates() 
	{
	Collection<BailiffRate> l_BailiffRates = null;

	try {
	    l_BailiffRates = m_EntityManager.createNamedQuery(BailiffRate.c_AllBailiffRates).getResultList();
		} 
	catch (NoResultException p_Exception) 
		{
	    l_BailiffRates = null;
		} 
	catch (Exception p_Exception) 
		{
	    l_BailiffRates = null;
	    this.log(Level.ERROR, "Failed to fetch Bailiff Rates!",p_Exception);
		}

	return l_BailiffRates;
    }

//---------------------------------------------------------------------------
/**
 * Fetches all bank accounts from the database.
 * 
 * @return A collection holding all bank accounts defined in the database,
 *         <code>null</code> if none could be found or if an error occured.
 */
//---------------------------------------------------------------------------

@SuppressWarnings("unchecked")
private List<Account> fetchAccounts() 
	{
	List<Account> l_Accounts = null;

	try {
	    l_Accounts = m_EntityManager.createNamedQuery(Account.c_AllActiveAccounts).getResultList();
		} 
	catch (NoResultException p_Exception) 
		{
	    l_Accounts = null;
		} 
	catch (Exception p_Exception) 
		{
	    this.log(Level.ERROR, "Failed to fetch Accounts!", p_Exception);
		}

	return l_Accounts;
    }

//---------------------------------------------------------------------------
/**
 * Fetches all settlement methods from the database.
 * 
 * @return A collection holding all settlement methods defined in the
 *         database, <code>null</code> if none could be found or if an error
 *         occured.
 */
//---------------------------------------------------------------------------

private Collection<Settlement> fetchSettlements() 
	{
	Collection<Settlement> l_Settlements = null;

	try {
	    l_Settlements = m_SettlementBean.getAllSettlements();
		} 
	catch (NoResultException p_Exception) 
		{
	    l_Settlements = null;
		} 
	catch (Exception p_Exception) 
		{
	    this.log(Level.ERROR, "Failed to fetch Settlement Methods!",p_Exception);
		}

	return l_Settlements;
    }

//---------------------------------------------------------------------------
/**
 * Fetches all physicians from the database.
 * 
 * @return A collection holding all physicians defined in the database,
 *         <code>null</code> if none could be found or if an error occured.
 */
//---------------------------------------------------------------------------

//private Collection<Physician> fetchPhysicians() 
//	{
//	Collection<Physician> l_Physicians = null;
//
//	try {
////	    l_Physicians = m_OfficeManager.getAllPhysicians();
//		l_Physicians = m_ListManager.getListReference(Physician.class);
//		}
//	catch (NoResultException p_Exception) 
//		{
//	    l_Physicians = null;
//		} 
//	catch (Exception p_Exception) 
//		{
//	    this.log(Level.ERROR, "Failed to fetch Physicians!",p_Exception);
//		}
//
//	return l_Physicians;
//    }

//---------------------------------------------------------------------------
/**
 * Fetches all users from the database.
 * 
 * @return A collection holding all users defined in the database,
 *         <code>null</code> if none could be found or if an error occured.
 */
//---------------------------------------------------------------------------

private Collection<GecamedUser> fetchUsers() 
	{
	Collection<GecamedUser> l_Users = null;

	try {
	    l_Users = m_LoginBean.getAllUsers();
		} 
	catch (NoResultException p_Exception) 
		{
	    l_Users = null;
		} 
	catch (Exception p_Exception) 
		{
	    this.log(Level.ERROR, "Failed to fetch Users!", p_Exception);
		}

	return l_Users;
    }

//---------------------------------------------------------------------------
/**
 * Fetches (lazy) patient data for specified invoice.
 * 
 * @param p_Invoice
 *            specifies the invoice to fetch lazy patient data for.
 * @return the specified invoice having its patient property properly set.
 */
//---------------------------------------------------------------------------

private Invoice fetchPatientForInvoice (Invoice p_Invoice) throws Exception 
	{
	if (p_Invoice == null) return null;

	p_Invoice = m_InvoiceInterface.fetchPatientForInvoice(p_Invoice);

	return p_Invoice;
    }


//---------------------------------------------------------------------------
/**
* Fetches the proper bailiff for the specified invoice. The jurisdiction of
* the Bailiff to execute demand of payment depends on the municipality of
* the billing address specified for the invoice. The method tries various
* strategies to determine the proper bailiff.
* 
* @param patient
*            specifies the invoice to get correct bailiff for.
* @return the correct bailiffs name for the specified invoice if municipality<code>null</code> otherwise.
*/
//---------------------------------------------------------------------------

public String getBailiffForPatient(Patient patient, boolean returnCountryIfForeigner) throws Exception 
	{
	PatientAddress l_BillingAddress;
	Locality l_Locality;
	Municipality l_Municipality;
	Bailiff l_Bailiff = null;

	if ((patient == null)) return null;

	// ====================================================================
	// = Retrieve billing address from invoice. If invoice doesn't have
	// = a billing address, then we're using home address of patient. If
	// = patient doesn't have a home address either, we give up.
	// ====================================================================
	
	l_BillingAddress = patient.getBillingAddress();
	if (l_BillingAddress == null)
		l_BillingAddress = patient.getHomeAddress();
	
	if (l_BillingAddress == null) return null;
	
	// foreigner.....
	if (! Country.LUXEMBOURG.equals(l_BillingAddress.getCountry())) {
    	if (returnCountryIfForeigner) {
    		return " " + m_Formatter.translateCountry(l_BillingAddress.getCountry());
    	} else {
    		return null;	    		
    	}
	}

	try {

	    // ====================================================================
	    // = If billing address does not specify a precise locality, we're
	    // = trying to look it up. First attempt will be to use name of locality
	    // = and specified ZIP code. If this attempt fails, we're trying to
	    // = lookup locality by name only. If this fails to, we're resorting to
	    // = looking up locality by zip code only. If this fails to, we give up.
	    // ====================================================================

	    if (l_BillingAddress.getLocalityId() == null) 
	    	{
	    	l_Locality = this.fetchLocalityByNameAndZip(l_BillingAddress.getLocality(), l_BillingAddress.getZip());
	    	
	    	if (l_Locality == null) l_Locality = this.fetchLocalityByNameAndZip(l_BillingAddress.getLocality(), null);
	    	if (l_Locality == null) l_Locality = this.fetchLocalityByNameAndZip(null,l_BillingAddress.getZip());
	    	} 
	    else 
	    	{
	    	l_Locality = (Locality) m_EntityManager.find(Locality.class,l_BillingAddress.getLocalityId());
	    	}

	    if (l_Locality == null) {
	    	if (returnCountryIfForeigner) {
	    		return " " + m_Formatter.translateCountry(l_BillingAddress.getCountry());
	    	} else {
	    		return null;	    		
	    	}
	    }

	    // ====================================================================
	    // = Once we have the proper locality, we can look for the municipality
	    // = it is part of.
	    // ====================================================================

	    l_Municipality = m_EntityManager.find(Municipality.class,l_Locality.getMunicipalityId());

	    if (l_Municipality == null) {
	    	if (returnCountryIfForeigner) {
	    		return " " + m_Formatter.translateCountry(l_BillingAddress.getCountry());
	    	} else {
	    		return null;	    		
	    	}	    	
	    }

	    // ====================================================================
	    // = Using the municipality we may no fetch the bailiff whose jurisdiction
	    // = includes the found municipality.
	    // ====================================================================

	    l_Bailiff = (Bailiff) m_EntityManager.createNamedQuery(Bailiff.c_BailiffByMunicipality).setParameter("municipality", l_Municipality).getSingleResult();
		} 
	catch (NoResultException p_Exception) 
		{
	    l_Bailiff = null;
		} 
	catch (Exception p_Exception) 
		{
	    l_Bailiff = null;
	    this.log(Level.ERROR, "Failed to fetch Bailiff for patient " + patient, p_Exception);
		}
	
	if (l_Bailiff == null) {
		if (returnCountryIfForeigner) {
    		return " " + m_Formatter.translateCountry(l_BillingAddress.getCountry());
    	} else {
    		return null;	    		
    	}
	}

	return l_Bailiff.getName();
  }


//---------------------------------------------------------------------------
/**
 * Fetches the proper bailiff for the specified invoice. The jurisdiction of
 * the Bailiff to execute demand of payment depends on the municipality of
 * the billing address specified for the invoice. The method tries various
 * strategies to determine the proper bailiff.
 * 
 * @param p_Invoice
 *            specifies the invoice to get correct bailiff for.
 * @return the correct bailiff for the specified invoice if municipality of
 *         billing address can be determined, <code>null</code> otherwise.
 */
//---------------------------------------------------------------------------

public Bailiff fetchBailiffForInvoice(Invoice p_Invoice) throws Exception 
	{
	PatientAddress l_BillingAddress;
	Locality l_Locality;
	Municipality l_Municipality;
	Bailiff l_Bailiff = null;

	if ((p_Invoice == null) || (p_Invoice.getPatient() == null)) return null;

	try {
	    // ====================================================================
	    // = Retrieve billing address from invoice. If invoice doesn't have
	    // = a billing address, then we're using home address of patient. If
	    // = patient doesn't have a home address either, we give up.
	    // ====================================================================

	    l_BillingAddress = p_Invoice.getPatient().getBillingAddress();
	    if (l_BillingAddress == null)
		l_BillingAddress = p_Invoice.getPatient().getHomeAddress();

	    if (l_BillingAddress == null) return null;
	    
		// foreigner.....
		if (! Country.LUXEMBOURG.equals(l_BillingAddress.getCountry())) {
	    		return null;	    		
		}

	    // ====================================================================
	    // = If billing address does not specify a precise locality, we're
	    // = trying to look it up. First attempt will be to use name of locality
	    // = and specified ZIP code. If this attempt fails, we're trying to
	    // = lookup locality by name only. If this fails to, we're resorting to
	    // = looking up locality by zip code only. If this fails to, we give up.
	    // ====================================================================

	    if (l_BillingAddress.getLocalityId() == null) 
	    	{
	    	l_Locality = this.fetchLocalityByNameAndZip(l_BillingAddress.getLocality(), l_BillingAddress.getZip());
	    	
	    	if (l_Locality == null) l_Locality = this.fetchLocalityByNameAndZip(l_BillingAddress.getLocality(), null);
	    	if (l_Locality == null) l_Locality = this.fetchLocalityByNameAndZip(null,l_BillingAddress.getZip());
	    	} 
	    else 
	    	{
	    	l_Locality = (Locality) m_EntityManager.find(Locality.class,l_BillingAddress.getLocalityId());
	    	}

	    if (l_Locality == null) return null;

	    // ====================================================================
	    // = Once we have the proper locality, we can look for the municipality
	    // = it is part of.
	    // ====================================================================

	    l_Municipality = m_EntityManager.find(Municipality.class,l_Locality.getMunicipalityId());

	    if (l_Municipality == null) return null;

	    // ====================================================================
	    // = Using the municipality we may no fetch the bailiff whose jurisdiction
	    // = includes the found municipality.
	    // ====================================================================

	    l_Bailiff = (Bailiff) m_EntityManager.createNamedQuery(Bailiff.c_BailiffByMunicipality).setParameter("municipality", l_Municipality).getSingleResult();
		} 
	catch (NoResultException p_Exception) 
		{
	    l_Bailiff = null;
		} 
	catch (Exception p_Exception) 
		{
	    l_Bailiff = null;
	    this.log(Level.ERROR, "Failed to fetch Bailiff for invoice " + p_Invoice.formatInvoiceNumber(false, true), p_Exception);
		}

	return l_Bailiff;
    }

// ---------------------------------------------------------------------------
/**
 * Fetches a locality either by name, by zip code or by both.
 * 
 * @param p_Name specifies the name of the locality to fetch. Specify
 *        <code>null</code> if you want to ignore name.
 * @param p_ZIP specifies the zip code of the locality to fetch. Specify
 *        <code>null</code> if you want to ignore zip.
 * @return the locality matching specified name and/or specified zip code.
 *         Returns <code>null</code> if non can be found or if an error
 *         occured.
 */
// ---------------------------------------------------------------------------

private Locality fetchLocalityByNameAndZip (String p_Name, String p_ZIP) 
	{
	String l_QueryString;
	Query l_Query;
	Locality l_Locality;
	WhereClause l_WhereClause;
	HibernateCondition l_Condition;

	Group l_ZipGroup;
	HibernateProperty l_LocalityIdProperty;

	if ((p_Name == null) && (p_ZIP == null)) return null;

	l_QueryString = "SELECT DISTINCT OBJECT(o) FROM Locality o";

	l_WhereClause = new WhereClause();
	l_WhereClause.setOperator(HibernateOperator.c_AndOperator);

	// ========================================================================
	// = Include locality name in query if a name was specified.
	// ========================================================================

	if (p_Name != null) 
		{
	    l_Condition = new HibernateCondition("name",HibernateOperator.c_EqualOperator, "localityName", p_Name);
	    l_Condition.setCaseSensitive(false);
	    l_WhereClause.addCondition(l_Condition);
		}

	// ========================================================================
	// = Include zip code in query if a zip was specified.
	// ========================================================================

	if (p_ZIP != null) 
		{
	    l_QueryString += ", Zip z";

	    l_ZipGroup = new Group();
	    l_ZipGroup.setOperator(HibernateOperator.c_AndOperator);

	    l_Condition = new HibernateCondition("zip",HibernateOperator.c_EqualOperator, "zipCode", this.parseZipCode(p_ZIP));
	    l_Condition.setEntity("z");
	    l_ZipGroup.addCondition(l_Condition);

	    l_LocalityIdProperty = new HibernateProperty("id");

	    l_Condition = new HibernateCondition("localityId",HibernateOperator.c_EqualOperator, l_LocalityIdProperty);
	    l_Condition.setEntity("z");
	    l_ZipGroup.addCondition(l_Condition);

	    l_WhereClause.addGroup(l_ZipGroup);
		}

	// ========================================================================
	// = Execute the query
	// ========================================================================

	try {
	    l_Query = HibernateQueryFactory.buildQueryFromWhereClause(m_EntityManager, l_QueryString, l_WhereClause);
	    l_Query.setMaxResults(1);

	    l_Locality = (Locality) l_Query.getSingleResult();
		} 
	catch (NoResultException p_Exception) 
		{
	    l_Locality = null;
		} 
	catch (Exception p_Exception) 
		{
	    this.log(Level.ERROR, "Error while fetch Locality by Name And/Or Zip!",p_Exception);
	    l_Locality = null;
		}

	return l_Locality;
    }

// ---------------------------------------------------------------------------
/**
 * Returns a list of executed transactions for the specified physician,
 * executed during the specified period and using the specified settlement
 * methods.
 * 
 * @param p_Physician
 *            specifies the physician to get transactions for, i.e.
 *            transactions are limited to invoices issued for the specified
 *            physician.
 * @param p_FromDate
 *            specifies the start date of period that transaction's
 *            settlement date has to comply with to be taken into account.
 * @param p_UntilDate
 *            specifies the end date of period that transaction's settlement
 *            date has to comply with to be taken into account.
 * @param p_Cashier
 *            specifies the cashier you want to get transactions of.
 *            Specifiy <code>null</code> to ignore cashier
 * @param p_Settlements
 *            specifies the accepted settlement methods for transactions to
 *            be taken into account.
 * @param p_EffectiveTransactions
 *            specifies whether the method should return all executed
 *            transactions or only those that are effective. Effective
 *            transactions exclude transactions which credit and debit the
 *            same amount, using the same settlement method and date.
 * @return A collection holding all transactions matching the specified
 *         criteria, <code>null</code> if non can be found.
 */
// ---------------------------------------------------------------------------

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
private Collection<Transaction> fetchTransactionsForPhysician( Physician p_Physician, Date p_FromDate, Date p_UntilDate,
	    													   GecamedUser p_Cashier, HashMap<Integer, Settlement> p_Settlements) 
	{
	Collection<Transaction> l_Transactions = null;

	try {
	    l_Transactions = m_AccountingBean.getTransactionsForPhysician(p_Physician, p_FromDate, p_UntilDate, 
	    															  p_Cashier, this.getSettlementIDs(p_Settlements));
		} 
	catch (Exception p_Exception) 
		{
	    this.log(Level.ERROR,"Failed to fetch Transactions for Physician!", p_Exception);
		}

	return l_Transactions;
    }

// ---------------------------------------------------------------------------
/**
 * Returns a list of executed transactions for the whole office, executed
 * during the specified period and using the specified settlement methods.
 * 
 * @param p_FromDate
 *            specifies the start date of period that transaction's
 *            settlement date has to comply with to be taken into account.
 * @param p_UntilDate
 *            specifies the end date of period that transaction's settlement
 *            date has to comply with to be taken into account.
 * @param p_Cashier
 *            specifies the cashier you want to get transactions of.
 *            Specifiy <code>null</code> to ignore cashier
 * @param p_Settlements
 *            specifies the accepted settlement methods for transactions to
 *            be taken into account.
 * @param p_EffectiveTransactions
 *            specifies whether the method should return all executed
 *            transactions or only those that are effective. Effective
 *            transactions exclude transactions which credit and debit the
 *            same amount, using the same settlement method and date.
 *            transactions to be taken into account.
 * @return A collection holding all transactions matching the specified
 *         criteria, <code>null</code> if non can be found.
 */
// ---------------------------------------------------------------------------

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
private Collection<Transaction> fetchTransactionsForOffice(Date p_FromDate, Date p_UntilDate, GecamedUser p_Cashier,
	    												   HashMap<Integer, Settlement> p_Settlements) 
	{
	Collection<Transaction> l_Transactions = null;

	try {
	    l_Transactions = m_AccountingBean.getTransactionsForOffice( p_FromDate, p_UntilDate, p_Cashier, this.getSettlementIDs(p_Settlements));
		} 
	catch (Exception p_Exception) 
		{
	    this.log(Level.ERROR,"Failed to fetch Transactions for Office!", p_Exception);
		}

	return l_Transactions;
    }

//===========================================================================
//= Getter Methods
//===========================================================================
// ---------------------------------------------------------------------------
/**
 * Returns cached instance of medical office. If cached instance does not
 * exist yet, the method fetches and initializes cached instance first.
 * 
 * @return the cached instance of medical office.
 */
// ---------------------------------------------------------------------------

private Office getMedicalOffice() 
	{
	if (m_MedicalOffice == null) m_MedicalOffice = this.fetchMedicalOffice();

	return m_MedicalOffice;
    }



private String getOfficeUCM(Office o, Physician p_Physician) {
	String ucm = null;
	if (o != null) {
		if (o.getUcmCode() != null && ! Physician.UCM_DEFAULT.equals(o.getUcmCode())) {
			ucm = o.getUcmCode();
		}
	}
	
	if (ucm == null) {
		ucm = getPhysicianUCM(p_Physician);
	}
	
	return ucm;
	
}

//---------------------------------------------------------------------------
/**
 * Returns cached instance of medical office. If cached instance does not
 * exist yet, the method fetches and initializes cached instance first.
 * 
 * @return the cached instance of medical office.
 */
//---------------------------------------------------------------------------

//private Collection<Physician> getPhysicians() 
//	{
//	if (m_Physicians == null) m_Physicians = this.fetchPhysicians();
//	
//	return m_Physicians;
//    }

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

private String getPhysicianUCM(Physician p_Physician) 
	{
	String l_PhysicianUCM = Physician.UCM_DEFAULT;

	if (p_Physician != null) 
		{
	    if ((p_Physician.getUcmFacturation() != null) && (!Physician.UCM_DEFAULT.equals(p_Physician.getUcmFacturation()))) 
	    	{
	    	l_PhysicianUCM = p_Physician.getUcmFacturation();
	    	} 
	    else if (p_Physician.getUcmCode() != null) 
	    	{
	    	l_PhysicianUCM = p_Physician.getUcmCode();
	    	}
		}

	return l_PhysicianUCM;
    }

//---------------------------------------------------------------------------
/**
 * Returns cached instance of all accounts. If cached instance does not
 * exist yet, the method fetches and initializes cached instance first.
 * 
 * @return the cached instance of all accounts.
 */
//---------------------------------------------------------------------------

public List<Account> getAccounts() 
	{
	if (m_Accounts == null) m_Accounts = this.fetchAccounts();

	return m_Accounts;
    }

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

public List<Account> getAccounts (Physician p_Physician)
	{
	List<Account>	l_AllAccounts		= getAccounts();
	List<Account>	l_PhysicianAccounts	= new ArrayList<Account>(l_AllAccounts.size());
	
	for (Account l_Account : l_AllAccounts)
		if (l_Account.getHolder() == null
				|| (p_Physician != null
				&& 	l_Account.getHolder().equals(p_Physician)))
			/* only those accounts, that are for p_Physician or,
			 * if p_Physician is null, all where holder is null
			 */
			l_PhysicianAccounts.add(l_Account);
	
	return l_PhysicianAccounts;
	}

//---------------------------------------------------------------------------
/**
 * Returns cached instance of all bailiff rates. If cached instance does not
 * exist yet, the method fetches and initializes cached instance first.
 * 
 * @return the cached instance of all bailiff rates.
 */
//---------------------------------------------------------------------------

public Collection<BailiffRate> getBailiffRates() 
	{
	if (m_BailiffRates == null) m_BailiffRates = this.fetchBailiffRates();

	return m_BailiffRates;
    }

//---------------------------------------------------------------------------
/**
 * Returns cached instance of all settlement methods. If cached instance
 * does not exist yet, the method fetches and initializes cached instance
 * first.
 * 
 * @return the cached instance of all settlement methods.
 */
//---------------------------------------------------------------------------

private Collection<Settlement> getSettlements() 
	{
	if (m_Settlements == null) m_Settlements = this.fetchSettlements();

	return m_Settlements;
    }

//---------------------------------------------------------------------------
/**
 * Method returns the applicable bailiff rate for the specified invoice.
 * 
 * @param p_Invoice
 *            specifies the invoice to get bailiff rate for.
 */
//---------------------------------------------------------------------------

public double getBailiffRateForInvoice(Invoice p_Invoice) throws Exception 
	{
	double l_Rate = 0.0f;
	Collection<BailiffRate> l_BailiffRates;
	Iterator<BailiffRate> l_RateIterator;
	BailiffRate l_BailiffRate;

	if (p_Invoice == null) return l_Rate;

	l_BailiffRates = this.getBailiffRates();
	if (l_BailiffRates != null) 
		{
	    l_RateIterator = l_BailiffRates.iterator();
	    while ((l_RateIterator.hasNext() && l_Rate == 0)) 
	    	{
	    	l_BailiffRate = l_RateIterator.next();
	    	if (p_Invoice.getBalance() < l_BailiffRate.getLowerThreshold()) continue;

	    	if (	(l_BailiffRate.getUpperThreshold() > 0) 
	    		&& (p_Invoice.getBalance() > l_BailiffRate .getUpperThreshold())) continue;

	    	l_Rate = l_BailiffRate.getRate();
	    	}
		}

	return l_Rate;
    }

// ---------------------------------------------------------------------------
/**
 * Returns cached instance of the physician lookup table. If cached instance
 * does not exist yet, the method fetches and initializes cached instance
 * first.
 * 
 * @return the cached instance of physician lookup table.
 */
// ---------------------------------------------------------------------------

private HashMap<Integer, String> getPhysicianLookup() 
	{
	Collection<Physician> l_Physicians;
	Iterator<Physician> l_PhysicianIterator;
	Physician l_Physician;

	if (m_PhysicianLookup != null) return m_PhysicianLookup;
	else m_PhysicianLookup = new HashMap<Integer, String>();

	l_Physicians = m_ListManager.getListReference(Physician.class);
	if (l_Physicians != null) 
		{
	    l_PhysicianIterator = l_Physicians.iterator();
	    while (l_PhysicianIterator.hasNext()) 
	    	{
	    	l_Physician = l_PhysicianIterator.next();
	    	m_PhysicianLookup.put(l_Physician.getId(), formatPhysicianName (l_Physician));
	    	}
		}

	return m_PhysicianLookup;
    }


//---------------------------------------------------------------------------
/**
* Returns cached instance of the physician lookup table. If cached instance
* does not exist yet, the method fetches and initializes cached instance
* first.
* 
* @return the cached instance of physician lookup table.
*/
//---------------------------------------------------------------------------

private HashMap<Integer, String> getInsuranceLookup() 
	{
	Collection<Insurance> l_Insurances;
	Iterator<Insurance> l_InsuranceIterator;
	Insurance l_Insurance;

	if (m_InsuranceLookup != null) return m_InsuranceLookup;
	else m_InsuranceLookup = new HashMap<Integer, String>();

	l_Insurances = m_ListManager.getListReference(Insurance.class);
	if (l_Insurances != null) 
		{
	    l_InsuranceIterator = l_Insurances.iterator();
	    while (l_InsuranceIterator.hasNext()) 
	    	{
	    	l_Insurance = l_InsuranceIterator.next();
	    	m_InsuranceLookup.put(l_Insurance.getId(), l_Insurance.getAcronym());
	    	}
		}

	return m_InsuranceLookup;
 }

// ---------------------------------------------------------------------------
/**
 * Returns a lookup table of settlement methods for the specified scope.
 * 
 * @param p_Scope specifies which setttlement methods to include in the lookup
 *        table. Possible values are:
 *        <ul>
 *        <li>c_AllSettlements : Include all settlement methods.</li>
 *        <li>c_OnlyPayments : Include only settlement methods
 *        specifying either cash, credit or debit cards.</li>
 *        <li>c_OnlyTransfers : Include only settlement methods
 *        specifying a bank account to transfer money to.</li>
 *        </ul>
 * @return A lookup table holdinf settlement methods for the specified
 *         scope.
 */
// ---------------------------------------------------------------------------

private HashMap<Integer, Settlement> getSettlementLookup(int p_Scope) 
	{
	HashMap<Integer, Settlement> l_SettlementLookup;
	Collection<Settlement> l_Settlements = null;
	Iterator<Settlement> l_SettlementIterator;
	Settlement l_Settlement;

	l_SettlementLookup = new HashMap<Integer, Settlement>();

	l_Settlements = this.getSettlements();
	if (l_Settlements != null) 
		{
	    l_SettlementIterator = l_Settlements.iterator();
	    while (l_SettlementIterator.hasNext()) 
	    	{
	    	l_Settlement = l_SettlementIterator.next();
	    	switch (p_Scope) 
	    		{
	    		case c_OnlyPayments:
	    			
	    			if (l_Settlement.getPayment() == null)
	    				continue;
	    			break;
	    			
	    		case c_OnlyTransfers:
		    
	    			if (l_Settlement.getTransferAccount() == null)
	    				continue;
	    			break;
	    		}

	    	l_SettlementLookup.put(l_Settlement.getId(), l_Settlement);
	    	}
		}

	return l_SettlementLookup;
    }

//---------------------------------------------------------------------------
/**
 * Returns cached instance of the user lookup table. If cached instance does
 * not exist yet, the method fetches and initializes cached instance first.
 * 
 * @return the cached instance of user lookup table.
 */
//---------------------------------------------------------------------------

private HashMap<Integer, GecamedUser> getUserLookup() 
	{
	Iterator<GecamedUser> l_UserIterator;
	GecamedUser l_User;

	if (m_UserLookup != null) return m_UserLookup;
	else m_UserLookup = new HashMap<Integer, GecamedUser>();

	m_Users = this.fetchUsers();

	if (m_Users != null) 
		{
	    m_UserLookup = new HashMap<Integer, GecamedUser>();
	    l_UserIterator = m_Users.iterator();
	    while (l_UserIterator.hasNext()) 
	    	{
	    	l_User = l_UserIterator.next();
	    	m_UserLookup.put(l_User.getId(), l_User);
	    	}
		}

	return m_UserLookup;
    }

//---------------------------------------------------------------------------
/**
 * Returns the Ids of the settlement methods stored in the specifed lookup
 * table.
 * 
 * @param p_Settlements
 *            specifies the lookup table to retrieve Ids of contained
 *            settlement methods from.
 * @return a collection holding the Ids of the settlement methods contained
 *         in the specified lookup table.
 */
//---------------------------------------------------------------------------

private Collection<Integer> getSettlementIDs(HashMap<Integer, Settlement> p_Settlements) 
	{
	Iterator<Settlement> l_SettlementIterator;
	Collection<Integer> l_SettlementIDs;

	l_SettlementIDs = new ArrayList<Integer>();

	l_SettlementIterator = p_Settlements.values().iterator();
	while (l_SettlementIterator.hasNext()) 
		{
	    l_SettlementIDs.add(l_SettlementIterator.next().getId());
		}

	return l_SettlementIDs;
    }

//---------------------------------------------------------------------------
//===========================================================================
//= Settings
//===========================================================================
//---------------------------------------------------------------------------
/**
 * Returns the state of the maiden name setting. Depending on the state of
 * this setting, maiden name of patients ought to be interpreted as such or
 * as married name.
 * 
 * @return <code>true</code> if maiden name is to be interpreted as married
 *         name, <code>false</code> if maiden name is still maiden name.
 */
//---------------------------------------------------------------------------

private boolean maidenNameIsMarriedName() 
	{
	Object l_Value;

	if (m_MaidenIsMarriedName == null) 
		{
	    l_Value = m_LoginBean.getAdminSettingValue("AdministrativeElementsPlugin", "MAIDEN_CONFIG");

	    if (l_Value instanceof Boolean) 
	    	 m_MaidenIsMarriedName = (Boolean) l_Value;
	    else m_MaidenIsMarriedName = Boolean.FALSE;
		}

	return m_MaidenIsMarriedName.booleanValue();
    }

//---------------------------------------------------------------------------
/**
 * Checks whether or not billing per physician is to be used or not. Method
 * checks value of split billing setting.
 * 
 * @return <code>true</code> if billing is done on per physician basis,
 *         <code>false</code> if shared medical office billing is to be
 *         used.
 */
//---------------------------------------------------------------------------

private boolean splitBilling() 
	{
	Object l_Value;

	if (m_SplitBilling == null) 
		{
		l_Value = m_LoginBean.getAdminSettingValue(BillingAdminSettings.c_ModuleName,
												   BillingAdminSettings.c_SplitBillingSetting);

		if (l_Value instanceof Boolean) 
			 m_SplitBilling = (Boolean) l_Value;
		else m_SplitBilling = Boolean.FALSE;
		}

return m_SplitBilling.booleanValue();
}

//---------------------------------------------------------------------------
/**
 * Checks whether long or short invoice numbers should be printed. Method
 * checks value of short invoice number setting.
 * 
 * @return <code>true</code> if short invoice numbers should be printed,
 *         <code>false</code> otherwise.
 */
//---------------------------------------------------------------------------

private boolean shortInvoiceNumbers() 
	{
	Object l_Value;

	if (m_ShortInvoiceNumbers == null) 
		{
	    l_Value = m_LoginBean.getAdminSettingValue( BillingAdminSettings.c_ModuleName,
	    											BillingAdminSettings.c_ShortInvoiceNumbersSetting);

	    if (l_Value instanceof Boolean) 
	    	 m_ShortInvoiceNumbers = (Boolean) l_Value;
	    else m_ShortInvoiceNumbers = Boolean.FALSE;
		}

	return m_ShortInvoiceNumbers.booleanValue();
    }


private boolean useLeadingZeros ()
{
	Object l_Value;

	if (m_UseLeadingZeros == null) 
		{
	    l_Value = m_LoginBean.getAdminSettingValue( BillingAdminSettings.c_ModuleName,
	    											BillingAdminSettings.c_UseLeadingZerosSetting);

	    if (l_Value instanceof Boolean) 
	    	 m_UseLeadingZeros = (Boolean) l_Value;
	    else m_UseLeadingZeros = Boolean.TRUE;
		}

	return m_UseLeadingZeros.booleanValue();
    }

//---------------------------------------------------------------------------
/**
 * Checks whether or not addresses ought to be printed in all uppercase or
 * not. Method checks value of address style setting.
 * 
 * @return <code>true</code> if addresses ought to be printed in uppercase,
 *         <code>false</code> otherwise.
 */
//---------------------------------------------------------------------------

private boolean printUpperCaseAddresses() 
	{
	Object l_Value;

	if (m_AddressStyle == null) 
		{
	    l_Value = m_LoginBean.getAdminSettingValue( BillingAdminSettings.c_ModuleName,
	    											BillingAdminSettings.c_AddressStyleSetting);
	    if (l_Value instanceof Integer) 
	    	 m_AddressStyle = (Integer) l_Value;
	    else m_AddressStyle = Integer.valueOf(-1);
		}

	return (m_AddressStyle.intValue() == 1) ? true : false;
    }

// ---------------------------------------------------------------------------
/**
 * Checks whether or not addresses ought to be printed with captialized
 * words. Method checks value of address style setting.
 * 
 * @return <code>true</code> if addresses ought to be printed with
 *         capitalized words, <code>false</code> otherwise.
 */
// ---------------------------------------------------------------------------

private boolean capitalizeWords() 
	{
	Object l_Value;

	if (m_AddressStyle == null) 
		{
	    l_Value = m_LoginBean.getAdminSettingValue(BillingAdminSettings.c_ModuleName,
	    										   BillingAdminSettings.c_AddressStyleSetting);
	    if (l_Value instanceof Integer) 
	    	 m_AddressStyle = (Integer) l_Value;
	    else m_AddressStyle = Integer.valueOf(-1);
		}

	return (m_AddressStyle.intValue() == 2) ? true : false;
    }

//---------------------------------------------------------------------------
//===========================================================================
//= Formatter
//===========================================================================

private void setupFormatting ()
	{
	Translatrix.setLocale(new Locale("fr", "FR"));
	
	Activity.setMaidenNameIsMarriedName    (this.maidenNameIsMarriedName());
	InvoiceStub.setMaidenNameIsMarriedName (this.maidenNameIsMarriedName());
	Transaction.setMaidenNameIsMarriedName (this.maidenNameIsMarriedName());
	
	m_Formatter.setReferenceAddress(this.getMedicalOffice().getLatestOfficeAddress());
	m_Formatter.setBillingPrinter(this);
	
	if (this.printUpperCaseAddresses()) 
		{
		m_Formatter.setAddressPrintMode(AddressFormatter.ALL_UPPERCASE);
		m_Formatter.setPatientNamePrintMode(PatientNameFormatter.ALL_UPPERCASE);
		}
	else if (this.capitalizeWords())
		{
		m_Formatter.setAddressPrintMode(AddressFormatter.CAPITALIZE_WORDS);
		m_Formatter.setPatientNamePrintMode(PatientNameFormatter.CAPITALIZE_WORDS);
		}
	else 
		{
		m_Formatter.setAddressPrintMode(AddressFormatter.ORIGINAL);
		m_Formatter.setPatientNamePrintMode(PatientNameFormatter.ORIGINAL);
		}
	}

//---------------------------------------------------------------------------
/**
 * Returns a printable representation of specified patient's social security
 * number.
 * 
 * @param p_Patient specifies the patient to get social security number from.
 * @return a printable representation of specified patient's social security
 *         number. <code>c_NotAvailable</code> will be returned if specified
 *         patient is <code>null</code>.
 */
//---------------------------------------------------------------------------

private String formatPatientSocialSecurityNumber(Patient p_Patient) 
	{
	return (p_Patient != null) ? p_Patient.formatSocialSecurityNumber(): c_NotAvailable;
    }

//---------------------------------------------------------------------------
/**
 * Returns a printable representation of bank accounts. Depending on whether
 * you specify a physician or not, method will either include only those
 * accounts that specified physician is the holder of, or all available
 * accounts.
 * 
 * @param p_Physician specifies the physician who ought to be the holder of the
 *            		  accounts to be included in printable representation. Specify
 *            		  <code>null</code> to include all available accounts.
 * @return a printable representation of bank accounts
 */
//---------------------------------------------------------------------------

public String formatAccountList (Physician p_Physician) 
	{
	Collection<Account> l_Accounts;
	Iterator<Account> 	l_AccountIterator;
	Account 			l_Account;
	StringBuffer 		l_AccountLine;

	l_Accounts = this.getAccounts();
	if (l_Accounts != null) 
		{
	    l_AccountLine = new StringBuffer();
	    l_AccountIterator = l_Accounts.iterator();
	    while (l_AccountIterator.hasNext()) 
	    	{
	    	l_Account = l_AccountIterator.next();
	    	if (	(p_Physician != null)
	    		 && (p_Physician.equals(l_Account.getHolder()))) 
	    		{
	    		l_AccountLine.append(l_Account).append(c_CRLF);
	    		} 
	    	else if (l_Account.getHolder() == null) 
	    		{
	    		l_AccountLine.append(l_Account).append(c_CRLF);
	    		}
	    	}
	    return l_AccountLine.toString();
		}
	return c_NotAvailable;
    }

//---------------------------------------------------------------------------
/**
 * Returns a printable representation of all physicians
 * 
 * @return a printable representation of all physicians
 */
//---------------------------------------------------------------------------

private String formatPhysicians() 
	{
	Collection<Physician> l_Physicians;
	Iterator<Physician> l_PhysicianIterator;
	Physician l_Physician;

	StringBuffer l_OfficePhysicians;

	l_OfficePhysicians = new StringBuffer();

	l_Physicians = m_ListManager.getListReference(Physician.class);
	if (l_Physicians != null) 
		{
	    l_PhysicianIterator = l_Physicians.iterator();
	    while (l_PhysicianIterator.hasNext()) 
	    	{
	    	l_Physician = l_PhysicianIterator.next();
	    	l_OfficePhysicians.append(formatPhysicianName(l_Physician)).append(c_CRLF);
	    	}
		}

	return l_OfficePhysicians.toString();
    }

//---------------------------------------------------------------------------
/**
 * Returns a printable representation of specified physician.
 * 
 * @param p_Physician
 *            specifies physician to get printable representation of.
 * @return a printable representation of specified physician. Method returns
 *         <code>c_NotAvailable</code> if specified physician is
 *         <code>null</code>.
 */
//---------------------------------------------------------------------------

private String formatPhysicianName (Physician p_Physician) 
	{
	if (p_Physician == null) return c_NotAvailable;

	return m_Formatter.formatPhysicianName(p_Physician, true);
    }

//---------------------------------------------------------------------------
/**
 * Returns a printable representation of specified patient's address.
 * Depending on whether patient is backed by a guarantor or not, address of
 * guarantor will be used instead of patient's address. An additional flag
 * allows to decide whether patient name should be included or not.
 * 
 * @param p_Patient specifies the patient to get printable representation of
 *            		address for.
 * @param p_WithName specifies whether or not to include patient name.
 * @return a printable representation of specified patient's address
 */
//---------------------------------------------------------------------------

private String formatPatientAddress(Patient p_Patient, boolean p_WithName) 
    {
	StringBuffer l_PatientAddress;
	l_PatientAddress = new StringBuffer();
	
	if (p_WithName)
		{
		l_PatientAddress.append(m_Formatter.formatGuarantorName(p_Patient, true, false));
		l_PatientAddress.append(System.getProperty ("line.separator"));
		}
	l_PatientAddress.append(m_Formatter.formatGuarantorAddress(p_Patient));
	
	return l_PatientAddress.toString();
    }

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

private String formatPaymentMethod (Settlement p_Settlement) 
	{
	String l_Method = "";

	if (p_Settlement == null) return l_Method;

	if (p_Settlement.getPayment() != null) 
		{
	    l_Method = p_Settlement.getPayment().getMethod();
		}

	return l_Method;
    }

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

private String formatTransferAccount (Settlement p_Settlement) 
	{
	StringBuffer l_Buffer;
	Account l_Account;

	if (p_Settlement == null) return "";

	if (p_Settlement.getTransferAccount() != null) 
		{
	    l_Buffer = new StringBuffer();
	    l_Account = p_Settlement.getTransferAccount();
	    l_Buffer.append(l_Account.getBankname()).append(" ").append(l_Account.getIban());
	    return l_Buffer.toString();
		} 
	else return "";
    }

//---------------------------------------------------------------------------
//===========================================================================
//= Template Parameters
//===========================================================================
//---------------------------------------------------------------------------

private HashMap<String, Object> setCommonParameters (Physician p_Physician, HashMap<String, Object> p_Parameters)
	{
	Office 		l_MedicalOffice 	  = null;
	String		l_PhysicianSpeciality = "";
	String 		l_Address 	 		  = "";
	String 		l_AddressLine 	  	  = "";
	String		l_OfficeUCMCode		  = "";
	
	l_MedicalOffice = this.getMedicalOffice();
	
	if (l_MedicalOffice != null) 
		{
		l_OfficeUCMCode = getOfficeUCM(l_MedicalOffice, p_Physician);
		
		p_Parameters.put("office_name", l_MedicalOffice.getName());
	    p_Parameters.put("office_info", l_MedicalOffice.getInformation());
		p_Parameters.put("office_phone", m_Formatter.formatOfficePhones (l_MedicalOffice, p_Physician));
		}
		
	if ((p_Physician != null) && (p_Physician.getPhysicianAddress() != null)) 
		{
	    l_Address 		= m_Formatter.formatPhysicianAddress (p_Physician);
	    l_AddressLine   = m_Formatter.formatPhysicianLine (p_Physician);
		} 
	else 
		{
	    l_Address 		= m_Formatter.formatOfficeAddress (l_MedicalOffice);
	    l_AddressLine   = m_Formatter.formatOfficeLine (l_MedicalOffice);
		}	
		
	if (p_Physician != null) l_PhysicianSpeciality = p_Physician.getSpeciality();
	
	p_Parameters.put("physician_name", formatPhysicianName (p_Physician));
	p_Parameters.put("physician_address", l_Address);

    p_Parameters.put("office_address", 			   l_Address);
    p_Parameters.put("office_address_line", 	   l_Address);	// Deprecated. Replaced by office_address
    p_Parameters.put("office_address_single_line", l_AddressLine);

    if (this.splitBilling() && p_Physician != null) 
		{
	    p_Parameters.put("code_medicin", 		getPhysicianUCM (p_Physician)); // Deprecated. Replaced by ucm_code
	    p_Parameters.put("ucm_code", 			getPhysicianUCM (p_Physician));    
	    p_Parameters.put("bank_account", 		formatAccountList (p_Physician));
	    p_Parameters.put("office_doctors", 		formatPhysicianName (p_Physician));
	    p_Parameters.put("office_speciality", 	l_PhysicianSpeciality);
		} 
	else 
		{
	    p_Parameters.put("code_medicin", 		l_OfficeUCMCode); // Deprecated. Replaced by ucm_code
		p_Parameters.put("ucm_code", 			l_OfficeUCMCode);
	    p_Parameters.put("bank_account", 		formatAccountList(null));
	    p_Parameters.put("office_doctors", 		formatPhysicians());
		}
	
	return p_Parameters;
	}
    
//---------------------------------------------------------------------------

private HashMap<String, Object> setInvoiceParameters (Invoice p_Invoice, HashMap<String, Object> p_Parameters)
	{
	if (p_Invoice == null) return p_Parameters;
	
	p_Parameters.put("invoice_id", p_Invoice.getId());
	p_Parameters.put("invoice_physician", formatPhysicianName(p_Invoice.getPhysician()));
	
	p_Parameters.put("invoice_number", p_Invoice.formatInvoiceNumber(this.shortInvoiceNumbers(), useLeadingZeros()));
	p_Parameters.put("invoice_date", m_DateFormat.format(p_Invoice.getInvoiceDate()));
	p_Parameters.put("invoice_payment_date", p_Invoice.getSettlementDate());
	p_Parameters.put("invoice_payment_method",formatPaymentMethod(p_Invoice.getSettlement()));
	p_Parameters.put("invoice_transfer_account",formatTransferAccount(p_Invoice.getSettlement()));

	p_Parameters.put("invoice_amount", p_Invoice.getAmount());
	p_Parameters.put("invoice_balance", p_Invoice.getBalance());
	p_Parameters.put("invoice_payment", p_Invoice.getPayment());

	p_Parameters.put("number_of_reminders", p_Invoice.getNumberOfReminders());
	
	if (p_Invoice.getReminderDate() != null)
		 p_Parameters.put("reminder_date", m_DateFormat.format(p_Invoice.getReminderDate()));
	else p_Parameters.put("reminder_date", "");

	if (p_Invoice.isAccident()) 
		{
		p_Parameters.put("invoice_accident_date", p_Invoice.getAccidentDate());

		if (p_Invoice.getAccidentNumber() == null)
		     p_Parameters.put("invoice_accident_number", AccidentNumberFormatter.getAccidentNumber(p_Invoice.getAccidentDate()));
		else p_Parameters.put("invoice_accident_number", p_Invoice.getAccidentNumber());
		}

	p_Parameters.put("number_of_acts", p_Invoice.getNumberOfActs());

	if (p_Invoice.getHospitalisationClass() != null) 
		{
		try {
			if (	(HospitalisationClass.c_FirstClass.equals(p_Invoice.getHospitalisationClass().getAcronym()))
				&& (p_Invoice.getFirstClassRequired())
				&& (p_Invoice.getThirdPartyPayer() != null))
    		{
			p_Parameters.put("hospitalisation_class", HospitalisationClass.c_SecondClass);
    		} 
    	else 
    		{
    		p_Parameters.put("hospitalisation_class", p_Invoice.getHospitalisationClass().getAcronym());
    		}
    	} 
    catch (Exception p_Exception) 
    	{
    	p_Exception.printStackTrace();
    	}
	}
	
	return p_Parameters;
	}

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

private HashMap<String, Object> setPatientParameters (Patient p_Patient, HashMap<String, Object> p_Parameters)
	{
	if (p_Patient == null) return p_Parameters;
	
	p_Parameters.put("patient_header", 		formatPatientAddress (p_Patient, true));
	p_Parameters.put("patient_matricule",	formatPatientSocialSecurityNumber(p_Patient));
	p_Parameters.put("patient_name", 		m_Formatter.formatPatientName (p_Patient, true, false));
	p_Parameters.put("guarantor_name", 		m_Formatter.formatGuarantorName (p_Patient, true, false));
	p_Parameters.put("patient_address", 	formatPatientAddress (p_Patient, false));	
	
	return p_Parameters;
	}

//---------------------------------------------------------------------------
//***************************************************************************
//* Class Body 																*
//***************************************************************************
//---------------------------------------------------------------------------
/**
 * Releases all cached objects. Objects will be fetched again from database
 * and cached if required.
 */
// ---------------------------------------------------------------------------

public void releaseCachedObjects() 
	{
	m_MedicalOffice = null;
	m_BailiffRates = null;
	m_Settlements = null;

	m_Users = null;
	m_UserLookup = null;

//	m_Physicians = null;
	m_PhysicianLookup = null;

	m_Accounts = null;

	m_MaidenIsMarriedName = null;
	m_SplitBilling = null;
	m_AddressStyle = null;
    }

// ---------------------------------------------------------------------------
/**
 * Generates a printable object for the specified invoice.
 * 
 * @param p_Invoice
 *            specifies the invoice generate printable object from.
 * @param p_MarkAsCopy
 *            specifies whether or not printable object should be
 *            explicitely marked as a copy.
 * @return a printable object generated from the specified invoice.
 */
// ---------------------------------------------------------------------------

@RolesAllowed("gecam")
public JasperPrint createInvoicePrintObject(Invoice p_Invoice, Boolean p_MarkAsCopy, HashMap<String, Object> p_Parameter, Boolean forceOriginal) throws Exception 
    {
	JasperReport l_Report = null;
	JRBeanCollectionDataSource l_Acts = null;
	JasperPrint l_InvoicePrinter = null;
	boolean l_PrintZeroActs  = ((Boolean) m_LoginBean.getAdminSettingValue(
			BillingAdminSettings.c_ModuleName, 
			BillingAdminSettings.c_PrintZeroActsSetting, 
			BillingAdminSettings.c_PrintZeroActsStationary)).booleanValue();
	
//	Template l_InvoiceTemplate = null;
	Physician l_Physician = null;
	Date l_DateOfInterest = null;
	

	if (Act.factorsNotSet()) m_InvoiceInterface.initializeFactors();

	// ====================================================================
	// Step 1. Make sure Invoice is ready to be printed. Doing so entails
	// fetching patient data of invoice as well as making sure that
	// acts are properly monetized.
	// ====================================================================

	p_Invoice = this.fetchPatientForInvoice(p_Invoice);
	
	if (!l_PrintZeroActs)
	{
		// exclude the acts, whose quantity is zero
		Set<Act> l_FilteredActs = new HashSet<Act>();
		
		for (Act a : p_Invoice.getActs())
		{
			if (a.getQuantity() != 0)
				l_FilteredActs.add(a);
		}
		
		if (l_FilteredActs.size() != p_Invoice.getActs().size())
		{
			p_Invoice	= (Invoice) p_Invoice.clone();
			p_Invoice.setActs(l_FilteredActs);
			p_Parameter.put(PrintParameter.PRINT_PARAMETER_INVOICE, p_Invoice);
		}
	}
	p_Invoice.monetize();

	// ====================================================================
	// Step 2. Fetch the proper template to print the invoice. If a custom
	// template has been defined for the physician specified by the invoice
	// then we'll use the custom one. If not, we'll resort to using the
	// default invoice.
	// ====================================================================

	l_Physician = p_Invoice.getPhysician();
	l_DateOfInterest = p_Invoice.getInvoiceDate();

	l_Report = m_TemplateManager.findTemplate(JasperTemplateBean.BILLING_INVOICE, l_Physician.getId(), l_DateOfInterest);
//	l_InvoiceTemplate = m_TemplateManager.getTemplate(c_InvoiceTemplateName, l_Physician.getId(), l_DateOfInterest);
//	
//	if (l_InvoiceTemplate != null) 
//		{
//	    l_Report = (JasperReport) JRLoader.loadObject(new ByteArrayInputStream(l_InvoiceTemplate.getJasper()));
//		} 
//	else 
//		{
////		l_Report = this.getStandardReport (c_InvoiceTemplate);
//		}

	this.setupFormatting();

	// ====================================================================
	// Step 3. Gather Parameters for Jasper
	// ====================================================================

	UtilFormatter l_Formatter = (UtilFormatter) p_Parameter.get("utilFormatter");
	if (forceOriginal != null)
		l_Formatter.setForceOriginal(forceOriginal.booleanValue());
	l_Formatter.setBillingPrinter(this);
	
	p_Parameter = this.setCommonParameters  (l_Physician, p_Parameter);
	p_Parameter = this.setInvoiceParameters (p_Invoice, p_Parameter);
	p_Parameter = this.setPatientParameters (p_Invoice.getPatient(), p_Parameter);
	
	// retrieve invoice is a copy or not
	p_Parameter.put("is_copy", p_MarkAsCopy);
	
	if (p_Invoice.isAccident()) 
		{
		p_Parameter.put("patient_accidentdate", p_Invoice.getAccidentDate());

	    if (p_Invoice.getAccidentNumber() == null)
	    	 p_Parameter.put("patient_accidentnr", AccidentNumberFormatter.getAccidentNumber(p_Invoice.getAccidentDate()));
	    else p_Parameter.put("patient_accidentnr", p_Invoice.getAccidentNumber());
		}

	try {
	    p_Parameter.put("patient_caisse", p_Invoice.getHealthInsurance().getAcronym());
		} 
	catch (Exception p_Exception) 
		{
	    this.log(Level.INFO, "No health insurance for patient " + p_Invoice.getPatient().toShortString() + " set");
	    p_Parameter.put("patient_caisse", c_NotAvailable);
		}

	// ====================================================================
	// Invoices where first class hospitalisation was deemed necessary
	// MUST be printed as second class if third party will pay for it
	// ====================================================================

	p_Parameter.put(JRJpaQueryExecuterFactory.PARAMETER_JPA_ENTITY_MANAGER,m_EntityManager);
	
	l_Acts = new JRBeanCollectionDataSource(ActReportField.createFields(p_Invoice));
	
	l_InvoicePrinter = JasperFillManager.fillReport(l_Report, p_Parameter, l_Acts);

	return l_InvoicePrinter;
    }

// ---------------------------------------------------------------------------
/**
 * Generates a printable list for the specified list of invoice stubs using
 * the template for reminder lists.
 * 
 * @param p_InvoiceStubs
 *            specifies the invoice stubs to generate printable list from.
 * @param p_Title
 *            specifies the title to appear on top of list.
 * @return a printable list generated from the specified invoice stubs with
 *         the specified title.
 */
// ---------------------------------------------------------------------------


@RolesAllowed("gecam")
public JasperPrint createReminderList(Collection<InvoiceStub> p_InvoiceStubs, String p_Title, HashMap<String, Object> p_Parameter) throws Exception 
	{
	JasperReport l_Report = null;
	JasperPrint l_InvoicePrinter = null;
	JRBeanCollectionDataSource l_InvoiceStubs = null;

	if (Act.factorsNotSet()) m_InvoiceInterface.initializeFactors();
	
	this.setupFormatting();

//	l_Report = this.getStandardReport (c_ReminderList);
	l_Report = this.getStandardReport (JasperTemplateBean.BILLING_REMINDERS);
	
	p_Parameter = this.setCommonParameters(null, p_Parameter);
	
	// set the EntityManager for the reportcreator
	p_Parameter.put(JRJpaQueryExecuterFactory.PARAMETER_JPA_ENTITY_MANAGER,m_EntityManager);

	p_Parameter.put("list_title", p_Title);
	p_Parameter.put("list_printing_date", new Date());
	p_Parameter.put("physicians", getPhysicianLookup());
	
	l_InvoiceStubs = new JRBeanCollectionDataSource(p_InvoiceStubs);
	l_InvoicePrinter = JasperFillManager.fillReport(l_Report, p_Parameter,l_InvoiceStubs);

	return l_InvoicePrinter;
    }

// ---------------------------------------------------------------------------
/**
 * Generates a printable list for the specified list of invoice stubs using
 * the template for invoice lists.
 * 
 * @param p_InvoiceStubs
 *            specifies the invoice stubs to generate printable list from.
 * @return a printable list generated from the specified invoice stubs with
 *         the specified title.
 */
// ---------------------------------------------------------------------------

@RolesAllowed("gecam")
public JasperPrint createInvoiceList (Collection<InvoiceStub> p_InvoiceStubs, HashMap<String, Object> p_Parameter) throws Exception 
	{
	JasperReport l_Report = null;
	JasperPrint l_InvoicePrinter = null;
	JRBeanCollectionDataSource l_InvoiceStubs = null;

	if (Act.factorsNotSet()) m_InvoiceInterface.initializeFactors();
	
	this.setupFormatting();
	
//	l_Report = this.getStandardReport (c_InvoiceList);
	l_Report = this.getStandardReport (JasperTemplateBean.BILLING_INVOICES);

	p_Parameter = this.setCommonParameters(null, p_Parameter);
	
	// set the EntityManager for the reportcreator
	p_Parameter.put(JRJpaQueryExecuterFactory.PARAMETER_JPA_ENTITY_MANAGER,m_EntityManager);

	p_Parameter.put("list_printing_date", new Date());

	p_Parameter.put("physicians", getPhysicianLookup());
	p_Parameter.put("insurances", getInsuranceLookup());

	l_InvoiceStubs = new JRBeanCollectionDataSource(p_InvoiceStubs);
	l_InvoicePrinter = JasperFillManager.fillReport(l_Report, p_Parameter,
		l_InvoiceStubs);
	
	return l_InvoicePrinter;
    }

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

public Map<Integer, Map<TimeSpan, Boolean>> getUnjoinableReportsForType (String p_TemplateType)
	{
	Collection<Template> 	l_TemplateList;
	TimeSpan				l_ValiditySpan;
	Boolean					l_Joinable;
	Map<TimeSpan, Boolean>	l_DateTemplateMap;
	
	Map<Integer, Map<TimeSpan, Boolean>>	
							l_IdTemplateMap;
	
	int 			l_TemplateType;
	
	Integer			l_PhysicianId;
	Integer 		l_LastId = null;
	Date 			l_ExpiringDate;
	Date			l_LastDate = null;
	
	
	l_TemplateList 	= m_TemplateManager.getTemplatesByType(p_TemplateType);
	l_IdTemplateMap = new HashMap<Integer, Map<TimeSpan,Boolean>>(l_TemplateList.size());
	
	if (p_TemplateType.equals(c_FirstNoticeTemplateType))
		 l_TemplateType = 1;
	else l_TemplateType = 2;
	
	for (Template l_Template : l_TemplateList)
		{
		l_PhysicianId 	= l_Template.getPhysicianID();
		l_ExpiringDate 	= l_Template.getExpiry();
		if (l_LastId != l_PhysicianId)
			l_LastDate 	= null;
		l_ValiditySpan	= new TimeSpan(l_LastDate, l_ExpiringDate);
		
		try {
			l_Joinable = canReportJoinReminders(l_TemplateType, l_PhysicianId, l_ExpiringDate);
			
			
			l_DateTemplateMap = l_IdTemplateMap.get(l_PhysicianId);
			if (l_DateTemplateMap == null)
				{
				l_DateTemplateMap = new HashMap<TimeSpan, Boolean>();
				l_IdTemplateMap.put(l_PhysicianId, l_DateTemplateMap);
				}
			l_DateTemplateMap.put(l_ValiditySpan, l_Joinable);
			}
		catch (Exception p_Exception) 
			{
			p_Exception.printStackTrace();
			}
		
		l_LastId	= l_PhysicianId;
		l_LastDate 	= l_ExpiringDate;
		}
	
	return l_IdTemplateMap;
	}

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

private JasperReport createReport (int p_NoticeType, Integer p_PhysicianId, Date p_DateOfInterest, Bailiff p_Bailiff) throws Exception
	{
//	String			l_TemplateFileName;
//	String 			l_TemplateType;
	String			l_TemplateBeanName;
	JasperReport	l_Report;
	
	switch (p_NoticeType)
		{
		case c_PrintFirstNotice:
//			l_TemplateFileName 	= c_FirstNoticeTemplateFileName;
//			l_TemplateType 		= c_FirstNoticeTemplateType;
			l_TemplateBeanName	= JasperTemplateBean.BILLING_FIRST_REMINDER;
			break;
			
		case c_PrintLastNotice:
//			l_TemplateFileName 	= c_SecondNoticeTemplateFileName;
//			l_TemplateType 		= c_SecondNoticeTemplateType;
			l_TemplateBeanName	= JasperTemplateBean.BILLING_SECOND_REMINDER;
			break;
			
		case c_PrintPaymentOrder:
		default:
//			l_TemplateFileName 	= c_DemandOfPaymentTemplate;
//			l_TemplateType 		= c_DemandOfPaymentTemplateName;
			
			// get PAYMENT ORDER TEMPLATE depending on Bailif
			if (p_Bailiff != null) {
				String name = p_Bailiff.getName();
				if (name.toLowerCase().contains("diekirch")) {
					l_TemplateBeanName	= JasperTemplateBean.TYPE_PAYMENT_ORDER_DIEKIRCH;
				} else if (name.toLowerCase().contains("esch")) {
					l_TemplateBeanName	= JasperTemplateBean.TYPE_PAYMENT_ORDER_ESCH;
				} else if (name.toLowerCase().contains("luxembourg")) {
					l_TemplateBeanName	= JasperTemplateBean.TYPE_PAYMENT_ORDER_LUXEMBOURG;
				} else {
					l_TemplateBeanName	= JasperTemplateBean.BILLING_PAYMENT_ORDER;	
				}
			} else {
				l_TemplateBeanName	= JasperTemplateBean.BILLING_PAYMENT_ORDER;				
			}
			break;
		}
	
	l_Report = m_TemplateManager.findTemplate(l_TemplateBeanName, p_PhysicianId, p_DateOfInterest);
//	Template l_Template = m_TemplateManager.getTemplate(
//			l_TemplateType, p_PhysicianId, p_DateOfInterest);
//	
//	if (l_Template != null)
//		{
//	    l_Report = (JasperReport) JRLoader.loadObject(new ByteArrayInputStream(l_Template.getJasper()));
//		}
//	else 
//		{
//		l_Report = this.getStandardReport (l_TemplateFileName);
//		}
	
	return l_Report;
	}

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

/**
 * @author ferring
 * Checks, if the report contains the most important field constants.
 * 
 * @param p_ReminderType
 * 	Defines if it is the first or second notice (c_FirstNotice / c_SecondNotice)
 * @param p_PhysicianId
 * 	The id of the physician, to fetch the report for.
 * @param p_DateOfInterest
 * 	The date of the invoice, to fetch the report from.
 * @return
 * 	<code>true</code> if the join function can be used<br>
 * 	else, <code>false</code>
 */
public boolean canReportJoinReminders (int p_ReminderType, Integer p_PhysicianId, Date p_DateOfInterest)
	{
	boolean			l_Contains;
	JasperReport 	l_Report;
	JRField[]		l_Fields;
	
//	String 			l_NoticeTemplateName;
	String			l_TemplateBeanName;
//	Template		l_Template;
	
	try {
		// try to get the report
		switch (p_ReminderType)
			{
			case c_PrintFirstNotice:
//				l_NoticeTemplateName 	= c_FirstNoticeTemplateType;
				l_TemplateBeanName		= JasperTemplateBean.BILLING_FIRST_REMINDER;
				break;
				
			case c_PrintLastNotice:
			default:
//				l_NoticeTemplateName 	= c_SecondNoticeTemplateType;
				l_TemplateBeanName		= JasperTemplateBean.BILLING_SECOND_REMINDER;
			}
		
		l_Report = m_TemplateManager.findTemplate(l_TemplateBeanName, p_PhysicianId, p_DateOfInterest);
//		l_Template = m_TemplateManager.getTemplate(
//				l_NoticeTemplateName, p_PhysicianId, p_DateOfInterest);
//		
//		
//		if (l_Template != null)
//			{
//		    l_Report = (JasperReport) JRLoader.loadObject(new ByteArrayInputStream(l_Template.getJasper()));
//			}
//		else 
//			{
//			// if no template is stored for this physician and date, take the default (which can join reminders)
//			return true;
//			}
		}
	catch (Exception e) 
		{
		this.log(Level.ERROR, "Unable to create the JasperReport.", e);
		return false;
		}
	
	l_Fields = l_Report.getFields();
	
	if (l_Fields == null || l_Fields.length <= 0)
		return false;
	
	// check whether the report contains all necessary fields
	for (String fieldName : c_ImportantReportFields)
		{
		l_Contains = false;
		for (JRField field : l_Fields)
			{
			if (field.getName().equals(fieldName))
				{
				l_Contains = true;
				break;
				}
			}
		
		if (!l_Contains)
			return false;
		}
	
	return true;
	}

//---------------------------------------------------------------------------
/**
* Generates a printable first notice letter for the specified invoice
* 
* @param p_Invoice
*            specifies the invoice to generate first notice letter for.
* @param p_LetterDate
*            specifies the offical date for the generated first notice
*            letter.
* @return a printable first notice letter for the specified invoice.
*/
//---------------------------------------------------------------------------

public JasperPrint createNoticePrintObject(int p_NoticeType, Invoice p_Invoice, List<Invoice> p_Invoices, Account p_Account,
		Date p_LetterDate, Date p_SettlementVerificationDate, HashMap<String, Object> p_Parameter) throws Exception 
	{
	Physician 					l_Physician 		= null;
	Date 						l_DateOfInterest 	= null;
	JasperReport 				l_Report 			= null;
	Office 						l_Office 			= null;
//	HashMap<String, Object> 	l_Parameters 		= null;
	JRBeanCollectionDataSource 	l_Fields;
	double 						l_TotalBalance;
	JasperPrint					l_Print				= null;
	Bailiff 					l_Bailiff 			= null;
	
	l_Physician = p_Invoice.getPhysician();
	l_DateOfInterest = p_Invoice.getInvoiceDate();
	
	if (p_NoticeType == c_PrintPaymentOrder)
	{
		l_Bailiff = this.fetchBailiffForInvoice(p_Invoice);
	}

	l_Report = this.createReport(p_NoticeType, l_Physician.getId(), l_DateOfInterest, l_Bailiff);

	this.setupFormatting();

	l_Office = this.getMedicalOffice();

	UtilFormatter l_Formatter = (UtilFormatter) p_Parameter.get("utilFormatter");
	l_Formatter.setBillingPrinter(this);
	
	p_Parameter = this.setCommonParameters  (l_Physician, p_Parameter);
	p_Parameter = this.setInvoiceParameters (p_Invoice, p_Parameter);
	p_Parameter = this.setPatientParameters (p_Invoice.getPatient(), p_Parameter);

	/* ---------------------------------------- */
	// Obsolete parameter. To be removed in later versions. 
	// Replaced by invoice_physician (Common Parameter Set)
	/* ---------------------------------------- */
	
	p_Parameter.put("letter_date", m_DateFormat.format(p_LetterDate));
	
	if (p_NoticeType < c_PrintPaymentOrder)
		{
		// obsolete parameter for reminders
		if (l_Office != null && l_Office.getLatestOfficeAddress() != null)
		    p_Parameter.put("letter_city", l_Office.getLatestOfficeAddress().getLocality());
		
		// calculate the total amount
		if (p_Invoices.isEmpty())
			{
			l_TotalBalance = p_Invoice.getBalance();
			}
		else 
			{
			l_TotalBalance = 0;
			for (Invoice l_Invoice : p_Invoices)
				l_TotalBalance += l_Invoice.getBalance();
			}
		
		p_Parameter.put("dr_name", 						formatPhysicianName(p_Invoice.getPhysician()));
		p_Parameter.put("settlement_verification_date", m_DateFormat.format(p_SettlementVerificationDate));
		p_Parameter.put("invoice_total_balance", 		l_TotalBalance);
		}
	else if (p_NoticeType == c_PrintPaymentOrder)
		{
		// obsolete parameter for payment order
		
		if (l_Bailiff != null)
			p_Parameter.put("bailiff", l_Bailiff.getName());
		else
			p_Parameter.put("bailiff", "");
		
		if (l_Office != null && l_Office.getLatestOfficeAddress() != null)
			p_Parameter.put("letter_city", l_Office.getLatestOfficeAddress().getLocality());
		
		if (p_Account == null)
		{
			log(Level.WARN, "No default banc account set!");
			p_Parameter.put("account",	"");
			p_Parameter.put("bank", 	"");
		}
		else
		{
		// retrieve accounts
			p_Parameter.put("account", 	p_Account.getIban());
			p_Parameter.put("bank", 	p_Account.getBankname());
		}
		p_Parameter.put("bailiff_rate", 			m_NumberFormat.format(this.getBailiffRateForInvoice(p_Invoice)));
		p_Parameter.put("invoice_balance", 			m_NumberFormat.format(p_Invoice.getBalance()));
		p_Parameter.put("invoice_balance_string", 	m_NumberFormat.format(p_Invoice.getBalance()));
		p_Parameter.put("invoice_balance_astext", 	NumberWriter.writeNumber(p_Invoice.getBalance(), Locale.FRENCH, " euro ", 2));
		p_Parameter.put("invoice_balance_spelled", 	NumberWriter.writeNumber(p_Invoice.getBalance(), Locale.FRENCH, " euro ", 2));
		p_Parameter.put("patient_name", 			m_Formatter.formatGuarantorName (p_Invoice.getPatient(), true, false));
		}
	
	
//	UtilSettings settings = (UtilSettings) p_Parameter.get(PrintParameterFetcher.PRINT_PARAMETER_SETTINGS);
//	System.out.println("SVD = " + settings.getSettlementVerificationDate());
//	Invoice invoice = (Invoice) p_Parameter.get(PrintParameterFetcher.PRINT_PARAMETER_INVOICE);
//	System.out.println("I.SD = " + invoice.getSettlementDate());
	
	
	/* ---------------------------------------- */
	// 	PRINT IT
	/* ---------------------------------------- */
	try {
		// prepare the datasource
		l_Fields = new JRBeanCollectionDataSource(InvoiceReportField.createFields(p_Invoices));
		
		// create the InvoicePrint
		l_Print = JasperFillManager.fillReport(l_Report, p_Parameter, l_Fields);
		}
	catch (JRException p_Exception)
		{
		this.log(Level.ERROR, "Report printing with fields failed, now printing without fields ...", p_Exception);
		l_Print = JasperFillManager.fillReport(l_Report, p_Parameter);
		}
	
	return l_Print;
 }


// ---------------------------------------------------------------------------
/**
 * Generates a printable third party statement, composed of the cover page
 * and the list of invoices on the statement.
 * 
 * @param p_Statement specifies the third party statement to generate printable
 *                    object for.
 * @param p_InvoiceStubs specifies the invoice stubs to be put on the list accompanying
 *                       the third party statement cover.
 * @return a printable list third party statement for the specified
 *         statement and the specified invoices.
 */
// ---------------------------------------------------------------------------

public JasperPrint createStatementPrintObject(Statement p_Statement, Collection<InvoiceStub> p_InvoiceStubs, HashMap<String, Object> p_Parameter) throws Exception 
    {
//	Template 		l_CoverTemplate;
	JasperPrint 	l_CoverPrinter;
	JasperPrint 	l_ListPrinter;
	JasperReport 	l_Cover;
	JasperReport 	l_List;
	JRPrintPage 	l_Page;
	UtilSettings 	l_Settings;

	JRBeanCollectionDataSource 	l_Data;
//	HashMap<String, Object> 	l_Parameters;

	Physician 	l_Physician = null;
	Integer 	l_PhysicianId = null;
	Date 		l_DateOfInterest = null;
	Office 		l_MedicalOffice = null;
//	String 		l_PhysicianAddress = null;
	InvoiceStub l_Stub;
	BigDecimal 	l_TotalAmount;
	
	Collection<Physician> 				l_Physicians = null;
	Iterator<Physician> 				l_PhysicianIterator = null;
	Collection<StatementReportField> 	l_Statement = null;
	Iterator<InvoiceStub> 				l_InvoiceStubIterator;

	if (p_Statement == null)
	    return null;

	if (Act.factorsNotSet()) m_InvoiceInterface.initializeFactors();
	InvoiceStub.setMaidenNameIsMarriedName (this.maidenNameIsMarriedName());
	
	// ========================================================================
	// = Step 1 consists in checking whether no, one or more physicians were
	// = specified for this third party statement. If no or more than one
	// = physician were specified, then we're going to use the template specified for
	// = the the medical office. If exactly one physician was specified, then
	// = we're going to fetch the template for that physician.
	// ========================================================================

	l_Physicians = p_Statement.getPhysicians();
	
	if ((l_Physicians == null) || (l_Physicians.isEmpty()) || (l_Physicians.size() > 1)) 
		{
	    l_PhysicianId = Template.OFFICE;
		} 
	else if (l_Physicians.size() == 1) 
		{
	    l_PhysicianIterator = l_Physicians.iterator();
	    if (l_PhysicianIterator.hasNext())
	    	l_Physician = l_PhysicianIterator.next();
	    l_PhysicianId = (l_Physician != null) ? l_Physician.getId(): Template.OFFICE;
		}

	// ========================================================================
	// = Step 2 We're using the end of the statement as the date of
	// interest.
	// ========================================================================

	l_DateOfInterest = p_Statement.getEndDate();

	// ========================================================================
	// = Step 3 consists in trying to get the matching template for the
	// statement
	// cover. If none can be found, we're going to use the default template.
	// ========================================================================

	l_Cover	= m_TemplateManager.findTemplate(JasperTemplateBean.BILLING_STATEMENT_COVER, l_PhysicianId, l_DateOfInterest);
//	l_CoverTemplate = m_TemplateManager.getTemplate(c_ThirdPartyStatementTemplateName, l_PhysicianId,l_DateOfInterest);
//	
//	if (l_CoverTemplate != null) 
//		{
//	    l_Cover = (JasperReport) JRLoader.loadObject(new ByteArrayInputStream(l_CoverTemplate.getJasper()));
//		} 
//	else 
//		{
//		l_Cover = this.getStandardReport (c_StatementCover);
//		}

	// ========================================================================
	// = Step 4 Get the template for the invoice list.
	// ========================================================================
	
	l_List = m_TemplateManager.findTemplate(JasperTemplateBean.BILLING_STATEMENTS);
//	l_List = this.getStandardReport (c_StatementList);

	this.setupFormatting();
	
	p_Parameter = this.setCommonParameters(l_Physician, p_Parameter);
	
	p_Parameter.put(JRJpaQueryExecuterFactory.PARAMETER_JPA_ENTITY_MANAGER,m_EntityManager);

	l_MedicalOffice = this.getMedicalOffice();

	if (l_MedicalOffice != null) 
		{
	    if (Template.OFFICE.equals(l_PhysicianId)) 
	    	{
	    	p_Parameter.put("office_name", l_MedicalOffice.getName());
	    	p_Parameter.put("ucm_code", getOfficeUCM(l_MedicalOffice, l_Physician));
	    	} 
	    else 
	    	{
	    	p_Parameter.put("office_name", formatPhysicianName (l_Physician));
	    	p_Parameter.put("ucm_code", getPhysicianUCM (l_Physician));
	    	}

	    p_Parameter.put("locality_and_date", m_Formatter.formatLocalityAndDate(l_MedicalOffice, new Date(), "dd/MM/yyyy"));
		}

	if (p_Statement != null) 
		{
	    l_Statement = new HashSet<StatementReportField>();
	    l_Statement.add(new StatementReportField(p_Statement));
	    p_Parameter.put("statement_id", 		p_Statement.formatStatementNumber());
	    p_Parameter.put("date_from", 			p_Statement.getStartDate());
	    p_Parameter.put("date_to", 				p_Statement.getEndDate());
	    p_Parameter.put("third_party_payers", 	p_Statement.formatThirdPartyPayers());
		}

	l_Settings = (UtilSettings) p_Parameter.get(PrintParameter.PRINT_PARAMETER_SETTINGS);
	if (p_InvoiceStubs != null) 
		{
	    l_TotalAmount = new BigDecimal(0);

	    l_InvoiceStubIterator = p_InvoiceStubs.iterator();
	    while (l_InvoiceStubIterator.hasNext()) 
	    	{
	    	l_Stub = l_InvoiceStubIterator.next();
	    	l_TotalAmount = InvoiceStub.addToTotal(l_TotalAmount, l_Stub.getAmount());
	    	}
	    p_Parameter.put("number_of_invoices", 	p_InvoiceStubs.size());
	    p_Parameter.put("total_amount", 		InvoiceStub.getTotal(l_TotalAmount));
	    
	    l_Settings.putSetting(UtilSettings.SETTING_TOTAL_AMOUNT, 	InvoiceStub.getTotal(l_TotalAmount));
	    l_Settings.putSetting(UtilSettings.SETTING_INVOICE_COUNT, 	p_InvoiceStubs.size());
		}
	else
		{
	    l_Settings.putSetting(UtilSettings.SETTING_TOTAL_AMOUNT, 	Double.valueOf(0.0));
	    l_Settings.putSetting(UtilSettings.SETTING_INVOICE_COUNT, 	Integer.valueOf(0));
		}

	l_Data = new JRBeanCollectionDataSource(l_Statement);

	l_CoverPrinter = JasperFillManager.fillReport(l_Cover, p_Parameter,l_Data);

	l_Data = new JRBeanCollectionDataSource(p_InvoiceStubs);

	l_ListPrinter = JasperFillManager.fillReport(l_List, p_Parameter,l_Data);

	l_Page = (JRPrintPage) l_CoverPrinter.getPages().get(0);
	l_ListPrinter.addPage(0, l_Page);

	return l_ListPrinter;
    }

// ---------------------------------------------------------------------------
/**
 * Generates a printable list of transactions, executed during the specified
 * period.
 * 
 * @param p_FromDate
 *            specifies start date of the period to get executed
 *            transactions for.
 * @param p_UntilDate
 *            specifies end date of the period to get executed transactions
 *            for.
 * @param p_Physician
 *            specifies the physician to limit transactions to. Specifiy
 *            <code>null</code> if you transactions for all office should be
 *            taken into account.
 * @return a printable list of transactions for the specified period and
 *         physician.
 */
// ---------------------------------------------------------------------------

@TransactionAttribute(TransactionAttributeType.NEVER)
public JasperPrint createTransactionList(Date p_FromDate, Date p_UntilDate,
	    								 Physician p_Physician, GecamedUser p_Cashier,
	    								 Boolean p_EffectiveTransactions, Boolean p_IncludeTransfers,
	    								 Boolean p_OnlyTotals, HashMap<String, Object> p_Parameters) throws Exception 
	{
	JasperReport l_TransactionList = null;
	HashMap<String, Object> l_Parameters = null;
	HashMap<Integer, Settlement> l_Settlements = null;
	Collection<Transaction> l_Transactions = null;

	JRBeanCollectionDataSource l_DataSource = null;
	JasperPrint l_TransactionPrinter = null;

	this.setupFormatting();

	l_TransactionList = m_TemplateManager.findTemplate(JasperTemplateBean.BILLING_TRANSACTIONS);
//	l_TransactionList = this.getStandardReport (c_TransactionList);
	

	// create an HashMap to store the Parameters
	l_Parameters = new HashMap<String, Object>(p_Parameters);
	l_Parameters = this.setCommonParameters (p_Physician, l_Parameters);
	
	// set the EntityManager for the reportcreator
	l_Parameters.put(JRJpaQueryExecuterFactory.PARAMETER_JPA_ENTITY_MANAGER,m_EntityManager);
	
	l_Parameters.put("list_printing_date", new Date());
	l_Parameters.put("list_from_date", p_FromDate);
	l_Parameters.put("list_until_date", p_UntilDate);

	if (p_IncludeTransfers)
	    l_Settlements = this.getSettlementLookup(c_AllSettlements);
	else
	    l_Settlements = this.getSettlementLookup(c_OnlyPayments);

	l_Parameters.put("settlements", l_Settlements);
	l_Parameters.put("cashiers", this.getUserLookup());
	l_Parameters.put("only_totals", p_OnlyTotals);

	if (p_Cashier != null) l_Parameters.put("cashier_id", p_Cashier.getId());

	l_Transactions = null;

	if (p_Physician != null) 
		{
		l_Parameters.put("physician_id", p_Physician.getId());
	    l_Transactions = this.fetchTransactionsForPhysician(p_Physician,p_FromDate, p_UntilDate, p_Cashier, l_Settlements);
		} 
	else 
		{
	    l_Transactions = this.fetchTransactionsForOffice(p_FromDate,p_UntilDate, p_Cashier, l_Settlements);
		}

	if (p_EffectiveTransactions)
	    l_Transactions = this.filterEffectiveTransactions(l_Transactions);

	l_DataSource = new JRBeanCollectionDataSource(l_Transactions);
	l_TransactionPrinter = JasperFillManager.fillReport(l_TransactionList,l_Parameters, l_DataSource);
	return l_TransactionPrinter;
    }

// ---------------------------------------------------------------------------
/**
 * Generates a printable list of issued invoices
 * 
 * @param p_IssuedInvoices
 *            specifies the issued invoices to generate a printable list
 *            from.
 * @param p_From
 *            specifies the start date to be put on the list.
 * @param p_Until
 *            specifies the end date to be put on the list.
 * @return a printable list generated from the specified invoices with the
 *         specified dates.
 */
// ---------------------------------------------------------------------------

public JasperPrint createIssuedInvoiceList (Collection<InvoiceStub> p_IssuedInvoices, Date p_From,
	    									Date p_Until, Boolean p_OnlyTotals, HashMap<String, Object> p_Parameters) throws Exception 
	{
	JasperReport l_Report = null;
	JasperPrint l_IssuedInvoicePrinter = null;
	JRBeanCollectionDataSource l_IssuedInvoices = null;

	HashMap<String, Object> l_Parameters = null;
	
	if (Act.factorsNotSet()) m_InvoiceInterface.initializeFactors();
	
	this.setupFormatting();
	
//	l_Report = this.getStandardReport (c_IssuedInvoiceList);
	l_Report = this.getStandardReport (JasperTemplateBean.BILLING_ISSUED_INVOICES);

	l_Parameters = new HashMap<String, Object>(p_Parameters);
	l_Parameters = this.setCommonParameters(null, l_Parameters);
	
	l_Parameters.put(JRJpaQueryExecuterFactory.PARAMETER_JPA_ENTITY_MANAGER,m_EntityManager);

	l_Parameters.put("list_from_date", p_From);
	l_Parameters.put("list_until_date", p_Until);
	l_Parameters.put("list_printing_date", new Date());
	l_Parameters.put("only_totals", p_OnlyTotals);
	l_Parameters.put("physicians", this.getPhysicianLookup());
	l_Parameters.put("insurances", getInsuranceLookup());
	l_Parameters.put("states", m_InvoiceStates);

	l_IssuedInvoices = new JRBeanCollectionDataSource(p_IssuedInvoices);
	l_IssuedInvoicePrinter = JasperFillManager.fillReport(l_Report,l_Parameters, l_IssuedInvoices);

	return l_IssuedInvoicePrinter;
    }

// ---------------------------------------------------------------------------
/**
 * Generates a printable list for the specified list of activities
 * 
 * @param p_Activities
 *            specifies the activities to generate printable list from.
 * @param p_From
 *            specifies the start date to be put on list of activities.
 * @param p_Until
 *            specifies the end date to be put on list of activities.
 * @return a printable list generated from the specified activities with the
 *         specified dates.
 */
// ---------------------------------------------------------------------------

public JasperPrint createActivityList(Collection<Activity> p_Activities, Date p_From, Date p_Until, HashMap<String, Object> p_Parameters) throws Exception 
	{
	JasperReport l_Report = null;
	JasperPrint l_ActivityPrinter = null;
	JRBeanCollectionDataSource l_Activities = null;

	HashMap<String, Object> l_Parameters = null;

	if (Act.factorsNotSet()) m_InvoiceInterface.initializeFactors();

	this.setupFormatting();
	
//	l_Report = this.getStandardReport (c_ActivityList);
	l_Report = this.getStandardReport (JasperTemplateBean.BILLING_ACTIVITIES);

	l_Parameters = new HashMap<String, Object>(p_Parameters);
	l_Parameters = this.setCommonParameters (null, l_Parameters);
	
	// set the EntityManager for the reportcreator
	l_Parameters.put(JRJpaQueryExecuterFactory.PARAMETER_JPA_ENTITY_MANAGER,m_EntityManager);

	l_Parameters.put("list_from_date", p_From);
	l_Parameters.put("list_until_date", p_Until);
	l_Parameters.put("list_printing_date", new Date());
	l_Parameters.put("physicians", this.getPhysicianLookup());

	l_Activities = new JRBeanCollectionDataSource(p_Activities);
	l_ActivityPrinter = JasperFillManager.fillReport(l_Report,l_Parameters, l_Activities);

	return l_ActivityPrinter;
    }

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

    public void relocalize() {
	m_InvoiceStates = new HashMap<Integer, String>();

	m_InvoiceStates.put(
			Integer.valueOf(InvoiceWorkflow.c_NewState),
			Translatrix.getTranslationString("InvoiceStates."
				 	  + InvoiceWorkflow.m_StateNames[InvoiceWorkflow.c_NewState]));
	m_InvoiceStates.put(
			Integer.valueOf(InvoiceWorkflow.c_OpenState),
			Translatrix.getTranslationString("InvoiceStates."
					  + InvoiceWorkflow.m_StateNames[InvoiceWorkflow.c_OpenState]));
	m_InvoiceStates.put(
			Integer.valueOf(InvoiceWorkflow.c_VerifiedState),
			Translatrix.getTranslationString("InvoiceStates."
					+ InvoiceWorkflow.m_StateNames[InvoiceWorkflow.c_VerifiedState]));
	m_InvoiceStates.put(
			Integer.valueOf(InvoiceWorkflow.c_ClosedState),
			Translatrix.getTranslationString("InvoiceStates."
					+ InvoiceWorkflow.m_StateNames[InvoiceWorkflow.c_ClosedState]));
	m_InvoiceStates.put(
			Integer.valueOf(InvoiceWorkflow.c_PrintedState),
			Translatrix.getTranslationString("InvoiceStates."
					+ InvoiceWorkflow.m_StateNames[InvoiceWorkflow.c_PrintedState]));
	m_InvoiceStates.put(
			Integer.valueOf(InvoiceWorkflow.c_PaidState),
			Translatrix.getTranslationString("InvoiceStates."
					+ InvoiceWorkflow.m_StateNames[InvoiceWorkflow.c_PaidState]));
	m_InvoiceStates.put(
			Integer.valueOf(InvoiceWorkflow.c_RemindedState),
			Translatrix.getTranslationString("InvoiceStates."
					+ InvoiceWorkflow.m_StateNames[InvoiceWorkflow.c_RemindedState]));
	m_InvoiceStates.put(
			Integer.valueOf(InvoiceWorkflow.c_CanceledState),
			Translatrix.getTranslationString("InvoiceStates."
					+ InvoiceWorkflow.m_StateNames[InvoiceWorkflow.c_CanceledState]));
	m_InvoiceStates.put(
			Integer.valueOf(InvoiceWorkflow.c_DeletedState),
			Translatrix.getTranslationString("InvoiceStates."
					+ InvoiceWorkflow.m_StateNames[InvoiceWorkflow.c_DeletedState]));
    }

//---------------------------------------------------------------------------
//***************************************************************************
//* End of Class 															*
//***************************************************************************
//---------------------------------------------------------------------------
}
