/*******************************************************************************
 * 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.gui.print;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;

import javax.swing.JOptionPane;

import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Account;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Activity;
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.Statement;
import lu.tudor.santec.gecamed.billing.ejb.session.beans.BillingPrinterBean;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.BillingPrinterInterface;
import lu.tudor.santec.gecamed.billing.gui.BillingModule;
import lu.tudor.santec.gecamed.billing.gui.invoice.stub.InvoiceStubComparator;
import lu.tudor.santec.gecamed.billing.gui.reminder.ReminderPanel;
import lu.tudor.santec.gecamed.billing.utils.InvoiceWorkflow;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.widgets.PrintPreviewDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.print.PrintParameterFetcher;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser;
import lu.tudor.santec.i18n.Relocalizable;
import lu.tudor.santec.i18n.Translatrix;
import net.sf.jasperreports.engine.JasperPrint;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

/**
 * this class has functionality to print invoices.
 * 
 * 
 * @author Johannes Hermen johannes.hermen(at)tudor.lu
 *
 */
//***************************************************************************
//* Class Definition and Members                                            *
//***************************************************************************

public class InvoicePrinter implements  Relocalizable
	{
	private PrintPreviewDialog 		m_PrintPreviewDialog;
	private JasperPrint				m_PrintData;
	private boolean 				m_PrintImmediately;
	
	private int						m_MaxJobsInQueue;
	private int						m_QueueSizeRetries;
	private long					m_QueueSizeDelay;
 	private int						m_JobAcceptanceRetries;
	private long					m_JobAcceptanceDelay;
	
	private Exception				m_Exception;
	private int						m_Status;
	
	private BillingPrinterInterface	 m_PrinterInterface;	
	
	private static Logger m_Logger = Logger.getLogger(InvoicePrinter.class.getName()); 
    
	public static final int		c_NoError				= 0;
	public static final int		c_TooManyJobsInQueue	= 1;
	public static final int		c_DidNotAcceptJobs		= 2;
	public static final int		c_PrinterError			= 3;
	
	private static final int	c_Retries 		 = 30;
	private static final int	c_MaxJobsInQueue = 10;
	private static final long	c_Delay			 = 1000;
	private static final float 	c_Hysteresis	 = 0.25f;
	
	
	
//***************************************************************************
//* Constructors                                       						*
//***************************************************************************
	
public InvoicePrinter() 
	{	
	
	m_PrintPreviewDialog = new PrintPreviewDialog();
	
	m_PrinterInterface = null;
	
	m_PrintData = new JasperPrint();
	
	m_MaxJobsInQueue 		= c_MaxJobsInQueue;
	m_QueueSizeRetries		= c_Retries;
	m_QueueSizeDelay		= c_Delay;
	m_JobAcceptanceRetries	= c_Retries;
	m_JobAcceptanceDelay	= c_Delay;
	
	m_Exception = null;
	
	this.relocalize();
	}
	
//---------------------------------------------------------------------------
//***************************************************************************
//* Class Primitives                                                        *
//***************************************************************************
//---------------------------------------------------------------------------

private BillingPrinterInterface getPrinterInterface ()
	{
	if (m_PrinterInterface != null) return m_PrinterInterface;
	
	try {
		m_PrinterInterface = (BillingPrinterInterface) ManagerFactory.getRemote(BillingPrinterBean.class);
		} 
	catch (Exception p_Exception) 
		{
		m_Logger.log(Level.WARN, "Couldn't get BillingPrinterBean", p_Exception);
		p_Exception.printStackTrace();
		}
	
	return m_PrinterInterface;
	}

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

private synchronized void sleep (long p_Delay)
	{
	try	{
		this.wait(p_Delay);
		}
	catch (InterruptedException p_Exception)
		{
		m_Logger.log(Level.WARN, "Failed to sleep!", p_Exception);
		}
	}

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

private boolean checkAndWaitForQueueSize ()
	{
	int	l_JobsInQueue	= 0;
	int	l_LowerTreshold	= 0;
	int	l_Retries		= 0;
	
	l_JobsInQueue = m_PrintPreviewDialog.getQueuedJobCount();
	
	if (l_JobsInQueue >= m_MaxJobsInQueue)
		{
		l_LowerTreshold = m_MaxJobsInQueue - Math.round((float)m_MaxJobsInQueue * c_Hysteresis);
	
		m_Logger.log(Level.INFO, "Number of Jobs in Queue greater or equal than " + m_MaxJobsInQueue +
								 "! Waiting for number of jobs to go down to " + l_LowerTreshold);
	
		while ((l_JobsInQueue > l_LowerTreshold) && (l_Retries < m_QueueSizeRetries))
			{
			this.sleep(m_QueueSizeDelay);
			l_JobsInQueue = m_PrintPreviewDialog.getQueuedJobCount();
			l_Retries++;
			}
		}	
	
	if (l_Retries >= m_QueueSizeRetries)
		{
		m_Status = c_TooManyJobsInQueue;
		return false;
		}
	else 
		{
		m_Status = c_NoError;
		return true;
		}
	}

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

private boolean waitForQueueToAcceptJobs ()
	{
	int		l_Retries		= 0;
	boolean l_AcceptsJobs	= false;
	
	while ((l_AcceptsJobs == false) && (l_Retries < m_JobAcceptanceRetries))
		{
		switch (m_PrintPreviewDialog.getStatus())
			{
			case PrintPreviewDialog.ACCEPTING_JOBS:
			
				l_AcceptsJobs = true;
				m_Status = c_NoError;
				break;
		
			case PrintPreviewDialog.NOT_ACCEPTING_JOBS:
			
				this.sleep(m_JobAcceptanceDelay);
				m_Status = c_DidNotAcceptJobs;
				l_Retries++;
				break;
			}
		}
	
	return l_AcceptsJobs;
	}


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

private boolean isAcceptingJobs ()
	{
	boolean	l_AcceptsJobs = false;
	
	if (m_PrintPreviewDialog.getStatus() == PrintPreviewDialog.ACCEPTING_JOBS)
		{
		l_AcceptsJobs = this.checkAndWaitForQueueSize();
		}
	else
		{	
		l_AcceptsJobs = this.waitForQueueToAcceptJobs();	
		}
	
	return l_AcceptsJobs;
	}

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

private void checkPrinterStatus ()
	{
	m_Exception = m_PrintPreviewDialog.getException();	
	if (m_Exception != null) m_Status = c_PrinterError;
	}

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

public static Collection <InvoiceStub> sortCollection (Collection <InvoiceStub> p_UnsortedCollection,
												 int p_SortingProperty, int p_SortDirection)
	{											
	int							l_Index;
	InvoiceStub[]				l_UnsortedArray;
	Collection <InvoiceStub>	l_SortedCollection;
	InvoiceStubComparator		l_Comparator;
	
	l_UnsortedArray = new InvoiceStub [p_UnsortedCollection.size()];
	l_UnsortedArray = p_UnsortedCollection.toArray(l_UnsortedArray);
	
	l_Comparator = new InvoiceStubComparator ();
	l_Comparator.addSortCriterion(InvoiceStubComparator.c_Grouping, InvoiceStubComparator.c_Ascending);
	l_Comparator.addSortCriterion(p_SortingProperty, p_SortDirection);
		
	Arrays.sort (l_UnsortedArray,l_Comparator);

	l_SortedCollection = new LinkedHashSet <InvoiceStub> ();
	for (l_Index = 0; l_Index < p_UnsortedCollection.size(); l_Index++)
		{
		l_SortedCollection.add (l_UnsortedArray [l_Index]);
		}
	
	return l_SortedCollection;
	
	}
//---------------------------------------------------------------------------

//***************************************************************************
//* Class Body		                                                        *
//***************************************************************************
//---------------------------------------------------------------------------

public void setPrintImmediately (boolean p_Immediately)
	{
	m_PrintImmediately = p_Immediately;
	}
	
//---------------------------------------------------------------------------

public void setMaxJobsInQueue (int p_NumberOfJobs)
	{
	m_MaxJobsInQueue = p_NumberOfJobs;
	}

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

public void setQueueSizeDelay (long p_Delay)
	{
	m_QueueSizeDelay = p_Delay;
	}

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

public void setQueueSizeRetries (int p_Retries)
	{
	m_QueueSizeRetries = p_Retries;
	}

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

public void setJobAcceptanceDelay (long p_Delay)
	{
	m_JobAcceptanceDelay = p_Delay;
	}

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

public void setJobAcceptanceRetries (int p_Retries)
	{
	m_JobAcceptanceRetries = p_Retries;
	}

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

public Exception getException ()
	{
	return m_Exception;
	}

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

public int getStatus ()
	{
	return m_Status;
	}

//---------------------------------------------------------------------------
	
public boolean printInvoice (Invoice p_Invoice, boolean p_PrintCopy, boolean p_AskToPrintCopy, HashMap<String, Object> p_Parameter) 
	{
	return this.printInvoice (p_Invoice, 1, p_PrintCopy, p_AskToPrintCopy, p_Parameter);
	}	
	
//---------------------------------------------------------------------------

public boolean printInvoice (Invoice p_Invoice, int p_NumberOfCopies, boolean p_PrintCopy, boolean p_AskToPrintCopy, HashMap<String, Object> p_Parameter) 
	{
	BillingPrinterInterface l_PrinterInterface;
	boolean					l_WasPrinted	= false;
	Integer					l_InvoiceState	= p_Invoice.getState();
	Date					l_PrintDate		= p_Invoice.getPrintDate();
	
	
	l_PrinterInterface = this.getPrinterInterface();
	if (l_PrinterInterface == null) return l_WasPrinted;
	
	if (this.isAcceptingJobs() == false) return false;
	
	Boolean forceOriginal = Boolean.FALSE;
	if (p_PrintCopy && p_AskToPrintCopy)
	{
		// ask to print a copy
		forceOriginal = PrintCopyDialog.showDialog();
		
		if (forceOriginal == null)
			return false;
	}
	
	try {		
		m_Exception = null;
		p_Invoice.monetize();
		m_PrintData = l_PrinterInterface.createInvoicePrintObject (p_Invoice, p_PrintCopy, p_Parameter, forceOriginal);
		if (m_PrintData != null)
			{
			m_PrintData.setName("INV_" + p_Invoice.formatInvoiceNumber(Invoice.c_ShortFormat, true));
			l_WasPrinted = m_PrintPreviewDialog.doPrint (m_PrintData, m_PrintImmediately, p_NumberOfCopies);
			if (l_WasPrinted)
				{
				if (!p_Invoice.alreadyPrinted()) 
					{
					// TODO set new print and due date if it was an original print
					p_Invoice.setPrintDate(new Date());
					p_Invoice.setDueDate(false);
					}
				}
			else this.checkPrinterStatus();	
			}
		} 
	catch (Exception p_Exception) 
		{
		m_Exception = p_Exception;
		m_Logger.log(Level.WARN, "Failed to print Invoice!", p_Exception);
		p_Exception.printStackTrace();
		l_WasPrinted = false;
		}
	finally
		{
		if (p_Invoice.getState().intValue() > InvoiceWorkflow.c_PrintedState)
			p_Invoice.setState(l_InvoiceState);
		if (l_PrintDate != null)
			p_Invoice.setPrintDate(l_PrintDate);
		}
	
	
	return l_WasPrinted;
	}	

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

public boolean printReminderList (Collection <InvoiceStub> p_InvoiceStubs, String p_Title, 
								  int p_SortingProperty, int p_SortDirection, HashMap<String, Object> p_Parameter, Integer groupType)
	{
	BillingPrinterInterface 	l_PrinterInterface;
	boolean						l_WasPrinted = false;
	Collection <InvoiceStub>	l_SortedInvoiceStubs;
	
	l_PrinterInterface = this.getPrinterInterface();
	if (l_PrinterInterface == null) return false;
	
	if (this.isAcceptingJobs() == false) return l_WasPrinted;


	// set the grouping string regarding to the selected printing type
	if (groupType != null) {
		p_InvoiceStubs = this.setStubGroupingString(p_InvoiceStubs, groupType);		
	}
	
	// sort by grouping string and table search criteria
	l_SortedInvoiceStubs = this.sortCollection(p_InvoiceStubs, p_SortingProperty, p_SortDirection);
	
	try {		
		m_Exception = null;
		m_PrintData = l_PrinterInterface.createReminderList(l_SortedInvoiceStubs, p_Title, p_Parameter);
		if (m_PrintData != null)
			{
			l_WasPrinted = m_PrintPreviewDialog.doPrint(m_PrintData, m_PrintImmediately, 1);
			if (!l_WasPrinted) this.checkPrinterStatus();	
			}
		} 
	catch (Exception p_Exception) 
		{
		m_Exception = p_Exception;
		m_Logger.log(Level.WARN, "Failed to print Reminder List!", p_Exception);
		p_Exception.printStackTrace();
		l_WasPrinted = false;
		}
	
	return l_WasPrinted;
	}

public static Collection<InvoiceStub> setStubGroupingString(Collection<InvoiceStub> p_InvoiceStubs, int type) {
	DateFormat sortableDateFormat = new SimpleDateFormat("yyyy-MM");
	for (InvoiceStub invoiceStub : p_InvoiceStubs) {
		switch (type) {
		case InvoiceStubComparator.GROUP_NONE:
			invoiceStub.setGroupingString("");
			break;
		case InvoiceStubComparator.GROUP_PHYSICIAN:
			invoiceStub.setGroupingString(invoiceStub.getPhysician()+"");
			break;
		case InvoiceStubComparator.GROUP_BAILIF:
			invoiceStub.setGroupingString(invoiceStub.getBailif()+"");
			break;
		case InvoiceStubComparator.GROUP_BAILIF_MONTH:
			invoiceStub.setGroupingString(invoiceStub.getBailif()+" "+sortableDateFormat.format(invoiceStub.getInvoiceDate()));
			break;
		default:
			invoiceStub.setGroupingString("");
			break;
		}
	}
	return p_InvoiceStubs;
}

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

public boolean printInvoiceList (Collection <InvoiceStub> p_InvoiceStubs, 
								  int p_SortingProperty, int p_SortDirection, HashMap<String, Object> p_Parameter)
	{
	BillingPrinterInterface 	l_PrinterInterface;
	boolean						l_WasPrinted = false;
	Collection <InvoiceStub>	l_SortedInvoiceStubs;
	
	l_PrinterInterface = this.getPrinterInterface();
	if (l_PrinterInterface == null) return false;
	
	if (this.isAcceptingJobs() == false) return l_WasPrinted;

	l_SortedInvoiceStubs = this.sortCollection(p_InvoiceStubs, p_SortingProperty, p_SortDirection);
	
	try {		
		m_Exception = null;
		m_PrintData = l_PrinterInterface.createInvoiceList(l_SortedInvoiceStubs, p_Parameter);
		if (m_PrintData != null)
			{
			l_WasPrinted = m_PrintPreviewDialog.doPrint(m_PrintData, m_PrintImmediately, 1);
			if (!l_WasPrinted) this.checkPrinterStatus();	
			}
		} 
	catch (Exception p_Exception) 
		{
		m_Exception = p_Exception;
		m_Logger.log(Level.WARN, "Failed to print Reminder List!", p_Exception);
		p_Exception.printStackTrace();
		l_WasPrinted = false;
		}
	
	return l_WasPrinted;
	}

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


public boolean printReminder (int p_ReminderType, Invoice p_Invoice, List<Invoice> p_Invoices, Account p_Account, Date p_LetterDate, 
		Date p_SettlementVerificationDate, int p_NumberOfCopies, HashMap<String, Object> p_Parameter)
	{
	BillingPrinterInterface l_PrinterInterface;
	boolean					l_WasPrinted = false;
	
	String 					l_NamePrefix;
	String					l_ErrorMessage;
	
	switch (p_ReminderType)
	{
	case BillingPrinterBean.c_PrintFirstNotice:
		l_NamePrefix 	= "REM1_";
		l_ErrorMessage 	= "Failed to print first reminder!";
		break;

	case BillingPrinterBean.c_PrintLastNotice:
		l_NamePrefix 	= "REM2_";
		l_ErrorMessage 	= "Failed to print second reminder!";
		break;

	case BillingPrinterBean.c_PrintPaymentOrder:
		l_NamePrefix 	= "REM3_";
		l_ErrorMessage 	= "Failed to print payment order!";
		break;

	default:
		m_Logger.warn("Unsupported reminder type \""+p_ReminderType+"\". Trying to print anyway.");
		l_NamePrefix 	= "REM_";
		l_ErrorMessage 	= "Failed to print reminder!";
		break;
	}
	
	l_PrinterInterface = this.getPrinterInterface();
	if (l_PrinterInterface == null) return l_WasPrinted;
	
	if (this.isAcceptingJobs() == false) return false;

	try {
		m_Exception = null;
//		p_Invoice.monetize();
//		m_PrintData = l_PrinterInterface.createFirstNoticePrintObject(p_Invoice, p_Invoices, p_LetterDate,p_SettlementVerificationDate);
		m_PrintData = l_PrinterInterface.createNoticePrintObject(p_ReminderType, p_Invoice, p_Invoices, p_Account, p_LetterDate,p_SettlementVerificationDate, p_Parameter);
		if (m_PrintData != null)
			{
			m_PrintData.setName(l_NamePrefix + p_Invoice.formatInvoiceNumber(Invoice.c_ShortFormat, true));
			l_WasPrinted = m_PrintPreviewDialog.doPrint (m_PrintData, m_PrintImmediately, p_NumberOfCopies);
			if (!l_WasPrinted) this.checkPrinterStatus();	
			}
		}
	catch (Exception p_Exception) 
		{
		m_Exception = p_Exception;
		m_Logger.log(Level.WARN, l_ErrorMessage, p_Exception);
		p_Exception.printStackTrace();
		l_WasPrinted = false;
		}
	
	return l_WasPrinted;
	}

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

//public boolean printFirstReminder (Invoice p_Invoice, List<Invoice> p_Invoices, 
//		Date p_LetterDate, Date p_SettlementVerificationDate, int p_NumberOfCopies)
//	{
//	BillingPrinterInterface l_PrinterInterface;
//	boolean					l_WasPrinted = false;
//	
//	l_PrinterInterface = this.getPrinterInterface();
//	if (l_PrinterInterface == null) return l_WasPrinted;
//	
//	if (this.isAcceptingJobs() == false) return false;
//
//	try {
//		m_Exception = null;
////		p_Invoice.monetize();
////		m_PrintData = l_PrinterInterface.createFirstNoticePrintObject(p_Invoice, p_Invoices, p_LetterDate,p_SettlementVerificationDate);
//		m_PrintData = l_PrinterInterface.createNoticePrintObject(BillingPrinterBean.c_FirstNotice, p_Invoice, p_Invoices, p_LetterDate,p_SettlementVerificationDate);
//		if (m_PrintData != null)
//			{
//			m_PrintData.setName("REM1_" + p_Invoice.formatInvoiceNumber(Invoice.c_ShortFormat));
//			l_WasPrinted = m_PrintPreviewDialog.doPrint (m_PrintData, m_PrintImmediately, p_NumberOfCopies);
//			if (!l_WasPrinted) this.checkPrinterStatus();	
//			}
//		}
//	catch (Exception p_Exception) 
//		{
//		m_Exception = p_Exception;
//		m_Logger.log(Level.WARN, "Failed to print First Reminder!", p_Exception);
//		p_Exception.printStackTrace();
//		l_WasPrinted = false;
//		}
//	
//	return l_WasPrinted;
//	}


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

//public boolean printSecondReminder (Invoice p_Invoice, List<Invoice> p_Invoices, 
//		Date p_LetterDate, Date p_SettlementVerificationDate, int p_NumberOfCopies)
//	{
//	BillingPrinterInterface l_PrinterInterface;
//	boolean					l_WasPrinted = false;
//	
//	l_PrinterInterface = this.getPrinterInterface();
//	if (l_PrinterInterface == null) return l_WasPrinted;
//	
//	if (this.isAcceptingJobs() == false) return false;
//
//	try {		
//		m_Exception = null;
////		p_Invoice.monetize();
////		m_PrintData = l_PrinterInterface.createSecondNoticePrintObject (p_Invoice, p_Invoices, p_LetterDate,p_SettlementVerificationDate);
//		m_PrintData = l_PrinterInterface.createNoticePrintObject (BillingPrinterBean.c_SecondNotice, p_Invoice, p_Invoices, p_LetterDate,p_SettlementVerificationDate);
//		if (m_PrintData != null)
//			{
//			m_PrintData.setName("REM2_" + p_Invoice.formatInvoiceNumber(Invoice.c_ShortFormat));
//			l_WasPrinted = m_PrintPreviewDialog.doPrint (m_PrintData, m_PrintImmediately, p_NumberOfCopies);
//			if (!l_WasPrinted) this.checkPrinterStatus();	
//			}
//		}
//	catch (Exception p_Exception) 
//		{
//		m_Exception = p_Exception;
//		m_Logger.log(Level.WARN, "Failed to print Second Reminder!", p_Exception);
//		p_Exception.printStackTrace();
//		l_WasPrinted = false;
//		}
//	
//	return l_WasPrinted;
//	}

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

//public boolean printPaymentOrder (Invoice p_Invoice, Account p_Account, Date p_LetterDate, 
//		int p_NumberOfCopies, HashMap<String, Object> p_Parameter)
//	{
//	BillingPrinterInterface l_PrinterInterface;
//	boolean					l_WasPrinted = false;
//	
//	l_PrinterInterface = this.getPrinterInterface();
//	if (l_PrinterInterface == null) return l_WasPrinted;
//	
//	if (this.isAcceptingJobs() == false) return false;
//
//	try {		
//		m_Exception = null;
//		p_Invoice.monetize();
//		
//		m_PrintData = l_PrinterInterface.createDemandOfPaymentPrintObject(p_Invoice, p_Account, p_LetterDate, p_Parameter);
//		if (m_PrintData != null)
//			{
//			m_PrintData.setName("REM3_" + p_Invoice.formatInvoiceNumber(Invoice.c_ShortFormat));
//			l_WasPrinted = m_PrintPreviewDialog.doPrint (m_PrintData, m_PrintImmediately, p_NumberOfCopies);
//			if (!l_WasPrinted) this.checkPrinterStatus();	
//			}
//		}
//	catch (Exception p_Exception) 
//		{
//		m_Exception = p_Exception;
//		m_Logger.log(Level.WARN, "Failed to print Payment Order!", p_Exception);
//		p_Exception.printStackTrace();
//		l_WasPrinted = false;
//		}
//	
//	return l_WasPrinted;
//	}

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

public boolean printStatementCover (Statement p_Statement, Collection <InvoiceStub> p_InvoiceStubs, String p_UCMCode) 
	{
	BillingPrinterInterface l_PrinterInterface;
	boolean					l_WasPrinted = false;
	HashMap<String, Object> l_Parameter;
	
	l_PrinterInterface = this.getPrinterInterface();
	if (l_PrinterInterface == null) return l_WasPrinted;
	
	if (this.isAcceptingJobs() == false) return false;

	l_Parameter = PrintParameterFetcher.createDefaultPrintParameter(p_InvoiceStubs);
	
	try {		
		m_Exception = null;
		m_PrintData = l_PrinterInterface.createStatementPrintObject (p_Statement, p_InvoiceStubs, l_Parameter);
		if (m_PrintData != null)
			{
			l_WasPrinted = m_PrintPreviewDialog.doPrint(m_PrintData, m_PrintImmediately, 1);
			if (!l_WasPrinted) this.checkPrinterStatus();	
			}
		} 
	catch (Exception p_Exception) 
		{
		m_Exception = p_Exception;
		m_Logger.log(Level.WARN, "Failed to print Statement List!", p_Exception);
		p_Exception.printStackTrace();
		l_WasPrinted = false;
		}

return l_WasPrinted;
	}	

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

public boolean printTransactionList (Date p_FromDate, Date p_UntilDate,
									 Physician 		p_Physician,
									 GecamedUser	p_Cashier,
									 boolean 		p_EffectiveTransactions,
									 boolean        p_IncludeTransfers,
									 boolean		p_OnlyTotals) 
	{
	BillingPrinterInterface l_PrinterInterface;
	boolean					l_WasPrinted = false;
		
	l_PrinterInterface = this.getPrinterInterface();
	if (l_PrinterInterface == null) return false;

	if (this.isAcceptingJobs() == false) return false;
			
	try {		
		m_Exception = null;
		m_PrintData = l_PrinterInterface.createTransactionList (p_FromDate, 
																p_UntilDate, 
															    p_Physician,
															    p_Cashier,
															    p_EffectiveTransactions,
															    p_IncludeTransfers,
															    p_OnlyTotals, 
															    PrintParameterFetcher.createDefaultPrintParameter());
		if (m_PrintData != null)
			{
			l_WasPrinted = m_PrintPreviewDialog.doPrint(m_PrintData, m_PrintImmediately, 1);
			if (!l_WasPrinted) this.checkPrinterStatus();	
			}
		} 
	catch (Exception p_Exception) 
		{
		m_Exception = p_Exception;
		m_Logger.log(Level.WARN, "Failed to print payment list!", p_Exception);
		p_Exception.printStackTrace();
		l_WasPrinted = false;
		}
	return l_WasPrinted;
	}	

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

public boolean printIssuedInvoiceList (Collection <InvoiceStub> p_IssuedInvoices, 
								  	   Date p_From, Date p_Until,
								  	   boolean p_OnlyTotals)
	{
	BillingPrinterInterface 	l_PrinterInterface;
	boolean						l_WasPrinted = false;
	Collection <InvoiceStub>	l_IssuedInvoices;
	
	InvoiceStubComparator		l_Comparator;
	
	InvoiceStub []				l_InvoiceStubs;
	int							l_Index;
	
	l_PrinterInterface = this.getPrinterInterface();
	if (l_PrinterInterface == null) return false;
	
	if (this.isAcceptingJobs() == false) return l_WasPrinted;

	l_InvoiceStubs = new InvoiceStub [p_IssuedInvoices.size()];
	l_InvoiceStubs = p_IssuedInvoices.toArray(l_InvoiceStubs);
		
	l_Comparator = new InvoiceStubComparator ();
	l_Comparator.addSortCriterion(InvoiceStubComparator.c_PhysicianId,     InvoiceStubComparator.c_Ascending);
	l_Comparator.addSortCriterion(InvoiceStubComparator.c_State,           InvoiceStubComparator.c_Ascending);
	l_Comparator.addSortCriterion(InvoiceStubComparator.c_PatientFullName, InvoiceStubComparator.c_Ascending);
		
	Arrays.sort (l_InvoiceStubs,l_Comparator);

	l_IssuedInvoices = new LinkedHashSet <InvoiceStub> ();

	for (l_Index = 0; l_Index < l_InvoiceStubs.length; l_Index++)
		{
		l_IssuedInvoices.add (l_InvoiceStubs [l_Index]);
		}
	
	try {		
		m_Exception = null;
		m_PrintData = l_PrinterInterface.createIssuedInvoiceList(l_IssuedInvoices, p_From, p_Until,p_OnlyTotals, 
				PrintParameterFetcher.createDefaultPrintParameter());
		if (m_PrintData != null)
			{
			l_WasPrinted = m_PrintPreviewDialog.doPrint(m_PrintData, m_PrintImmediately, 1);
			if (!l_WasPrinted) this.checkPrinterStatus();	
			}
		} 
	catch (Exception p_Exception) 
		{
		m_Exception = p_Exception;
		m_Logger.log(Level.WARN, "Failed to print Issued Invoices List!", p_Exception);
		p_Exception.printStackTrace();
		l_WasPrinted = false;
		}
	
	return l_WasPrinted;
	}

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

public boolean printActivityList (Collection <Activity> p_Activities, 
								  Date p_From, Date p_Until)
	{
	BillingPrinterInterface 	l_PrinterInterface;
	boolean						l_WasPrinted = false;
	Collection <Activity>		l_SortedActivities;
	Iterator <Activity>			l_ActivityIterator;
	ActivityComparator			l_Comparator;
	
	Activity []					l_Activities;
	int							l_Index;
	
	l_PrinterInterface = this.getPrinterInterface();
	if (l_PrinterInterface == null) return false;
	
	if (this.isAcceptingJobs() == false) return l_WasPrinted;

	l_Activities = new Activity [p_Activities.size()];
	l_Activities = p_Activities.toArray(l_Activities);
	
	l_ActivityIterator = p_Activities.iterator();
	while (l_ActivityIterator.hasNext())
		{
		l_ActivityIterator.next().monetize();
		}
	
	l_Comparator = new ActivityComparator ();
	l_Comparator.addSortCriterion(ActivityComparator.c_PhysicianId,     ActivityComparator.c_Ascending);
	l_Comparator.addSortCriterion(ActivityComparator.c_PatientFullName, ActivityComparator.c_Ascending);
		
	Arrays.sort (l_Activities,l_Comparator);

	l_SortedActivities = new LinkedHashSet <Activity> ();

	for (l_Index = 0; l_Index < l_Activities.length; l_Index++)
		{
		l_SortedActivities.add (l_Activities [l_Index]);
		}
	
	try {		
		m_Exception = null;
		m_PrintData = l_PrinterInterface.createActivityList(l_SortedActivities, p_From, p_Until, PrintParameterFetcher.createDefaultPrintParameter());
		if (m_PrintData != null)
			{
			l_WasPrinted = m_PrintPreviewDialog.doPrint(m_PrintData, m_PrintImmediately, 1);
			if (!l_WasPrinted) this.checkPrinterStatus();	
			}
		} 
	catch (Exception p_Exception) 
		{
		m_Exception = p_Exception;
		m_Logger.log(Level.WARN, "Failed to print Activity List!", p_Exception);
		p_Exception.printStackTrace();
		l_WasPrinted = false;
		}
	
	return l_WasPrinted;
	}

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

public void close ()
	{
	BillingPrinterInterface l_PrinterInterface;
	
	l_PrinterInterface = this.getPrinterInterface();
	if (l_PrinterInterface != null)
		{
		try {		
			l_PrinterInterface.releaseCachedObjects();
			} 
		catch (Exception p_Exception) 
			{
			m_Logger.log(Level.WARN, "Failed to release cached objects!", p_Exception);
			}
		}
	}

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

public void relocalize() 
	{
 	}

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

//***************************************************************************
//* End Of Class                                                            *
//***************************************************************************
//---------------------------------------------------------------------------
	
}
