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

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.Timer;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Account;
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.session.beans.BillingPrinterBean;
import lu.tudor.santec.gecamed.billing.ejb.session.beans.InvoiceBean;
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.gui.BillingModule;
import lu.tudor.santec.gecamed.billing.gui.invoice.stub.InvoiceStubComparator;
import lu.tudor.santec.gecamed.billing.gui.invoice.stub.InvoiceStubUtils;
import lu.tudor.santec.gecamed.billing.gui.print.InvoicePrinter;
import lu.tudor.santec.gecamed.billing.utils.BillingAdminSettings;
import lu.tudor.santec.gecamed.billing.utils.InvoiceWorkflow;
import lu.tudor.santec.gecamed.billing.utils.ReportSorterBean;
import lu.tudor.santec.gecamed.billing.utils.TimeSpan;
import lu.tudor.santec.gecamed.core.gui.GECAMedColors;
import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.GECAMedLog;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.utils.GECAMedGuiUtils;
import lu.tudor.santec.gecamed.core.gui.utils.SwingWorker;
import lu.tudor.santec.gecamed.core.gui.widgets.ErrorDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.animatedicon.AnimatedIcon;
import lu.tudor.santec.gecamed.core.gui.widgets.print.PrintParameterFetcher;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.usermanagement.gui.settings.UserSettingsPlugin;
import lu.tudor.santec.i18n.Relocalizable;
import lu.tudor.santec.i18n.Translatrix;

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

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.toedter.calendar.JDateChooser;

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

public class MailingPrintDialog extends JDialog implements ItemListener,
														   ActionListener,
														   Relocalizable
{
	private JPanel						m_MailingPanel;
	private TitledBorder				m_MailingBorder;
	
	private JLabel						m_NumberOfMailingsLabel;
	private JLabel						m_NumberOfCopiesLabel;
	private JLabel						m_NumberOfInvoicesLabel;
	private JLabel						m_JoinRemindersLabel;
	
	private JTextField					m_NumberOfMailings;
	private JSpinner					m_NumberOfCopies;
	private JSpinner					m_NumberOfInvoices;
	private JCheckBox					m_OnlyExpired;
	private JCheckBox					m_JoinReminders;
//	private boolean						m_CanEnableJoinReminders = true;

	private JPanel						m_AdditionalInfoPanel;
	private TitledBorder				m_AdditionalInfoBorder;
	private JLabel						m_SettlementVerificationDateLabel;
	private JDateChooser				m_SettlementVerificationDate;
		
	private JPanel						m_PrintMailingPanel;
	private TitledBorder				m_PrintMailingBorder;
	private JCheckBox					m_PrintAll;
	private JLabel						m_PrintFromLabel;
	private JSpinner					m_PrintFrom;
	private JLabel						m_PrintToLabel;
	private JSpinner					m_PrintTo;
	private JButton						m_PrintMailingButton;
	private JProgressBar				m_PrintMailingProgress;
	
	private ImageIcon					m_InvoicePrintIcon;
	private ImageIcon					m_SuspendPrintIcon;
	private AnimatedIcon				m_ResumePrintIcon;

	private JButton						m_CancelButton;

	private SwingWorker  				m_BatchPrinter;
	private Timer						m_Timer;
	private int							m_BatchSize;
	private boolean						m_Suspend;
	private boolean						m_Paused;
	private boolean						m_Aborted;
	
	private Collection <InvoiceStub>	m_InvoiceStubs;
	private Collection <InvoiceStub>	m_NotPrintedInvoiceStubs;
	
	private boolean						m_MarkAsCopy;
	private int							m_NumberOfInvoiceCopies;
	private int							m_NumberOfReminderCopies;
	private int							m_ReminderLevel;
	private Account						m_Account;
	private int							m_SortingProperty;
	private int							m_SortDirection;
	private Boolean						m_ShortInvoiceNumbers;
	private Boolean						m_UseLeadingZeros;
	private InvoiceInterface m_InvoiceInterface;
	private boolean m_ProgressWorkflow;

	
	
	private static final Collection <Integer> m_Dependencies = new ArrayList <Integer> ();
    
	static 	{
    		m_Dependencies.add (InvoiceInterface.c_PatientDependency);
			}
	
//***************************************************************************
//* Class Constants                                                         *
//***************************************************************************

	private final static long serialVersionUID = 1L;

	private final static Dimension c_PreferredSize = new Dimension (200,410);
	
	private final static int	   c_IconTextGap   = 10;

	private final static int	   c_TimerDelay	   = 5000;
	
	private final static int c_NothingChosenOption	= -1;
	private final static int c_JoinAllOption 		= 0;
	private final static int c_JoinPossibleOption	= 1;
	private final static int c_JoinNoneOption		= 2;
	private final static int c_CancelPrintingOption	= 3;
	private final static int c_DefaultOption		= c_CancelPrintingOption;

	//=======================================================================
	//= Layout Strings
	//=======================================================================

	private final static String c_Columns				= 	"3dlu,fill:max(75dlu;pref):grow," +
														  	"3dlu,fill:max(75dlu;pref):grow,3dlu";

	private final static String c_Rows					= 	"3dlu,fill:pref," +
															"3dlu,fill:pref," +
															"3dlu,fill:pref," +
	  														"3dlu,fill:pref,3dlu";

	private final static String c_InvoicesColumns 		= 	"3dlu,fill:max(75dlu;pref)," +
	  													  	"3dlu,fill:max(75dlu;pref),3dlu";

	private final static String c_InvoicesRows 			= 	"3dlu,fill:pref," +
															"3dlu,fill:pref," +
															"3dlu,fill:pref," +
	  														"3dlu,fill:pref," +
		  													"3dlu,fill:pref," +
		  													"3dlu,fill:pref,3dlu";
	
	private final static String c_AdditionalInfoColumns = 	"3dlu,fill:max(75dlu;pref)," +
	  														"3dlu,fill:max(75dlu;pref),3dlu";

	private final static String c_AdditionalInfoRows 	= 	"3dlu,fill:pref,3dlu";

	private final static String c_PrintInvoicesColumns 	= 	"3dlu,fill:pref," +
				  											"3dlu,fill:pref:grow," +
	  													  	"3dlu,fill:pref," +
	  													  	"3dlu,fill:pref:grow,3dlu";


	private final static String c_PrintInvoicesRows 	= 	"3dlu,fill:pref," +
	  														"3dlu,fill:pref," +
	  														"3dlu,fill:pref," +
	  														"3dlu,fill:pref,3dlu";
	
	//=======================================================================
	//= I18N Strings
	//=======================================================================

	private final static String c_Title								= "MailingPrintDialog.Title";
	private final static String c_MailingBorder						= "MailingPrintDialog.MailingBorder";
	private final static String c_NumberOfMailingsLabel				= "MailingPrintDialog.NumberOfMailingsLabel";
	private final static String c_NumberOfCopiesLabel				= "MailingPrintDialog.NumberOfCopiesLabel";
	private final static String c_NumberOfInvoicesLabel				= "MailingPrintDialog.NumberOfInvoicesLabel";
	private final static String c_JoinRemindersLabel				= "MailingPrintDialog.JoinRemindersOfPatient";
	private final static String c_OnlyExpiredLabel					= "MailingPrintDialog.OnlyExpiredLabel";
	
	private final static String c_AdditionalInfoBorder				= "MailingPrintDialog.AdditionalInfoBorder";
	private final static String c_SettlementVerificationDateLabel	= "MailingPrintDialog.SettlementVerificationDateLabel";
	
	private final static String c_PrintMailingBorder		= "MailingPrintDialog.PrintMailingBorder";
	private final static String c_PrintMailingButton		= "MailingPrintDialog.PrintMailingButton";
	private final static String c_PrintAllLabel				= "MailingPrintDialog.PrintAllLabel";
	private final static String c_PrintFromLabel			= "MailingPrintDialog.PrintFromLabel";
	private final static String c_PrintToLabel				= "MailingPrintDialog.PrintToLabel";
	private final static String c_PrintSuspendButton		= "MailingPrintDialog.PrintSuspendButton";
	private final static String c_PrintResumeButton			= "MailingPrintDialog.PrintResumeButton";
	private final static String c_PrintProgressIdle			= "MailingPrintDialog.PrintProgressIdle";
	private final static String c_PrintProgressDone			= "MailingPrintDialog.PrintProgressDone";
	private final static String c_PrintProgressAbort		= "MailingPrintDialog.PrintProgressAbort";
	private final static String c_PrintProgressPaused		= "MailingPrintDialog.PrintProgressPaused";
	private final static String c_WaitingForPrinter			= "MailingPrintDialog.WaitingForPrinter";

	private final static String c_PrintErrorTitle			= "MailingPrintDialog.PrintErrorTitle";
	private final static String c_PrintErrorMessage			= "MailingPrintDialog.PrintErrorMessage";

	private final static String c_NoError					= "MailingPrintDialog.NoError"; 
	private final static String c_TooManyJobsInQueue		= "MailingPrintDialog.TooManyJobsInQueue"; 
	private final static String c_DidNotAcceptJobs			= "MailingPrintDialog.DidNotAcceptJobs"; 

	private final static String c_NoNotice					= "MailingPrintDialog.NoNotice"; 
	private final static String c_FirstNotice				= "MailingPrintDialog.FirstNotice"; 
	private final static String c_SecondNotice				= "MailingPrintDialog.SecondNotice"; 
	private final static String c_PaymentOrder				= "MailingPrintDialog.PaymentOrder"; 

	private static Logger m_Logger = Logger.getLogger (MailingPrintDialog.class.getName());

//---------------------------------------------------------------------------
//***************************************************************************
//* Constructor                                                             *
//***************************************************************************
//---------------------------------------------------------------------------
	
public MailingPrintDialog ()
	{
	super (MainFrame.getInstance(),Translatrix.getTranslationString(c_Title),true);
	
	CellConstraints				l_Constraints;
	FormLayout					l_Layout;
//	BillingPrinterInterface 	l_PrinterInterface;
	
	m_SortingProperty = InvoiceStubComparator.c_None;
	m_SortDirection   = InvoiceStubComparator.c_Ascending;
	
	this.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
	
	l_Constraints  = new CellConstraints();
	
	m_MailingBorder 	= new TitledBorder ("");
	
	m_OnlyExpired = new JCheckBox ();
	m_OnlyExpired.setOpaque(false);
	m_OnlyExpired.setSelected(true);
	m_OnlyExpired.addItemListener(this);

	m_NumberOfMailingsLabel = new JLabel ();
	m_NumberOfMailingsLabel.setForeground(GECAMedColors.c_LabelColor);
	
	m_NumberOfCopiesLabel = new JLabel ();
	m_NumberOfCopiesLabel.setForeground(GECAMedColors.c_LabelColor);
	
	m_JoinRemindersLabel = new JLabel ();
	m_JoinRemindersLabel.setForeground(GECAMedColors.c_LabelColor);
	
	m_NumberOfInvoicesLabel = new JLabel ();
	m_NumberOfInvoicesLabel.setForeground(GECAMedColors.c_LabelColor);

	m_PrintFromLabel		= new JLabel ();
	m_PrintFromLabel.setForeground(GECAMedColors.c_LabelColor);
	
	m_PrintToLabel		= new JLabel ();
	m_PrintToLabel.setForeground(GECAMedColors.c_LabelColor);

	m_SettlementVerificationDateLabel	= new JLabel ();
	m_SettlementVerificationDateLabel.setForeground(GECAMedColors.c_LabelColor);
	
	m_SettlementVerificationDate = GECAMedGuiUtils.getDateChooser(false);
	m_SettlementVerificationDate.setDate(new Date());
	
	m_CancelButton = new JButton ();
	m_CancelButton.setIcon(GECAMedModule.getSmallIcon(GECAMedIconNames.CANCEL));
	m_CancelButton.addActionListener(this);
	
	this.getContentPane().setBackground(GECAMedColors.c_GECAMedBackground);
	this.relocalize();
		
	//=======================================================================
	//= Assemble Invoices Panel
	//=======================================================================

	l_Layout = new FormLayout(c_InvoicesColumns, c_InvoicesRows);
	m_MailingBorder = new TitledBorder (Translatrix.getTranslationString(c_MailingBorder));
	
	m_MailingPanel = new JPanel ();
	m_MailingPanel.setOpaque(false);
	m_MailingPanel.setLayout(l_Layout);
	m_MailingPanel.setBorder(m_MailingBorder);
	
	m_NumberOfMailings = new JTextField ();
	m_NumberOfMailings.setHorizontalAlignment(JTextField.RIGHT);
	m_NumberOfMailings.setText ("0");
	m_NumberOfMailings.setEditable(false);

	m_NumberOfCopies   = new JSpinner (new SpinnerNumberModel (0,0,10,1));
	m_NumberOfCopies.addChangeListener(new ChangeListener() {
		public void stateChanged(ChangeEvent e) 
			{
			enableJoinRemindersBox();
			}
	});
	
	m_NumberOfInvoices = new JSpinner (new SpinnerNumberModel (0,0,10,1));

	m_JoinReminders = new JCheckBox();
	m_JoinReminders.setOpaque(false);
	enableJoinRemindersBox();

	m_MailingPanel.add (m_OnlyExpired,    			l_Constraints.xywh(2, 2, 3, 1));
	m_MailingPanel.add (m_NumberOfMailingsLabel,    l_Constraints.xywh(2, 4, 1, 1));
	m_MailingPanel.add (m_NumberOfMailings,   		l_Constraints.xywh(4, 4, 1, 1));
	m_MailingPanel.add (m_NumberOfCopiesLabel,   	l_Constraints.xywh(2, 6, 1, 1));
	m_MailingPanel.add (m_NumberOfCopies,   		l_Constraints.xywh(4, 6, 1, 1));
	m_MailingPanel.add (m_NumberOfInvoicesLabel,   	l_Constraints.xywh(2, 8, 1, 1));
	m_MailingPanel.add (m_NumberOfInvoices,   		l_Constraints.xywh(4, 8, 1, 1));
	m_MailingPanel.add (m_JoinRemindersLabel,   	l_Constraints.xywh(2, 10, 1, 1));
	m_MailingPanel.add (m_JoinReminders,   			l_Constraints.xywh(4, 10, 1, 1));
	
	//=======================================================================
	//= Assemble Invoices Panel
	//=======================================================================

	l_Layout = new FormLayout(c_AdditionalInfoColumns, c_AdditionalInfoRows);
	m_AdditionalInfoBorder = new TitledBorder (Translatrix.getTranslationString(c_AdditionalInfoBorder));
	
	m_AdditionalInfoPanel = new JPanel ();
	m_AdditionalInfoPanel.setOpaque(false);
	m_AdditionalInfoPanel.setLayout(l_Layout);
	m_AdditionalInfoPanel.setBorder(m_AdditionalInfoBorder);
	
	m_AdditionalInfoPanel.add (m_SettlementVerificationDateLabel, 	l_Constraints.xywh(2, 2, 1, 1));
	m_AdditionalInfoPanel.add (m_SettlementVerificationDate,   		l_Constraints.xywh(4, 2, 1, 1));
	
	//=======================================================================
	//= Assemble Print Panel
	//=======================================================================

	l_Layout = new FormLayout(c_PrintInvoicesColumns, c_PrintInvoicesRows);
	m_PrintMailingBorder = new TitledBorder (Translatrix.getTranslationString(c_PrintMailingBorder));

	m_PrintMailingPanel = new JPanel ();
	
	m_PrintMailingPanel = new JPanel ();
	m_PrintMailingPanel.setOpaque(false);
	m_PrintMailingPanel.setLayout(l_Layout);
	m_PrintMailingPanel.setBorder(m_PrintMailingBorder);
	
	m_PrintAll = new JCheckBox (Translatrix.getTranslationString (c_PrintAllLabel));
	m_PrintAll.setOpaque(false);
    m_PrintAll.addItemListener(this);
	m_PrintAll.setSelected(true);
	
    m_PrintFrom   = new JSpinner (new SpinnerNumberModel ());
	m_PrintFrom.setEnabled(false);
	m_PrintFromLabel.setEnabled(false);
	
	m_PrintTo = new JSpinner (new SpinnerNumberModel ());
	m_PrintTo.setEnabled(false);
	m_PrintToLabel.setEnabled(false);

    m_InvoicePrintIcon = BillingModule.getIconResource("rmndr_batch_print.png");
    m_SuspendPrintIcon = BillingModule.getIconResource("rmndr_print_suspend.png");
    m_ResumePrintIcon  = new AnimatedIcon (BillingModule.getIconResource("rmndr_print_paused.gif"));

    m_PrintMailingButton = new JButton ();
	m_PrintMailingButton.setIcon(m_InvoicePrintIcon);
	m_PrintMailingButton.setText(Translatrix.getTranslationString(c_PrintMailingButton));
	m_PrintMailingButton.setIconTextGap(c_IconTextGap);
	m_PrintMailingButton.addActionListener(this);
	
	m_PrintMailingProgress = new JProgressBar ();
	m_PrintMailingProgress.setMinimum(0);
	m_PrintMailingProgress.setValue(0);
	m_PrintMailingProgress.setStringPainted(true);
	m_PrintMailingProgress.setString (Translatrix.getTranslationString(c_PrintProgressIdle));
	
	m_PrintMailingPanel.add (m_PrintAll,	  	l_Constraints.xywh( 2, 2, 7, 1));
	m_PrintMailingPanel.add (m_PrintFromLabel,	l_Constraints.xywh( 2, 4, 1, 1));
	m_PrintMailingPanel.add (m_PrintFrom,		l_Constraints.xywh( 4, 4, 1, 1));
	m_PrintMailingPanel.add (m_PrintToLabel,	l_Constraints.xywh( 6, 4, 1, 1));
	m_PrintMailingPanel.add (m_PrintTo,			l_Constraints.xywh( 8, 4, 1, 1));
	
	m_PrintMailingPanel.add (m_PrintMailingButton, l_Constraints.xywh( 2, 6, 7, 1));
	m_PrintMailingPanel.add (m_PrintMailingProgress, l_Constraints.xywh( 2, 8, 7, 1));
	
	//=======================================================================
	//= Assemble Dialog
	//=======================================================================
 
	l_Layout = new FormLayout(c_Columns, c_Rows);
	this.setLayout(l_Layout);
	this.add (m_MailingPanel,  	 	 l_Constraints.xywh(2, 2, 3, 1));
	this.add (m_AdditionalInfoPanel, l_Constraints.xywh(2, 4, 3, 1));
	this.add (m_PrintMailingPanel,   l_Constraints.xywh(2, 6, 3, 1));
	this.add (m_CancelButton,  		 l_Constraints.xywh(4, 8, 1, 1));
	
	this.setSize(c_PreferredSize);
	}

//---------------------------------------------------------------------------
//***************************************************************************
//* Class Primitives                                                        *
//***************************************************************************
//---------------------------------------------------------------------------

private void toggleSuspendButton (boolean p_SuspendButton)
	{
	if (p_SuspendButton)
		{
		m_PrintMailingButton.setIcon(m_SuspendPrintIcon);
		m_PrintMailingButton.setText(Translatrix.getTranslationString(c_PrintSuspendButton));	
		}
	else
		{
		m_PrintMailingButton.setIcon(m_InvoicePrintIcon);
		m_PrintMailingButton.setText(Translatrix.getTranslationString(c_PrintMailingButton));	
		}
	}

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

private void toggleResumeButton (boolean p_ResumeButton)
	{
	if (p_ResumeButton)
		{
		m_PrintMailingButton.setIcon(m_ResumePrintIcon);
		m_PrintMailingButton.setText(Translatrix.getTranslationString(c_PrintResumeButton));	
		}
	else
		{
		m_PrintMailingButton.setIcon(m_SuspendPrintIcon);
		m_PrintMailingButton.setText(Translatrix.getTranslationString(c_PrintSuspendButton));	
		}
	}

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

private int getPrintFrom ()
	{
	int	l_PrintFrom;
	int l_PrintTo;
	
	l_PrintFrom = ((Integer)m_PrintFrom.getValue()).intValue();
	l_PrintTo   = ((Integer)m_PrintTo.getValue()).intValue();
	
	return Math.min(l_PrintFrom, l_PrintTo);
	}

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

private int getPrintTo ()
	{
	int	l_PrintFrom;
	int l_PrintTo;
	
	l_PrintFrom = ((Integer)m_PrintFrom.getValue()).intValue();
	l_PrintTo   = ((Integer)m_PrintTo.getValue()).intValue();
	
	return Math.max(l_PrintFrom, l_PrintTo);
	}

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

private String getMeaningOf (int p_PrinterStatus)
	{
	switch (p_PrinterStatus)
		{
		case InvoicePrinter.c_NoError 			 : return Translatrix.getTranslationString(c_NoError);
		case InvoicePrinter.c_TooManyJobsInQueue : return Translatrix.getTranslationString(c_TooManyJobsInQueue);
		case InvoicePrinter.c_DidNotAcceptJobs	 : return Translatrix.getTranslationString(c_DidNotAcceptJobs);
		}
	return "";
	}

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

private String stringifyReminderLevel (int p_ReminderLevel)
	{
	switch (p_ReminderLevel)
		{
		case 0	: return Translatrix.getTranslationString(c_NoNotice);
		case 1 	: return Translatrix.getTranslationString(c_FirstNotice);
		case 2	: return Translatrix.getTranslationString(c_SecondNotice);
		case 3	: return Translatrix.getTranslationString(c_PaymentOrder);
		}
	return "";
	}

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

private void showPrintError (int p_PrinterStatus, Exception p_Exception, String[] p_Filler)
	{
	String l_PrinterStatus;
	
	if (p_Exception == null)
		{
		l_PrinterStatus = this.getMeaningOf (p_PrinterStatus);
		
		ErrorDialog.showErrorDialog	(MainFrame.getInstance(), 
									 Translatrix.getTranslationString(c_PrintErrorTitle), 
									 Translatrix.getTranslationString(c_PrintErrorMessage,p_Filler),
									 l_PrinterStatus);
		}
	else	
		{
		ErrorDialog.showErrorDialog	(MainFrame.getInstance(), 
									 Translatrix.getTranslationString(c_PrintErrorTitle), 
									 Translatrix.getTranslationString(c_PrintErrorMessage,p_Filler),
									 p_Exception);	
		}
	}
						
//---------------------------------------------------------------------------

private Collection <InvoiceStub> sortInvoiceStubs (Collection <InvoiceStub> p_Unsorted)
	{
	Collection <InvoiceStub>	l_InvoiceStubs;
	InvoiceStub []				l_InvoiceStubArray;
	InvoiceStubComparator		l_Comparator;
	int							l_Index;
	
	if (p_Unsorted == null) return null;
	
	l_InvoiceStubArray = new InvoiceStub[p_Unsorted.size()];
	l_InvoiceStubArray = p_Unsorted.toArray(l_InvoiceStubArray);
	
	l_Comparator = new InvoiceStubComparator ();

//	if (m_GroupingProperty !=  null && m_GroupingProperty != 0) {
//		l_Comparator.addSortCriterion(InvoiceStubComparator.c_Grouping, InvoiceStubComparator.c_Ascending);
//	}
//	 
	l_Comparator.addSortCriterion(m_SortingProperty, m_SortDirection);
		
	Arrays.sort (l_InvoiceStubArray,l_Comparator);

	l_InvoiceStubs = new LinkedHashSet <InvoiceStub> ();
	for (l_Index = 0; l_Index < l_InvoiceStubArray.length; l_Index++)
		{
		l_InvoiceStubs.add (l_InvoiceStubArray [l_Index]);
		}
	
	return l_InvoiceStubs;
	}

//---------------------------------------------------------------------------
//***************************************************************************
//* Swing Worker Thread                                                     *
//***************************************************************************
//---------------------------------------------------------------------------

Object BatchPrinter ()
	{
	this.batchPrintMailing();
	return "";
	}

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

private synchronized void batchPrintMailing ()
	{
	InvoiceStubUtils			l_InvoiceStubUtils;
	
	Iterator <InvoiceStub>  	l_InvoiceStubIterator;
	InvoiceStub			    	l_InvoiceStub;
	Invoice						l_Invoice;
	Date						l_Today;
	boolean 					l_UseShortInvoiceNumbers;
	boolean 					l_UseLeadingZeros;
	DateFormat					l_DateFormat;
	
	InvoicePrinter				l_Printer;
	boolean						l_WasPrinted;
	boolean						l_OnlyExpired;
	boolean						l_RequiresCopy;
	Integer						l_PhysicianId;
	int							l_DialogOption 				 = -1;
	String 						l_ReminderType;
	
	String[]					l_DialogOptions;
	boolean						l_Join;
	Date						l_InvoiceDate;
	
	Date						l_SettlementVerificationDate = new Date ();
	int							l_MailingCount 				 = 0;
	int							l_ReminderCopies			 = 0;
	int							l_InvoiceCopies 			 = 0;
	int							l_BatchCount   				 = 0;
	int							l_PrintFrom	   				 = 0;
	int							l_PrintTo	   				 = 0;
	int							l_Action;
	String[]					l_Filler;
	
	// added for joining the reminders
	boolean						l_Done		   				= false;
	boolean 					l_JoinRemindersOfPatient;
	Integer						l_PatientId;
	BillingPrinterInterface		l_PrinterBean;
	ReportSorterBean			l_ReportSorterBean			= null;
	TimeSpan					l_ValiditySpan;
	List<Invoice>				l_InvoiceList;
	List<Integer>				l_UnjoinableInvoices 		= new LinkedList<Integer>();
	Map<TimeSpan, Boolean>		l_JoinabilityMap;
	Map<ReportSorterBean, List<Invoice>>	l_JoinedInvoices 	= null;
	Map<ReportSorterBean, Boolean>			l_PrintedReminders	= new HashMap<ReportSorterBean, Boolean>();
	Map<Integer, Map<TimeSpan, Boolean>>	l_ReportJoinability	= null;
	HashMap<String, Object>					l_Parameter;
	

	this.toggleSuspendButton(true);
	
	if ((Boolean)MainFrame.getInstance().userSettings.getValue(UserSettingsPlugin.PRINTER_BATCH_SPLIT_ENABLED))
		 m_BatchSize = (Integer) MainFrame.getInstance().userSettings.getValue(UserSettingsPlugin.PRINTER_BATCH_SIZE);
	else m_BatchSize = 0;
	
	m_Paused	= false;
	m_Suspend	= false;
	
	l_InvoiceStubUtils = new InvoiceStubUtils ();
	
	m_PrintMailingProgress.setMinimum(0);

	if (!m_PrintAll.isSelected())
		{
		// Minus 1 because Invoice positions on statement start with one
		// and internally we're using 0 based indexes.
		
		l_PrintFrom = this.getPrintFrom() - 1;
		l_PrintTo = this.getPrintTo() - 1;
		
		m_PrintMailingProgress.setMaximum(l_PrintTo - l_PrintFrom + 1);
		}
	else
		{
		m_PrintMailingProgress.setMaximum(m_InvoiceStubs.size());
		}
	
	m_Timer = new Timer (c_TimerDelay,this);

	//========================================================================
	//= Step 1. Get instance of InvoicePrinter object. In the case of batch
	//= print, we don't want neither a preview nor a print dialog. Setting
	//= InvoicePrinters' print immediately flag makes sure they won't show.
	//========================================================================
	
	l_Printer = new InvoicePrinter ();
	l_Printer.setPrintImmediately(true);
	l_Printer.setQueueSizeRetries (6);
	l_Printer.setQueueSizeDelay (10000);
	l_Printer.setJobAcceptanceRetries (10);
	l_Printer.setJobAcceptanceDelay (1000);
	
	//========================================================================
	//= Step 2. Next step consists in iterating over all the invoices.
	//= Each invoice will be fed to the invoice workflow to make sure it
	//= may be printed. If so, the invoice will be in printed state.
	//= After the invoice is printed, it will be saved to keep track of its 
	//= state change.
	//========================================================================
	
	l_Today 					 = new Date ();
	l_ReminderCopies			 = (Integer) m_NumberOfCopies.getValue();
	l_InvoiceCopies 			 = (Integer) m_NumberOfInvoices.getValue();
	l_JoinRemindersOfPatient	 = m_JoinReminders.isSelected()
									&& m_JoinReminders.isEnabled();
	l_SettlementVerificationDate = m_SettlementVerificationDate.getDate();
	l_OnlyExpired				 = m_OnlyExpired.isSelected();
	m_NotPrintedInvoiceStubs 	 = new LinkedHashSet <InvoiceStub> ();
	
	if (l_ReminderCopies <= 0 && l_InvoiceCopies <= 0)
	{
		// nothing will be printed -> stop here ...
		this.toggleSuspendButton(false);
		return;
	}
	
	//========================================================================
	//= Step 3. Sort stubs using specified criteria.
	//========================================================================

//	if (m_SortingProperty != InvoiceStubComparator.c_None)
//		{
//		m_InvoiceStubs = this.sortInvoiceStubs(m_InvoiceStubs);
//		}
	
	if (m_ReminderLevel == BillingPrinterBean.c_PrintFirstNotice)
		 l_ReminderType = BillingPrinterBean.c_FirstNoticeTemplateType;
	else l_ReminderType = BillingPrinterBean.c_SecondNoticeTemplateType;

	//========================================================================
	//= Step 4. Join the reminders if desired
	//========================================================================
	l_UseShortInvoiceNumbers 	= this.useShortInvoiceNumbers();
	l_UseLeadingZeros 			= this.useLeadingZeros();
	l_DateFormat = new SimpleDateFormat("dd/MM/yyyy", Translatrix.getLocale());
	
	if (l_JoinRemindersOfPatient)
		{
		// prepare
		l_JoinedInvoices 		= new HashMap<ReportSorterBean, List<Invoice>>();
		l_InvoiceStubIterator 	= m_InvoiceStubs.iterator();
		l_PrinterBean			= (BillingPrinterInterface) ManagerFactory.getRemote(BillingPrinterBean.class);
		l_ReportJoinability		= l_PrinterBean.getUnjoinableReportsForType(l_ReminderType);
		
		// run through the invoices
		while (l_InvoiceStubIterator.hasNext())
			{
			l_InvoiceStub 	= l_InvoiceStubIterator.next();
			l_Invoice 		= l_InvoiceStubUtils.fetchInvoiceForStub (l_InvoiceStub, m_Dependencies);
			l_PhysicianId	= l_Invoice.getPhysician().getId();
			l_PatientId 	= l_InvoiceStub.getPatientId();
			l_InvoiceDate 	= l_Invoice.getInvoiceDate();
			l_ValiditySpan 	= null;
					
			// get a fitting time span for the invoice (there must be exactly one)
			l_JoinabilityMap = l_ReportJoinability.get(l_PhysicianId);
			l_ValiditySpan = findTimeSpan (l_JoinabilityMap, l_InvoiceDate);
			
			l_ReportSorterBean	= new ReportSorterBean(l_PatientId, l_PhysicianId, l_ValiditySpan);
			l_InvoiceList = l_JoinedInvoices.get(l_ReportSorterBean);
			if (l_InvoiceList == null)
				{
				l_InvoiceList = new LinkedList<Invoice>();
				l_JoinedInvoices.put(l_ReportSorterBean, l_InvoiceList);
				}
			
			
			l_JoinabilityMap = l_ReportJoinability.get(l_Invoice.getPhysician().getId());
			if (l_JoinabilityMap != null)
				{
				for (TimeSpan l_TimeSpan : l_JoinabilityMap.keySet())
					{
					if (l_TimeSpan != null && l_TimeSpan.equals(l_InvoiceDate))
						{
						l_UnjoinableInvoices.add(l_Invoice.getId());
						break;
						}
					}
				}
			
			
			
			
			// prepare the invoice
			l_Invoice.monetize();
			l_Invoice.setUseShortNumbers(l_UseShortInvoiceNumbers);
			l_Invoice.setUseLeadingZeros(l_UseLeadingZeros);
			l_Invoice.setFormatedDate(l_DateFormat.format(l_Invoice.getInvoiceDate()));
			if (l_Invoice.getReminderDate() != null)
				 l_Invoice.setFormatedReminderDate(l_DateFormat.format(l_Invoice.getReminderDate()));
			else l_Invoice.setFormatedReminderDate("");
			
			l_InvoiceList.add(l_Invoice);
			}
		
		if (!l_UnjoinableInvoices.isEmpty())
			{
			l_DialogOptions = new String[] {
					Translatrix.getTranslationString("MailingPrintDialog.JoinAnywayOption"),
					Translatrix.getTranslationString("MailingPrintDialog.JoinAsPossibleOption"),
					Translatrix.getTranslationString("MailingPrintDialog.JoinNoneOption"),
					Translatrix.getTranslationString("MailingPrintDialog.CancelPrintingOption")};
			
			l_DialogOption = JOptionPane.showOptionDialog(this, 
					Translatrix.getTranslationString("MailingPrintDialog.CannotJoinRemindersMessage"), 
					Translatrix.getTranslationString("MailingPrintDialog.CannotJoinRemindersTitle"), 
					JOptionPane.OK_CANCEL_OPTION, 
					JOptionPane.WARNING_MESSAGE, 
					null, 
					l_DialogOptions, 
					c_DefaultOption);
			
			if (l_DialogOption == c_CancelPrintingOption)
				m_Aborted = true;
			}
		}
//	l_InvoiceList = new LinkedList<Invoice>();
	/* ************************************************ */
	
	l_InvoiceStubIterator = m_InvoiceStubs.iterator();
	while (l_InvoiceStubIterator.hasNext() && !l_Done && !m_Aborted)
		{
		//====================================================================
		//= Step 5. If user specified a print from boundary, then we have to
		//= fast forward iterator to specified position.
		//====================================================================
		
		if (l_PrintFrom > 0)
			{
			l_InvoiceStub = l_InvoiceStubIterator.next();
			l_PrintFrom--;
			l_MailingCount++;
			continue;
			}
		
		//====================================================================
		//= Step 6. If user specified a print to boundary, then we have to
		//= make sure we stop at the desired location.
		//====================================================================

		if ((l_PrintTo > 0) && (l_MailingCount >= l_PrintTo)) l_Done = true;
	
		if (m_Suspend || ((m_BatchSize > 0) && (l_BatchCount == m_BatchSize)))
			{
			l_Filler = new String [2];
			l_Filler [0] = Integer.valueOf(l_MailingCount).toString();
			l_Filler [1] = m_NumberOfMailings.getText();
			
			m_PrintMailingProgress.setString (Translatrix.getTranslationString(c_PrintProgressPaused,l_Filler));	
			this.suspendBatchPrinting();
			l_BatchCount = 0;
			m_Suspend = false;
			}			

		l_WasPrinted = false;
		l_InvoiceStub = l_InvoiceStubIterator.next();
		
		if (l_OnlyExpired && !l_InvoiceStub.isExpired()) continue;
		
		l_Invoice = l_InvoiceStubUtils.fetchInvoiceForStub (l_InvoiceStub,m_Dependencies);

		l_PatientId 	= l_Invoice.getPatient().getId();
		l_PhysicianId 	= l_Invoice.getPhysician().getId();
		l_InvoiceDate	= l_Invoice.getInvoiceDate();

		l_Parameter = PrintParameterFetcher.createDefaultPrintParameter(l_Invoice, l_SettlementVerificationDate);
		
		/**
		 * @author ferring
		 * Added to join reminders
		 */
		l_Join = l_JoinRemindersOfPatient  					// IF 	the join reminders button is checked
				&& l_DialogOption != c_JoinNoneOption 		// AND 	any reminder shall be joined 
				&& (										// AND 	the following conditions are fulfilled:
				   l_DialogOption == c_NothingChosenOption	// 		nothing was chosen (the dialog wasn't opened)
				|| l_DialogOption == c_JoinAllOption		// OR 	the join all button was pressed
				|| (										// OR 	one of the following conditions is fulfilled:
				   l_DialogOption == c_JoinPossibleOption	// 		the join possible button was pressed
				&& !l_UnjoinableInvoices.contains(l_Invoice.getId())));	// AND	the invoice is not in the list of not compatible invoices)
		
		if (l_Join)
			{
			// load the invoices for the patient
			l_JoinabilityMap 	= l_ReportJoinability.get(l_PhysicianId);
			l_ValiditySpan 		= findTimeSpan(l_JoinabilityMap, l_InvoiceDate);
			l_ReportSorterBean 	= new ReportSorterBean(l_PatientId, l_PhysicianId, l_ValiditySpan);
			
			l_InvoiceList = l_JoinedInvoices.get(l_ReportSorterBean);
			}
		else{
			// only load the current invoice into the list
			l_InvoiceList = new LinkedList<Invoice>();
			l_InvoiceList.add(l_Invoice);
			}
		
		// if the reminders shall be joined, this operation is already done
		if (!l_JoinRemindersOfPatient) 
			l_Invoice.monetize();
		/**************************************************/
		
		if (m_ReminderLevel > 0) {
			l_Action = InvoiceWorkflow.c_RemindAction;			
		} else {
			l_Action = InvoiceWorkflow.c_PrintAction;
		}
			
		l_Action = InvoiceWorkflow.changeInvoiceState(l_Invoice, l_Action);
		
		if (   (l_Action == InvoiceWorkflow.c_DoPrint) 
//			|| (l_Action == InvoiceWorkflow.c_DoPrintCopy)
			|| (l_Action == InvoiceWorkflow.c_DoPrintOriginal)
			|| (l_Action == InvoiceWorkflow.c_DoRemind))
			{
			m_PrintMailingProgress.setString(l_Invoice.formatInvoiceNumber(Invoice.c_LongFormat, true));
			m_PrintMailingProgress.setValue(l_MailingCount + 1);
			
			m_Timer.restart ();
			
			try	{
				l_WasPrinted = false;
				switch (m_ReminderLevel)
					{
					case 0: 
						l_RequiresCopy = BillingModule.copyRequired (l_Invoice);
						l_WasPrinted = l_Printer.printInvoice (l_Invoice, l_InvoiceCopies, l_RequiresCopy, false, l_Parameter);
						break;
						
					case 1:
					case 2:
						if (!l_Join || !l_PrintedReminders.containsKey(l_ReportSorterBean))
//							 l_WasPrinted = l_Printer.printFirstReminder(l_Invoice, l_InvoiceList, l_Today, l_SettlementVerificationDate, l_ReminderCopies);
							 l_WasPrinted = l_Printer.printReminder(m_ReminderLevel, l_Invoice, l_InvoiceList, m_Account, l_Today, l_SettlementVerificationDate, l_ReminderCopies, l_Parameter);
						else l_WasPrinted = true;
						
						if (l_WasPrinted && (l_InvoiceCopies > 0))
							l_WasPrinted = l_Printer.printInvoice(l_Invoice, l_InvoiceCopies, m_MarkAsCopy, false, l_Parameter);
						
						if (l_WasPrinted)
							{
							l_Invoice.setNumberOfReminders(m_ReminderLevel);
							l_Invoice.setReminderDate(l_Today);
							l_Invoice.setDueDate(false);
							}
						break;
						
//					case 2: 
//						if (l_PrintedReminders.containsKey(l_Invoice.getPatient().getId()))
////							 l_WasPrinted = l_Printer.printSecondReminder(l_Invoice, l_InvoiceList, l_Today, l_SettlementVerificationDate, l_ReminderCopies);
//							 l_WasPrinted = l_Printer.printReminder(BillingPrinterBean.c_SecondNotice, l_Invoice, l_InvoiceList, l_Today, l_SettlementVerificationDate, l_ReminderCopies);
//						else l_WasPrinted = true;
//						
//						if(l_WasPrinted && (l_InvoiceCopies > 0)) l_WasPrinted = l_Printer.printInvoice(l_Invoice, l_InvoiceCopies, m_MarkAsCopy);
//						if (l_WasPrinted)
//							{
//							l_Invoice.setNumberOfReminders(m_ReminderLevel);
//							l_Invoice.setReminderDate(l_Today);
//							l_Invoice.setDueDate(Invoice.getDueDate(l_Today));
//							}
//						break;
					
	//				case 3: l_WasPrinted = l_Printer.printPaymentOrder (l_Invoice, m_Account, l_Today, l_ReminderCopies);
	//						if (l_WasPrinted && (l_InvoiceCopies > 0)) l_WasPrinted = l_Printer.printInvoice(l_Invoice, l_InvoiceCopies, m_MarkAsCopy);
					case 3: 
						l_WasPrinted = true;
						if (!l_Join || !l_PrintedReminders.containsKey(l_ReportSorterBean))
							 l_WasPrinted = l_Printer.printReminder(m_ReminderLevel, l_Invoice, l_InvoiceList, m_Account, l_Today, l_SettlementVerificationDate, l_ReminderCopies, l_Parameter);
						else l_WasPrinted = true;
						
//						if ((l_ReminderCopies > 0)) 
//							l_WasPrinted = l_Printer.printPaymentOrder (l_Invoice, m_Account, l_Today, l_ReminderCopies, l_Parameter);
						
						if (l_WasPrinted && (l_InvoiceCopies > 0)) 
							l_WasPrinted = l_Printer.printInvoice (l_Invoice, l_InvoiceCopies, m_MarkAsCopy, false, l_Parameter);
						
						if (l_WasPrinted)
							{
							l_Invoice.setNumberOfReminders(m_ReminderLevel);
							l_Invoice.setReminderDate(l_Today);
							l_Invoice.setDueDate(false);
							}
						break;
					}
				
				if (! m_ProgressWorkflow) {
					GECAMedLog.user("Billing","PRINT Reminder COPY","Printed Reminder COPY for Invoice with ID " + l_Invoice.getId());
					
					if (l_Join)
						l_PrintedReminders.put(l_ReportSorterBean, Boolean.TRUE);
				} else if (l_WasPrinted) {
//					if (!l_Invoice.alreadyPrinted()) l_Invoice.setPrintDate(new Date ());
					l_Invoice = l_InvoiceStubUtils.saveInvoice(l_Invoice);
					
					GECAMedLog.user("Billing","PRINT Reminder","Printed Reminder for Invoice with ID " + l_Invoice.getId());
			
					if (l_Join)
						l_PrintedReminders.put(l_ReportSorterBean, Boolean.TRUE);
				} else {
					m_NotPrintedInvoiceStubs.add (l_InvoiceStub);
					
					l_Filler = new String [3];
					l_Filler[0] = this.stringifyReminderLevel(m_ReminderLevel);
					l_Filler[1] = l_Invoice.formatInvoiceNumber(Invoice.c_LongFormat, true);
					l_Filler[2] = Integer.valueOf(l_MailingCount).toString();
						
					this.showPrintError (l_Printer.getStatus(), l_Printer.getException(), l_Filler);
					m_Aborted = true;
				}						
					
			}catch (Exception p_Exception)
				{
				l_Filler = new String [3];
				l_Filler[0] = this.stringifyReminderLevel(m_ReminderLevel);
				l_Filler[1] = l_Invoice.formatInvoiceNumber(Invoice.c_LongFormat, true);
				l_Filler[2] = Integer.valueOf(l_MailingCount).toString();
						
				this.showPrintError (l_Printer.getStatus(), p_Exception, l_Filler);
				m_Logger.log(Level.ERROR, "Failed to save Invoice state\n" + p_Exception.getLocalizedMessage());
				m_Aborted = true;
				}
			}
		l_MailingCount++;
		l_BatchCount++;
		}
	
	this.toggleSuspendButton(false);
	l_Printer.close();
	
	m_PrintMailingProgress.setValue(0);
	if (m_Aborted)
		{
		m_PrintMailingProgress.setString (Translatrix.getTranslationString(c_PrintProgressAbort));	
		}
	else
		{
		m_PrintMailingProgress.setString (Translatrix.getTranslationString(c_PrintProgressDone));
		this.setVisible (false);
		}
	}

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

private TimeSpan findTimeSpan (Map<TimeSpan, Boolean> p_UnjoinableList, Date p_InvoiceDate)
	{
	TimeSpan l_TimeSpan;
	
	if (p_UnjoinableList != null)
		{
		Iterator<TimeSpan> iter = p_UnjoinableList.keySet().iterator();
		while (iter.hasNext())
			{
			l_TimeSpan = iter.next();
			if (l_TimeSpan != null && l_TimeSpan.equals(p_InvoiceDate))
				return l_TimeSpan;
			}
		}
	else return null;
	
	// there should be exactly one time span, if list isn't null
	try {
		throw new Exception ("no TimeSpan found!");
		}
	catch (Exception p_Exception)
		{
		p_Exception.printStackTrace();
		return null;
		}
	}

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

private void startBatchPrinting ()
	{

	m_BatchPrinter = new SwingWorker() 
	{
	public Object construct() 
		{
		return BatchPrinter ();
		}
	public void start ()
		{
		m_Aborted = false;
		super.start();
		}
	public void finished ()
		{
		}
	public void interrupt ()
		{
		m_Aborted = true;
		super.interrupt();
		}
	};

	m_BatchPrinter.start ();  	
	}

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

private void abortBatchPrinting ()
	{
	m_Aborted = true;
	if (m_BatchPrinter != null) m_BatchPrinter.interrupt();
	}

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

private synchronized void suspendBatchPrinting ()
	{
	m_Paused = true;
	this.toggleResumeButton(true);
	while (m_Paused) 
		try {wait(500);} 
		catch (Exception p_Exception) 
			{
			m_Logger.log(Level.ERROR, "Exception while suspended!", p_Exception);
			m_Paused = false;
			};
			
	this.toggleResumeButton(false);
	}

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

private void resumeBatchPrinting ()
	{
	m_Paused = false;
	}

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

public Integer countInvoiceStubs (boolean p_OnlyExpired)
	{
	int						l_Count = 0;
	Iterator <InvoiceStub>	l_InvoiceStubIterator;
	
	if (m_InvoiceStubs == null) return l_Count;
	
	if (p_OnlyExpired == true) 
		{
		l_InvoiceStubIterator = m_InvoiceStubs.iterator();
		while (l_InvoiceStubIterator.hasNext())
			{
			if (l_InvoiceStubIterator.next().isExpired()) l_Count++;
			}
		}
	else l_Count = m_InvoiceStubs.size();
	
	return l_Count;
	}

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

public void setInvoiceStubs (Collection <InvoiceStub> p_InvoiceStubs)
	{
	Integer	l_Count;
	
	if (p_InvoiceStubs != null)
		{
		m_InvoiceStubs = p_InvoiceStubs;
		l_Count = this.countInvoiceStubs(m_OnlyExpired.isSelected());
		m_PrintMailingButton.setEnabled(l_Count > 0);
		m_NumberOfMailings.setText (l_Count.toString());
		}
	}

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

//public void setSortingCriteria (int p_SortingProperty, int p_SortDirection)
//	{
//	m_SortingProperty = p_SortingProperty;
//	m_SortDirection   = p_SortDirection;
//	}


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

public void setMarkAsCopy (boolean p_MarkAsCopy)
	{
	m_MarkAsCopy = p_MarkAsCopy;
	}

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

public void setNumberOfInvoiceCopies (int p_NumberOfCopies)
	{
	m_NumberOfInvoiceCopies = p_NumberOfCopies;
	m_NumberOfInvoices.setValue (m_NumberOfInvoiceCopies);
	}

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

public void setNumberOfReminderCopies (int p_NumberOfCopies)
	{
	m_NumberOfReminderCopies = p_NumberOfCopies;
	m_NumberOfCopies.setValue (m_NumberOfReminderCopies);
	}

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

/**
 * @author ferring
 * @param p_Join
 */
public void setJoinReminders (Boolean p_Join)
	{
	if (p_Join == null)
		{
		m_JoinReminders.setVisible(false);
		m_JoinReminders.setSelected(false);
		m_JoinRemindersLabel.setVisible(false);
		} 
	else 
		{
		m_JoinReminders.setSelected(p_Join);// && m_CanEnableJoinReminders);
		}
	}

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

private void enableJoinRemindersBox () 
	{
	int l_NumberOfCopies = ((Integer)m_NumberOfCopies.getValue()).intValue();
	
	if (l_NumberOfCopies > 0)
		{
		m_JoinReminders.setEnabled(true);
		m_JoinRemindersLabel.setEnabled(true);
		}
	else
		{
		m_JoinReminders.setEnabled(false);
		m_JoinRemindersLabel.setEnabled(false);
		}
	} 

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

public void setReminderLevel (int p_ReminderLevel)
	{
	m_ReminderLevel = p_ReminderLevel;
	
	if (BillingPrinterBean.c_PrintInvoice == p_ReminderLevel)
		{
		m_NumberOfCopies.setValue(Integer.valueOf(0));
		m_NumberOfCopies.setEnabled(false);
		}
	else m_NumberOfCopies.setEnabled(true);
	}

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

public Collection <InvoiceStub> getNotPrintedInvoiceStubs ()
	{
	return m_NotPrintedInvoiceStubs;
	}

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

public void setAccount (Account p_Account)
	{
	m_Account = p_Account;
	}

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

public boolean wasAborted ()
	{
	return m_Aborted;
	}

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

public void relocalize() 
	{
	if (m_MailingBorder != null)
		m_MailingBorder.setTitle(Translatrix.getTranslationString (c_MailingBorder));
		
	if (m_NumberOfMailingsLabel != null)
		m_NumberOfMailingsLabel.setText(Translatrix.getTranslationString (c_NumberOfMailingsLabel));

	if (m_NumberOfCopiesLabel != null)
		m_NumberOfCopiesLabel.setText(Translatrix.getTranslationString (c_NumberOfCopiesLabel));
		
	if (m_NumberOfInvoicesLabel != null)
		m_NumberOfInvoicesLabel.setText(Translatrix.getTranslationString (c_NumberOfInvoicesLabel));
	
	if (m_JoinRemindersLabel != null)
		m_JoinRemindersLabel.setText(Translatrix.getTranslationString(c_JoinRemindersLabel));

	if (m_OnlyExpired != null)
		m_OnlyExpired.setText(Translatrix.getTranslationString (c_OnlyExpiredLabel));
	
	if (m_SettlementVerificationDateLabel != null)
		m_SettlementVerificationDateLabel.setText(Translatrix.getTranslationString (c_SettlementVerificationDateLabel));
	
	if (m_SettlementVerificationDate != null) 
		{
		m_SettlementVerificationDate.setLocale (Translatrix.getLocale());
		m_SettlementVerificationDate.setDateFormatString("d MMMM yyyy");   
		m_SettlementVerificationDate.getDateEditor().setLocale (Translatrix.getLocale());
		}

	if (m_PrintMailingBorder != null)
		m_PrintMailingBorder.setTitle(Translatrix.getTranslationString (c_PrintMailingBorder));
	
	if (m_PrintMailingButton != null)
		m_PrintMailingButton.setText(Translatrix.getTranslationString(c_PrintMailingButton));
	
	if (m_PrintAll != null) 
		m_PrintAll.setText(Translatrix.getTranslationString(c_PrintAllLabel));

	if (m_PrintFromLabel != null) 
		m_PrintFromLabel.setText(Translatrix.getTranslationString(c_PrintFromLabel));
	
	if (m_PrintToLabel != null) 
		m_PrintToLabel.setText(Translatrix.getTranslationString(c_PrintToLabel));
	
	if (m_CancelButton != null) 
		m_CancelButton.setText(Translatrix.getTranslationString("core.cancel"));
	}

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

public void actionPerformed(ActionEvent p_Event) 
	{
	if (p_Event.getSource().equals(m_PrintMailingButton))
		{		
		if (m_PrintMailingButton.getText().equals(Translatrix.getTranslationString(c_PrintMailingButton)))
			{
			if (BillingModule.userHasPermission(BillingModule.c_BillingModule, BillingModule.c_printReminders))
				this.startBatchPrinting();
			}
		else if (m_PrintMailingButton.getText().equals(Translatrix.getTranslationString(c_PrintSuspendButton)))
			{
			m_Suspend = true;
			}	
		else if (m_PrintMailingButton.getText().equals(Translatrix.getTranslationString(c_PrintResumeButton)))
			{
			this.resumeBatchPrinting();
			}	
		}
	else if (p_Event.getSource().equals (m_CancelButton))
		{
		this.abortBatchPrinting();
		this.setVisible (false);
		}
	else if (p_Event.getSource().equals (m_Timer))
		{
		m_PrintMailingProgress.setString (Translatrix.getTranslationString(c_WaitingForPrinter));	
		}

	}

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

public void itemStateChanged(ItemEvent p_Event) 
	{
	Integer	l_Count;
	boolean l_EnableIt;
	
	if (p_Event.getSource().equals(m_OnlyExpired))
		{
		if (m_NumberOfMailings != null)
			{
			l_Count = this.countInvoiceStubs (m_OnlyExpired.isSelected());
			m_PrintMailingButton.setEnabled(l_Count > 0);
			m_NumberOfMailings.setText (l_Count.toString());
			}
		}	
	else if (p_Event.getSource().equals (m_PrintAll))
		{
		l_EnableIt = (p_Event.getStateChange() == ItemEvent.DESELECTED)?true:false; 

		if (	(m_PrintFromLabel == null) || (m_PrintToLabel == null)
				|| (m_PrintFrom	  == null) || (m_PrintTo      == null)) return;
		
		m_PrintFromLabel.setEnabled(l_EnableIt);
		m_PrintFrom.setEnabled(l_EnableIt);
		m_PrintToLabel.setEnabled(l_EnableIt);
		m_PrintTo.setEnabled(l_EnableIt);
		
		if (l_EnableIt)
			{
			if ((m_InvoiceStubs != null) && (m_InvoiceStubs.size() > 0))
				{
				m_PrintFrom.setValue(Integer.valueOf (1));
				m_PrintTo.setValue((Integer)m_InvoiceStubs.size());
				}
			}
		}	
	}

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

private boolean useShortInvoiceNumbers ()
	{
	if (m_ShortInvoiceNumbers == null) 
		{
		Object l_Value = BillingModule.getSetting(BillingAdminSettings.c_ShortInvoiceNumbersSetting);

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

	return m_ShortInvoiceNumbers.booleanValue();
	}


private boolean useLeadingZeros ()
{
if (m_UseLeadingZeros == null) 
	{
	Object l_Value = BillingModule.getSetting(BillingAdminSettings.c_UseLeadingZerosSetting);

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

return m_UseLeadingZeros.booleanValue();
}

private InvoiceInterface getInvoiceInterface()
{
if (m_InvoiceInterface != null) return m_InvoiceInterface;

try {
	m_InvoiceInterface = (InvoiceInterface) ManagerFactory.getStatefulRemote(InvoiceBean.class);
	} 
catch (Exception p_Exception) 
	{
	m_Logger.warn(p_Exception.getLocalizedMessage());
	}

return m_InvoiceInterface;
}

public void setProgressWorkFlow(boolean progressWorkflow) {
	m_ProgressWorkflow = progressWorkflow;
}
			
//---------------------------------------------------------------------------	


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