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

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import javax.swing.AbstractButton;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Act;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Invoice;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Rate;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Suffix;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.TemplateRate;
import lu.tudor.santec.gecamed.billing.ejb.session.beans.InvoiceBean;
import lu.tudor.santec.gecamed.billing.ejb.session.beans.NomenclatureBean;
import lu.tudor.santec.gecamed.billing.ejb.session.beans.RuleBean;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.InvoiceInterface;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.NomenclatureInterface;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.RuleInterface;
import lu.tudor.santec.gecamed.billing.gui.BillingModule;
import lu.tudor.santec.gecamed.billing.gui.act.ActListBox;
import lu.tudor.santec.gecamed.billing.gui.act.ActListModel;
import lu.tudor.santec.gecamed.billing.gui.act.HospitalisationClassListener;
import lu.tudor.santec.gecamed.billing.gui.config.BillingUserSettingsPlugin;
import lu.tudor.santec.gecamed.billing.gui.event.invoice.InvoiceChangeEvent;
import lu.tudor.santec.gecamed.billing.gui.event.invoice.InvoiceListener;
import lu.tudor.santec.gecamed.billing.gui.event.usermode.UserModeListener;
import lu.tudor.santec.gecamed.billing.gui.hospitalisation.HospitalisationPanel;
import lu.tudor.santec.gecamed.billing.gui.hospitalisation.HospitalisationPeriodDialog;
import lu.tudor.santec.gecamed.billing.gui.print.InvoicePrinter;
import lu.tudor.santec.gecamed.billing.gui.rate.RateSearchDialog;
import lu.tudor.santec.gecamed.billing.gui.templates.InvoiceTemplateDialog;
import lu.tudor.santec.gecamed.billing.utils.BillingAdminSettings;
import lu.tudor.santec.gecamed.billing.utils.BillingUserSettings;
import lu.tudor.santec.gecamed.billing.utils.InvoiceWorkflow;
import lu.tudor.santec.gecamed.billing.utils.rules.RuleOptions;
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.GECAMedTab;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.utils.LogFileViewer;
import lu.tudor.santec.gecamed.core.gui.widgets.AccidentPropertiesPanel;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
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.patient.ejb.entity.beans.HospitalisationClass;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Insurance;
import lu.tudor.santec.i18n.Relocalizable;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.jfree.data.time.Month;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

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

public class InvoiceEditorPanel extends GECAMedTab implements 	ActionListener,
														  		TableModelListener,
														  		PropertyChangeListener,
														  		UserModeListener,
														  		InvoiceListener,
														  		Relocalizable,
														  		HospitalisationClassListener
{
	private static final long serialVersionUID = 1L;

	private InvoiceInterface			m_InvoiceInterface;
	private RuleInterface				m_RuleInterface;
	private NomenclatureInterface		m_NomenclatureInterface;
	
	private Invoice						m_Invoice;
	private ActListBox					m_Acts;
	private RateSearchDialog			m_RateSearch;
	
	private JButton						m_AddActButton;
	private JButton						m_RemoveActButton;
	private JButton						m_BrowseActButton;
	private JButton 					m_AddHospPeriodButton;
	private JButton						m_OpenTemplateButton;
	
	private JButton						m_SaveTemplateButton;
	private JButton						m_ApplyRulesButton;
	
	private JButton						m_PrintInvoiceButton;
	private JButton						m_SplitInvoiceButton;
	private JButton						m_SettleInvoiceButton;
	private JButton						m_CancelInvoiceButton;
	private JButton						m_SaveInvoiceButton;
	
//	private	int							m_DuePeriod	= 45;
	private static final int			c_DefaultHours = 12;
	private static final int			c_DefaultMinutes = 0;
	
	private boolean						m_Showing;
	private boolean						m_ExtendedMode;
//	private boolean						m_ApplyRulesOnSave;
	private boolean						m_AutomaticallyAddActs;
	
	private boolean						m_SavingCanceled = false;
	
	private int							m_LastEditorKey = -1;
	
	private HospitalisationPeriodDialog	m_HospitalisationDialog;
	
	private static Logger m_Logger = Logger.getLogger ("gecamed.billing.gui.InvoiceEditorPanel");

	
//***************************************************************************
//* Class Constants                                                         *
//***************************************************************************

	private static final String c_AddActButton    		= "InvoiceEditorPanel.AddActButton";
	private static final String c_RemoveActButton 		= "InvoiceEditorPanel.RemoveActButton";
	private static final String c_BrowseActButton 		= "InvoiceEditorPanel.BrowseActButton";
	private static final String c_HospPeriodButton 		= "InvoiceEditorPanel.AddHospPeriodButton";
	private static final String c_OpenTemplateButton 	= "InvoiceEditorPanel.OpenTemplateButton";
	private static final String c_SaveTemplateButton 	= "InvoiceEditorPanel.SaveTemplateButton";
	private static final String c_ApplyRulesButton 		= "InvoiceEditorPanel.ApplyRulesButton";
	private static final String c_SaveInvoiceButton 	= "InvoiceEditorPanel.SaveInvoiceButton";
	private static final String c_PrintInvoiceButton 	= "InvoiceEditorPanel.PrintInvoiceButton";
	private static final String c_PrintCopyButton 		= "InvoiceEditorPanel.PrintCopyButton";
	private static final String c_PrintSettledButton 	= "InvoiceEditorPanel.PrintSettledButton";
	private static final String c_SettleInvoiceButton 	= "InvoiceEditorPanel.SettleInvoiceButton";
	private static final String c_CancelInvoiceButton 	= "InvoiceEditorPanel.CancelInvoiceButton";
	
	private static final String c_AddActTip    			= "InvoiceEditorPanel.AddActTip";
	private static final String c_RemoveActTip 			= "InvoiceEditorPanel.RemoveActTip";
	private static final String c_BrowseActTip 			= "InvoiceEditorPanel.BrowseActTip";
	private static final String c_HospPeriodTip 		= "InvoiceEditorPanel.HospPeriodTip";
	private static final String c_OpenTemplateTip	 	= "InvoiceEditorPanel.OpenTemplateTip";
	private static final String c_SaveTemplateTip	 	= "InvoiceEditorPanel.SaveTemplateTip";
	private static final String c_ApplyRulesTip	 		= "InvoiceEditorPanel.ApplyRulesTip";
	private static final String c_SaveInvoiceTip	 	= "InvoiceEditorPanel.SaveInvoiceTip";
	private static final String c_PrintInvoiceTip	 	= "InvoiceEditorPanel.PrintInvoiceTip";
	private static final String c_PrintCopyTip			= "InvoiceEditorPanel.PrintCopyTip";
	private static final String c_PrintSettledTip		= "InvoiceEditorPanel.PrintSettledTip";
	private static final String c_SettleInvoiceTip	 	= "InvoiceEditorPanel.SettleInvoiceTip";
	private static final String c_CancelInvoiceTip	 	= "InvoiceEditorPanel.CancelInvoiceTip";
	
	public static final String c_InvoiceModified		= "InvoiceEditorPanel.InvoiceModified";
	public static final String c_InvoiceSaved			= "InvoiceEditorPanel.InvoiceSaved";
	public static final String c_InvoicePrinted			= "InvoiceEditorPanel.InvoicePrinted";
	public static final String c_InvoicePaid			= "InvoiceEditorPanel.InvoicePaid";
	public static final String c_InvoiceUpdated			= "InvoiceEditorPanel.InvoiceUpdated";
	
	public static final String c_UnsavedChangesTitle	= "InvoiceEditorPanel.UnsavedChangesTitle";
	public static final String c_UnsavedChangesMessage	= "InvoiceEditorPanel.UnsavedChangesMessage";
	
	public static final String c_InvoiceUpdatedTitle	= "InvoiceEditorPanel.InvoiceUpdatedTitle";
	public static final String c_InvoiceUpdatedMessage	= "InvoiceEditorPanel.InvoiceUpdatedMessage";
	
	public static final String c_InvoiceDeletedTitle	= "InvoiceEditorPanel.InvoiceDeletedTitle";
	public static final String c_InvoiceDeletedMessage	= "InvoiceEditorPanel.InvoiceDeletedMessage";
	
	private final static String c_Columns 	= "3dlu,fill:1px:grow,3dlu,fill:111dlu,3dlu";
	
	private final static String c_Rows 		= "3dlu,fill:1px:grow,10dlu";
	
	private final static String c_ButtonPanelColumns 	= "fill:pref:grow";
	
	private final static String c_ButtonPanelRows 		= 
										 	"fill:max(10dlu;pref),3dlu,fill:max(10dlu;pref),3dlu,fill:max(10dlu;pref),3dlu,fill:max(10dlu;pref),10dlu," +
										 	"fill:max(10dlu;pref),3dlu,fill:max(10dlu;pref),10dlu," +
										 	"fill:max(10dlu;pref),fill:max(10dlu;pref):grow," +
										 	"fill:max(10dlu;pref),3dlu,fill:max(10dlu;pref),3dlu,fill:max(10dlu;pref),3dlu,fill:max(10dlu;pref)";
	
	
	private final static String c_C38Code				= "C38";
		
	private static final boolean [][] m_ButtonStateTable = 
	{
					// Add		Remove		Browse	OpenTmpl	SaveTmpl	Apply	Save		Print	Settle	Cancel
	/* NEW */ 		{ true,		true,		true,	true,		true,		true,	true,		true,	true,	false },
	/* OPN */ 		{ true,		true,		true,	true,		true,		true,	true,		true,	true,	false },
	/* VER */ 		{ true,		true,		true,	false,		true,		true,	true,		true,	true,	false },
	/* CLS */ 		{ false,	false,		false,	false,		true,		false,	false,		true,	false,	false },
	/* PRN */ 		{ false,	false,		false,	false,		true,		false,	false,		true,	true,	false },
	/* REM */ 		{ false,	false,		false,	false,		true,		false,	false,		true,	true,	false },
	/* PAI */ 		{ false,	false,		false,	false,		true,		false,	false,		true,	true,	false },
	/* CAN */ 		{ false,	false,		false,	false,		true,		false,	false,		false,	false,	false },
	/* DEL */ 		{ false,	false,		false,	false,		true,		false,	false,		false,	false,	false }
	};
	
	private static final boolean [] m_ExtendedButtonStates =
	/* Extended */ 	{ true,		true,		true,	true,		true,		true,	true,		true,	true,	true };
	
	
//***************************************************************************
//* Constructor(s)                                                          *
//***************************************************************************

public InvoiceEditorPanel (Collection <Suffix> p_Suffixes, Collection <Physician> p_Physicians)
	{	
	CellConstraints		l_Constraints;
	FormLayout			l_Layout;
	ImageIcon			l_Icon; 
	MouseAdapter		l_MouseAdapter;
	FormLayout 			l_ButtonPanelLayout;
	JPanel 				l_ButtonPanel;
	JScrollPane 		l_ScrollPane;
	
	m_InvoiceInterface 		= null;
	m_RuleInterface   		= null;
	m_NomenclatureInterface = null;
	m_Invoice    	  		= null;
	m_Showing				= false;
	m_ExtendedMode			= false;
//	m_ApplyRulesOnSave		= false;
	
	l_Constraints  = new CellConstraints();
	     
	l_Layout = new FormLayout(c_Columns, c_Rows);
	this.setLayout(l_Layout);
	this.setOpaque(false);

	m_Acts	= new ActListBox (p_Suffixes,p_Physicians);
	m_Acts.getViewport().setOpaque(false);
	m_Acts.setBackground(GECAMedColors.c_ScrollPaneBackground);
	m_Acts.addTableModelListener(this);
	
  	//-----------------------------------------------------------------------
   	// Setup a MouseAdapter to intercept double-clicks on invoice. Double-click
   	// on invoice ought to open invoice in Editor Panel. Right-click on invoice
   	// ought to settle currently selected invoice.
    //-----------------------------------------------------------------------
  	
   	l_MouseAdapter = new MouseAdapter()
    		{
    		public void mouseClicked(MouseEvent p_Event)
    			{
    			if (p_Event.getClickCount() == 2)
    				{
    				if (!m_Acts.isEditing()) addAct (new Act(),true, false); 
    				}
    			}
    		};
    
    m_Acts.addMouseListener(l_MouseAdapter);
    				
	m_RateSearch = new RateSearchDialog (ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
	
	l_Icon = BillingModule.getButtonIcon ("add_act.png");
	m_AddActButton = new JButton (Translatrix.getTranslationString(c_AddActButton),l_Icon);
	m_AddActButton.setToolTipText (Translatrix.getTranslationString(c_AddActTip));
	m_AddActButton.setHorizontalAlignment(SwingConstants.LEFT);
	m_AddActButton.setVerticalTextPosition(AbstractButton.CENTER);
	m_AddActButton.setHorizontalTextPosition(AbstractButton.TRAILING); 
	m_AddActButton.setEnabled(false);
	
	l_Icon = BillingModule.getButtonIcon ("remove_act.png");
	m_RemoveActButton = new JButton (Translatrix.getTranslationString(c_RemoveActButton),l_Icon);
	m_RemoveActButton.setToolTipText (Translatrix.getTranslationString(c_RemoveActTip));
	m_RemoveActButton.setHorizontalAlignment(SwingConstants.LEFT);
	m_RemoveActButton.setVerticalTextPosition(AbstractButton.CENTER);
	m_RemoveActButton.setHorizontalTextPosition(AbstractButton.TRAILING); 
	m_RemoveActButton.setEnabled(false);

	l_Icon = BillingModule.getButtonIcon ("browse_act.png");
	m_BrowseActButton = new JButton (Translatrix.getTranslationString(c_BrowseActButton),l_Icon);
	m_BrowseActButton.setToolTipText (Translatrix.getTranslationString(c_BrowseActTip));
	m_BrowseActButton.setHorizontalAlignment(SwingConstants.LEFT);
	m_BrowseActButton.setVerticalTextPosition(AbstractButton.CENTER);
	m_BrowseActButton.setHorizontalTextPosition(AbstractButton.TRAILING); 
	m_BrowseActButton.setEnabled(false);
	
	l_Icon = BillingModule.getButtonIcon("hospitalisation.png");
	m_AddHospPeriodButton = new JButton(Translatrix.getTranslationString(c_HospPeriodButton), l_Icon);
	m_AddHospPeriodButton.setToolTipText (Translatrix.getTranslationString(c_HospPeriodTip));
	m_AddHospPeriodButton.setHorizontalAlignment(SwingConstants.LEFT);
	m_AddHospPeriodButton.setVerticalTextPosition(AbstractButton.CENTER);
	m_AddHospPeriodButton.setHorizontalTextPosition(AbstractButton.TRAILING); 
	m_AddHospPeriodButton.setEnabled(false);
	
	l_Icon = BillingModule.getButtonIcon ("open_template.png");
	m_OpenTemplateButton = new JButton (Translatrix.getTranslationString(c_OpenTemplateButton),l_Icon);
	m_OpenTemplateButton.setToolTipText (Translatrix.getTranslationString(c_OpenTemplateTip));
	m_OpenTemplateButton.setHorizontalAlignment(SwingConstants.LEFT);
	m_OpenTemplateButton.setVerticalTextPosition(AbstractButton.CENTER);
	m_OpenTemplateButton.setHorizontalTextPosition(AbstractButton.TRAILING); 
	m_OpenTemplateButton.setEnabled(false);
	
	l_Icon = BillingModule.getButtonIcon ("save_template.png");
	m_SaveTemplateButton = new JButton (Translatrix.getTranslationString(c_SaveTemplateButton),l_Icon);
	m_SaveTemplateButton.setToolTipText (Translatrix.getTranslationString(c_SaveTemplateTip));
	m_SaveTemplateButton.setHorizontalAlignment(SwingConstants.LEFT);
	m_SaveTemplateButton.setVerticalTextPosition(AbstractButton.CENTER);
	m_SaveTemplateButton.setHorizontalTextPosition(AbstractButton.TRAILING); 
	m_SaveTemplateButton.setEnabled(false);

    l_Icon = BillingModule.getButtonIcon ("apply_rules.png");
	m_ApplyRulesButton = new JButton (Translatrix.getTranslationString(c_ApplyRulesButton),l_Icon);
	m_ApplyRulesButton.setToolTipText (Translatrix.getTranslationString(c_ApplyRulesTip));
	m_ApplyRulesButton.setHorizontalAlignment(SwingConstants.LEFT);
	m_ApplyRulesButton.setVerticalTextPosition(AbstractButton.CENTER);
	m_ApplyRulesButton.setHorizontalTextPosition(AbstractButton.TRAILING); 
	m_ApplyRulesButton.setEnabled(false);
	m_ApplyRulesButton.addMouseListener(new MouseAdapter() {
		@Override
		public void mouseClicked(MouseEvent e) {
			super.mouseClicked(e);
			if (e.getButton() == MouseEvent.BUTTON3) {
				if (m_Invoice.getRuleLog() != null) {
					LogFileViewer.showLogFile(MainFrame.getInstance(), "Rule Log", m_Invoice.getRuleLog(), false);					
				}
			}
		}
	});

	l_Icon = BillingModule.getButtonIcon ("save_invoice.png");
	m_SaveInvoiceButton = new JButton (Translatrix.getTranslationString(c_SaveInvoiceButton),l_Icon);
	m_SaveInvoiceButton.setToolTipText (Translatrix.getTranslationString(c_SaveInvoiceTip));
	m_SaveInvoiceButton.setHorizontalAlignment(SwingConstants.LEFT);
	m_SaveInvoiceButton.setVerticalTextPosition(AbstractButton.CENTER);
	m_SaveInvoiceButton.setHorizontalTextPosition(AbstractButton.TRAILING); 
	m_SaveInvoiceButton.setEnabled(false);

	l_Icon = BillingModule.getButtonIcon ("print_invoice.png");
	m_PrintInvoiceButton = new JButton (Translatrix.getTranslationString(c_PrintInvoiceButton),l_Icon);
	m_PrintInvoiceButton.setToolTipText (Translatrix.getTranslationString(c_PrintInvoiceTip));
	m_PrintInvoiceButton.setHorizontalAlignment(SwingConstants.LEFT);
	m_PrintInvoiceButton.setVerticalTextPosition(AbstractButton.CENTER);
	m_PrintInvoiceButton.setHorizontalTextPosition(AbstractButton.TRAILING); 
	m_PrintInvoiceButton.setEnabled(false);
	
	l_Icon = BillingModule.getButtonIcon ("print_invoice.png");
	m_SplitInvoiceButton = new JButton (Translatrix.getTranslationString("InvoiceEditorPanel.SplitFirstClassInvoice"),l_Icon);
	m_SplitInvoiceButton.setToolTipText (Translatrix.getTranslationString("InvoiceEditorPanel.SplitFirstClassInvoiceTitle"));
	m_SplitInvoiceButton.setHorizontalAlignment(SwingConstants.LEFT);
	m_SplitInvoiceButton.setVerticalTextPosition(AbstractButton.CENTER);
	m_SplitInvoiceButton.setHorizontalTextPosition(AbstractButton.TRAILING); 
	m_SplitInvoiceButton.setEnabled(false);

	l_Icon = BillingModule.getButtonIcon ("settle_invoice.png");
	m_SettleInvoiceButton = new JButton (Translatrix.getTranslationString(c_SettleInvoiceButton),l_Icon);
	m_SettleInvoiceButton.setToolTipText (Translatrix.getTranslationString(c_SettleInvoiceTip));
	m_SettleInvoiceButton.setHorizontalAlignment(SwingConstants.LEFT);
	m_SettleInvoiceButton.setVerticalTextPosition(AbstractButton.CENTER);
	m_SettleInvoiceButton.setHorizontalTextPosition(AbstractButton.TRAILING); 
	m_SettleInvoiceButton.setEnabled(false);
	
	l_Icon = BillingModule.getButtonIcon ("cancel_invoice.png");
	m_CancelInvoiceButton = new JButton (Translatrix.getTranslationString(c_CancelInvoiceButton),l_Icon);
	m_CancelInvoiceButton.setToolTipText (Translatrix.getTranslationString(c_CancelInvoiceTip));
	m_CancelInvoiceButton.setHorizontalAlignment(SwingConstants.LEFT);
	m_CancelInvoiceButton.setVerticalTextPosition(AbstractButton.CENTER);
	m_CancelInvoiceButton.setHorizontalTextPosition(AbstractButton.TRAILING); 
	m_CancelInvoiceButton.setEnabled(false);
	
	l_ButtonPanelLayout = new FormLayout	(c_ButtonPanelColumns, c_ButtonPanelRows);
	l_ButtonPanel 		= new JPanel 		(l_ButtonPanelLayout);
	l_ScrollPane 		= new JScrollPane 	(l_ButtonPanel);
	
	l_ButtonPanel.setOpaque(false);
	l_ScrollPane.setOpaque(false);
	l_ScrollPane.getViewport().setOpaque(false);
//	l_ScrollPane.setBorder(BorderFactory.createEmptyBorder());
	l_ScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
	
	this.add (m_Acts, 		l_Constraints.xy(2, 2));
	this.add (l_ScrollPane, l_Constraints.xy(4, 2));
	
	l_ButtonPanel.add (m_AddActButton, 			l_Constraints.xy(1, 1));
	l_ButtonPanel.add (m_RemoveActButton, 		l_Constraints.xy(1, 3));
	l_ButtonPanel.add (m_BrowseActButton, 		l_Constraints.xy(1, 5));
	l_ButtonPanel.add (m_AddHospPeriodButton, 	l_Constraints.xy(1, 7));
	l_ButtonPanel.add (m_OpenTemplateButton, 	l_Constraints.xy(1, 9));
	l_ButtonPanel.add (m_SaveTemplateButton, 	l_Constraints.xy(1, 11));
	l_ButtonPanel.add (m_ApplyRulesButton, 		l_Constraints.xy(1, 13));
	l_ButtonPanel.add (m_SaveInvoiceButton, 	l_Constraints.xy(1, 15));
	l_ButtonPanel.add (m_PrintInvoiceButton, 	l_Constraints.xy(1, 17));
	l_ButtonPanel.add (m_SettleInvoiceButton, 	l_Constraints.xy(1, 19));
	l_ButtonPanel.add (m_SplitInvoiceButton, 	l_Constraints.xy(1, 21));
//	l_ButtonPanel.add (m_CancelInvoiceButton, 	l_Constraints.xy(1, 21);
	
	m_AddActButton.addActionListener        (this);
	m_RemoveActButton.addActionListener     (this);
	m_BrowseActButton.addActionListener     (this);
	m_AddHospPeriodButton.addActionListener (this);
	m_OpenTemplateButton.addActionListener	(this);
	m_SaveTemplateButton.addActionListener	(this);
	m_ApplyRulesButton.addActionListener    (this);
	m_SaveInvoiceButton.addActionListener   (this);
	m_PrintInvoiceButton.addActionListener  (this);
	m_SettleInvoiceButton.addActionListener (this);	
	m_SplitInvoiceButton.addActionListener (this);
	
	BillingModule.getInstance().getAccidentProperties().addPropertyChangeListener(this);
	BillingModule.getInstance().getHospitalisationProperties().addPropertyChangeListener(this);
	BillingModule.getInstance().addUserModeListener(this);
	BillingModule.getInstance().addInvoiceListener(this);
	BillingModule.getInstance().addHospitalisationClassListener(this);
	
	Invoice.setExpiryPeriod((Integer)BillingModule.getSetting(BillingAdminSettings.c_DuePeriodSetting));
	
	m_AutomaticallyAddActs = (Boolean)BillingModule.getUserSetting(BillingUserSettings.c_AutomaticallyAddActsSetting);
	
	}
	
//***************************************************************************
//* Primitives                                       						*
//***************************************************************************

//---------------------------------------------------------------------------
//===========================================================================
//= Getters for required Interfaces
//===========================================================================
//---------------------------------------------------------------------------

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 Invoice getSelectedInvoice ()
{
	return m_Invoice;
}

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

private RuleInterface getRuleInterface ()
	{
	if (m_RuleInterface != null) return m_RuleInterface;

	try {
		m_RuleInterface = (RuleInterface) ManagerFactory.getRemote(RuleBean.class);
		} 
	catch (Exception p_Exception) 
		{
		m_Logger.warn(p_Exception.getLocalizedMessage());
		}

	return m_RuleInterface;
	}

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

private NomenclatureInterface getNomenclatureInterface ()
	{
	if (m_NomenclatureInterface != null) return m_NomenclatureInterface;

	try {
		m_NomenclatureInterface = (NomenclatureInterface) ManagerFactory.getRemote(NomenclatureBean.class);
		} 
	catch (Exception p_Exception) 
		{
		m_Logger.warn(p_Exception.getLocalizedMessage());
		}

	return m_NomenclatureInterface;
	}

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

private void setModifier ()
	{
	if (m_Invoice == null) return;
	
	m_Invoice.setModifier(BillingModule.getCurrentUser());
	m_Invoice.setModificationDate(new Date ());
	}

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

private void updateInvoice (boolean notify)
	{
	if (m_Invoice == null) return;
	
	m_Invoice.setActs(m_Acts.getActs());
	m_Invoice.monetize();
	this.setModified(notify);
	if (notify) {
		this.firePropertyChange(InvoiceEditorPanel.c_InvoiceModified,null,m_Invoice);				
	}
	}

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

public static Date getPerformedDateWithDefaultTime (Date p_InvoiceDate)
	{
	GregorianCalendar l_NewDate;
	
	if (p_InvoiceDate == null) return new Date ();
	
	l_NewDate = new GregorianCalendar();
	l_NewDate.setTime (p_InvoiceDate);
	l_NewDate.set(Calendar.HOUR_OF_DAY,c_DefaultHours);
	l_NewDate.set(Calendar.MINUTE,c_DefaultMinutes);
	l_NewDate.set(Calendar.SECOND,0);
	l_NewDate.set(Calendar.MILLISECOND,0);

	return l_NewDate.getTime();
	}

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

private void stopEditing ()
	{
	m_AutomaticallyAddActs = false;
	m_Acts.stopEditing();
	m_AutomaticallyAddActs = (Boolean)BillingModule.getUserSetting(BillingUserSettings.c_AutomaticallyAddActsSetting);
	}

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

	public void addAct (Act p_Act, boolean p_requiresFocus, boolean keepDate)
	{
		if ((m_Invoice == null) || (p_Act == null))
			return;
		
		if (BillingModule.userHasPermissionForInvoice(m_Invoice, BillingModule.c_editStem, true) == false)
			return;
		
		if (m_Invoice.isLocked() && !m_ExtendedMode)
			return;
		
		BillingModule.getInstance().getInvoiceProperties().updateInvoice(m_Invoice);
		
		Date	performedDate;
		Act		l_SelectedAct	= m_Acts.getSelectedAct();
		int		l_Row;
		
		
		if (l_SelectedAct != null)
		{
			
			if (! keepDate) {
				p_Act.setPerformedDate(			l_SelectedAct.getPerformedDate());
				p_Act.setShowTime(				l_SelectedAct.getShowTime());
			}
			
			p_Act.setHospitalisationClass(	l_SelectedAct.getHospitalisationClass(), m_Invoice);
			p_Act.setMedPrescCode(			l_SelectedAct.getMedPrescCode());
			if (p_Act.getPhysicianId() == null) {
				p_Act.setPhysicianId(l_SelectedAct.getPhysicianId());				
			}
		}
		else
		{
			if (! keepDate) {
				performedDate = m_Invoice.getInvoiceDate();
				performedDate = getPerformedDateWithDefaultTime(performedDate);
				p_Act.setPerformedDate(performedDate);
			}
			
			if (m_Invoice.getHospitalisationClass() == null)
				p_Act.setHospitalisationClass(HospitalisationClass.c_Ambulant, m_Invoice);
			else
				p_Act.setHospitalisationClass(m_Invoice.getHospitalisationClass().getAcronym(), m_Invoice);
			
			if (p_Act.getPhysicianId() == null && m_Invoice.getPhysician() != null)
			{
				p_Act.setPhysicianId(m_Invoice.getPhysician().getId());
			}
		}
		
		// set majoration from the current insurance.
		p_Act.setMajoration(m_Invoice.getMajoration());
		
		l_Row = m_Acts.addAct(p_Act);
		m_Acts.select(l_Row >= 0 ? l_Row : m_Acts.getActs().size() - 1);
//		m_Acts.selectAct(p_Act.getCode());
		
		if (p_requiresFocus)
			m_Acts.focusOnSelectedAct();
		
		this.updateInvoice(p_Act.getCode() != null && ! "".equals(p_Act.getCode().trim()));
	}

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

private void removeSelectedActs ()
	{
	if (BillingModule.userHasPermissionForInvoice(m_Invoice, BillingModule.c_editStem,true) == false) return;		

	if (m_Invoice.isLocked() && !m_ExtendedMode) return;
	
	BillingModule.getInstance().getInvoiceProperties().updateInvoice	(m_Invoice);

	m_Acts.removeSelectedActs();
	
	this.updateInvoice(true);
	
	m_SaveTemplateButton.setEnabled(doesValidActExist());
	}

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

private void saveAsInvoiceTemplate ()
	{
	InvoiceTemplateDialog	l_Dialog;	
	
	l_Dialog = new InvoiceTemplateDialog (InvoiceTemplateDialog.c_SaveDialog);
	l_Dialog.pack ();
	
	l_Dialog.setActsForTemplate(m_Invoice.getActs());
	
	MainFrame.showDialogCentered(l_Dialog);
	}

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

private void createInvoiceFromTemplate ()
	{
	InvoiceTemplateDialog	l_Dialog;	
	Set <TemplateRate>		l_TemplateRates;
	Iterator <TemplateRate>	l_RateIterator;
	TemplateRate 			l_TemplateRate;
	Date					l_ActDate;
	Calendar				l_ActCal;
	Rate					l_Rate;
	Act						l_Act;
	Boolean					l_SettingsCheck;
	
	if (m_Invoice == null) return;
	if (m_Invoice.isLocked() && !m_ExtendedMode) return;
	
	if (BillingModule.userHasPermissionForInvoice(m_Invoice, BillingModule.c_editStem, true) == false) return;		

	l_Dialog = new InvoiceTemplateDialog (InvoiceTemplateDialog.c_OpenDialog);
	
	l_Act = m_Acts.getSelectedAct();
	if (l_Act != null)
		 l_ActDate = l_Act.getPerformedDate();
//	else l_ActDate = m_Invoice.getInvoiceDate();
	else l_ActDate = BillingModule.getInstance().getDateOfInvoicePropertiesPanel();
	l_Dialog.setActDate(l_ActDate);
	
	l_Dialog.pack ();
	
	MainFrame.showDialogCentered(l_Dialog);
			
	if (l_Dialog.wasValidated() == false) return;
	
	BillingModule.getInstance().getInvoiceProperties().updateInvoice (m_Invoice);
	
	l_TemplateRates = l_Dialog.getRatesFromTemplate();
	if (l_TemplateRates == null) return;
	
	l_ActDate = l_Dialog.getActDate();
	if (l_ActDate == null)
		l_ActDate = new Date();
	
	// set time to 12:00.000
	l_ActCal = new GregorianCalendar();
	l_ActCal.setTime(l_ActDate);
	l_ActCal.set(Calendar.HOUR_OF_DAY,	12);
	l_ActCal.set(Calendar.MINUTE,		0);
	l_ActCal.set(Calendar.SECOND,		0);
	l_ActCal.set(Calendar.MILLISECOND,	0);
	l_ActDate = l_ActCal.getTime();
	
	l_RateIterator = l_TemplateRates.iterator();
	while (l_RateIterator.hasNext())
		{
		l_TemplateRate = l_RateIterator.next();
		l_Rate = l_TemplateRate.getRate();
		l_Act = new Act ();
		l_Act.setPerformedDate (this.getPerformedDateWithDefaultTime(m_Invoice.getInvoiceDate()));
		
		if (m_Invoice.getPhysician() != null) l_Act.setPhysicianId (m_Invoice.getPhysician().getId());	
		
		try {
			l_Act = getNomenclatureInterface().initializeAct(l_Rate.getCode(), l_Act);			
		} catch (Exception e) {
			m_Logger.error("Error initializing Act", e);
		}
		
		// check settings to load the suffixes
		l_SettingsCheck = (Boolean) BillingModule.getUserSetting(BillingUserSettings.c_LoadTemplateSuffixesSettings);
		if (l_SettingsCheck != null && l_SettingsCheck.booleanValue())
			l_Act.setSuffixes(l_TemplateRate.getSuffixes());
		
		// check settings to load the quantity 
		l_SettingsCheck = (Boolean) BillingModule.getUserSetting(BillingUserSettings.c_LoadTemplateQuantitySettings);
		if (l_SettingsCheck != null && l_SettingsCheck.booleanValue())
			l_Act.setQuantity(l_TemplateRate.getQuantity());
		
		l_Act.setPerformedDate(l_ActDate);
		m_Acts.addAct(l_Act);
		}
	
	this.updateInvoice(true);
	}

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

private void applyRules ()
	{
	int		l_Option;
	
	
	if (m_Invoice == null) return;
	
	if (BillingModule.userHasPermissionForInvoice(m_Invoice, BillingModule.c_editStem,true) == false) return;		
	
	if (m_Invoice.isLocked() && !m_ExtendedMode) return;
	
	if (!BillingModule.getInstance().getInvoiceProperties().getHealthInsurance().getUcmAffiliated())
		{
		l_Option	= (Integer) BillingModule.getUserSetting(BillingUserSettings.c_AllowRulesForNotCnsInsurance);
		if (l_Option == BillingUserSettingsPlugin.c_AllowRulesForNotCnsInsuranceNever)
			{
			GECAMedBaseDialogImpl.showMessageDialog(this, 
					Translatrix.getTranslationString("BillingUserSettingsPlugin.RuleWarning.DontAllowRulesTitle"), 
					Translatrix.getTranslationString("BillingUserSettingsPlugin.RuleWarning.DontAllowRulesMessage"), 
					GECAMedBaseDialogImpl.OK_BUTTON_MODE, 
					GECAMedModule.getBigIcon(GECAMedIconNames.ERROR));
			return;
			}
		else if (l_Option == BillingUserSettingsPlugin.c_AllowRulesForNotCnsInsuranceAsk)
			{
			l_Option	= GECAMedBaseDialogImpl.showMessageDialog(this, 
					Translatrix.getTranslationString("BillingUserSettingsPlugin.RuleWarning.AskToAllowRulesTitle"), 
					Translatrix.getTranslationString("BillingUserSettingsPlugin.RuleWarning.AskToAllowRulesMessage"), 
					GECAMedBaseDialogImpl.YES_NO_BUTTON_MODE, 
					GECAMedModule.getBigIcon(GECAMedIconNames.WARNING));
			
			if (l_Option != GECAMedBaseDialogImpl.YES_OPTION)
				return;
			}
		}
	
	removeEmptyActs();
	
	BillingModule.getInstance().getInvoiceProperties().updateInvoice			(m_Invoice);
	BillingModule.getInstance().getAccidentProperties().updateInvoice			(m_Invoice);
	BillingModule.getInstance().getHospitalisationProperties().updateInvoice	(m_Invoice);
//	BillingModule.getInstance().getMedTransProperties().updateInvoice			(m_Invoice);
	
	m_Invoice.setActs(m_Acts.getActs());
	m_Invoice.monetize();
	
	try {
		MainFrame.getInstance().setWaitCursor(true);
		
		m_RuleInterface = this.getRuleInterface();
		
		if (m_RuleInterface != null)
			{
			/* TODO: set the rule options when the changing of settings per invoice is provided 
			 * (replace the 3rd parameter (null) of applyRules with RulesObjectHolder.createRuleObjects(...).)
			 */
			m_Invoice = m_RuleInterface.applyRules (m_Invoice, 
					new RuleOptions(
							(Boolean)BillingModule.getSetting(BillingAdminSettings.c_UseSessionMode), 
							(Integer)BillingModule.getSetting(BillingAdminSettings.c_HospitalizedCumulationMode), 
							m_Invoice.getPatient().getBirthDate(), 
							(Integer)BillingModule.getSetting(BillingAdminSettings.c_TiersPayantMinValue)));
			BillingModule.getInstance().getInvoiceProperties().setInvoice(m_Invoice);
			m_Invoice.monetize();
			m_Acts.setMajoration(m_Invoice.getMajoration());
			m_Acts.setActs(m_Invoice.getActs());
			this.setModified(true);
			this.firePropertyChange(InvoiceEditorPanel.c_InvoiceModified,null,m_Invoice);	
//			m_ApplyRulesOnSave = false;
			}
		}
	catch (Exception p_Exception) 
		{
		m_Logger.log (Level.WARN, "Failed to apply Rules to Invoice",p_Exception);
		}
	finally
		{
		MainFrame.getInstance().setWaitCursor(false);
		}
		if (showModifiedWarning())
			m_Invoice.setUnmodified();
	}

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

private Set <Act> verifyActs (Set <Act> p_Unverified)
	{
	InvoiceInterface 	l_InvoiceInterface = null;
	
	l_InvoiceInterface = this.getInvoiceInterface();
	if (l_InvoiceInterface == null) return p_Unverified;
	
	try	{
		p_Unverified = l_InvoiceInterface.verifyActs(p_Unverified);
		}
	catch (Exception p_Exception) 
		{
		m_Logger.log(Level.ERROR,"Failed to verify acts!",p_Exception);
		}
	
	return p_Unverified;
	}

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

private boolean saveInvoice ()
	{
	int					l_Action;
	int					l_Option;
	Invoice				l_Invoice;
	String 				l_Warning;
	String 				l_FormatedDate;
	String				l_FormatedPatientName;
	String				l_FormatedPhysicianName;
	InvoiceInterface 	l_InvoiceInterface;
	Date				l_CreationDate;
	Calendar			l_FromDate;
	Calendar 			l_ToDate;
	int 				l_Month;
	Invoice				l_OldInvoice;
	
	Set <Act> 			l_Acts;
	String[]			l_Filler;
	
	if (m_Invoice == null) return false;
	
	removeEmptyActs();
	
	if (BillingModule.userHasPermissionForInvoice(m_Invoice, BillingModule.c_editStem,true) == false) return false;		
	
	// if no acts on Invoice, dont't save.
	if (m_Acts.getActs() == null || m_Acts.getActs().size() == 0) {
		return false;
	}
	
	
	m_Invoice.setHealthInsurance(BillingModule.getInstance().getInvoiceProperties().getHealthInsurance());
	m_Invoice.setThirdPartyPayer(BillingModule.getInstance().getInvoiceProperties().getThirdPartyPayer());
	m_Invoice.setHospitalisationClass(BillingModule.getInstance().getHospitalisationProperties().getHospitalisationClass());
	m_Invoice.setFirstClassRequired(BillingModule.getInstance().getHospitalisationProperties().getFirstClassRequired());
	m_Invoice.updateFirstClassRequired();
//	m_Invoice.setMedTrans(BillingModule.getInstance().getMedTransProperties().getMedTrans());
	
	l_Option = (Integer) BillingModule.getUserSetting(BillingUserSettings.c_AllowPrivateActsForCnsInsurance);
	if (l_Option == BillingUserSettingsPlugin.c_AllowCnsAndNonCnsCodesOnInvoiceNever)
	{
		if (m_Invoice.getHealthInsurance().getUcmAffiliated()
				&& m_Invoice.hasPrivateActs())
		{
			// mixed acts are never allowed, warn ... 
			GECAMedBaseDialogImpl.showMessageDialog(this, 
					Translatrix.getTranslationString("BillingUserSettingsPlugin.MixedActs.DenySavingTitle"), 
					Translatrix.getTranslationString("BillingUserSettingsPlugin.MixedActs.DenySavingMessage"), 
					GECAMedBaseDialogImpl.OK_BUTTON_MODE, 
					GECAMedModule.getBigIcon(GECAMedIconNames.ERROR));
			// ... and end
			return false;
		}
	} else if (l_Option == BillingUserSettingsPlugin.c_AllowCnsAndNonCNSCodesOnInvoiceAsk
			&& m_Invoice.getHealthInsurance().getUcmAffiliated()
			&& m_Invoice.hasPrivateActs())
	{
		// ask if the mixed acts are OK
		l_Option = GECAMedBaseDialogImpl.showMessageDialog(this, 
				Translatrix.getTranslationString("BillingUserSettingsPlugin.MixedActs.AskForPermissionTitle"), 
				Translatrix.getTranslationString("BillingUserSettingsPlugin.MixedActs.AskForPermissionMessage"), 
				GECAMedBaseDialogImpl.YES_NO_BUTTON_MODE, 
				GECAMedModule.getIcon(GECAMedIconNames.WARNING));
		
		if (l_Option == GECAMedBaseDialogImpl.NO_OPTION	|| l_Option == GECAMedBaseDialogImpl.CLOSED_OPTION) {
			return false;			
		}
	}
	
	// check if invoice was modified
	if (m_Invoice.isModified()
			&& m_Invoice.hasCnsActs())
		{
		l_Option = (Integer)BillingModule.getUserSetting(BillingUserSettings.c_WarnIfRulesNotApplied);
		if (l_Option == BillingUserSettingsPlugin.c_WarnIfRulesNotAppliedAlways
				|| (l_Option == BillingUserSettingsPlugin.c_WarnIfRulesNotAppliedUCM
				&& m_Invoice.getHealthInsurance().getUcmAffiliated()))
			{
			l_Option	= GECAMedBaseDialogImpl.showMessageDialog(this, 
					Translatrix.getTranslationString("BillingUserSettingsPlugin.RuleWarning.WarningTitle"), 
					Translatrix.getTranslationString("BillingUserSettingsPlugin.RuleWarning.WarningMessage"), 
					GECAMedBaseDialogImpl.YES_NO_CANCEL_BUTTON_MODE, 
					GECAMedModule.getBigIcon(GECAMedIconNames.WARNING));
			
			if (l_Option == GECAMedBaseDialogImpl.YES_OPTION)
				applyRules();
			else if (l_Option == GECAMedBaseDialogImpl.CANCEL_OPTION
					|| l_Option == GECAMedBaseDialogImpl.CLOSED_OPTION)
				return false;
//			else if (l_DialogOption == GECAMedBaseDialogImpl.NO_OPTION) // proceed as normal
			}
		}
	
	l_Acts = m_Acts.getActs();
	for (Act a : l_Acts)
		if (a != null && a.getCode().trim().toUpperCase().equals(c_C38Code))
			{
			// the invoice contains the act C38
			
			/* look up if an invoice of this patient and this physician 
			 * during the last 6 month also contains a C38 
			 */
			l_CreationDate = BillingModule.getInstance().getDateOfInvoicePropertiesPanel();
			
			// set the from date to 6 month earlier than the creation date
			l_FromDate = new GregorianCalendar();
			l_FromDate.setTime(l_CreationDate);
			l_Month = l_FromDate.get(Calendar.MONTH) - 6;
			if (l_Month < Calendar.JANUARY)
				{
				l_Month = Month.DECEMBER + l_Month + 1;
				l_FromDate.set(Calendar.YEAR, l_FromDate.get(Calendar.YEAR) - 1);
				}
			l_FromDate.set(Calendar.MONTH, l_Month);

			// set the to date to 6 month later than the creation date
			l_ToDate = new GregorianCalendar();
			l_ToDate.setTime(l_CreationDate);
			l_Month = l_ToDate.get(Calendar.MONTH) + 6;
			if (l_Month > Calendar.DECEMBER)
				{
				l_Month = Month.JANUARY + (l_Month - Calendar.DECEMBER - 1);
				l_ToDate.set(Calendar.YEAR, l_ToDate.get(Calendar.YEAR) + 1);
				}
			l_ToDate.set(Calendar.MONTH, l_Month);
			
//			System.out.println("FROM: " + l_FromDate.get(Calendar.YEAR) + "-" + (l_FromDate.get(Calendar.MONTH)+1) + "-" + l_FromDate.get(Calendar.DAY_OF_MONTH));
//			System.out.println("TO: " + l_ToDate.get(Calendar.YEAR) + "-" + (l_ToDate.get(Calendar.MONTH)+1) + "-" + l_ToDate.get(Calendar.DAY_OF_MONTH));
			
			l_InvoiceInterface = (InvoiceInterface) ManagerFactory.getRemote(InvoiceBean.class);
			l_Invoice = l_InvoiceInterface.getInvoiceByAct (m_Invoice.getPatient(), m_Invoice.getPhysician(), 
					l_FromDate.getTime(), l_ToDate.getTime(), c_C38Code, m_Invoice.getId());
			
			if (l_Invoice != null)
				{
				// TODO: if another C38 was found, inform the user and ask to continue or to cancel
				l_FormatedDate = new SimpleDateFormat("yyyy-MM-dd").format(l_Invoice.getInvoiceDate());
				l_FormatedPatientName = l_Invoice.getPatient().toShortString();
				l_FormatedPhysicianName = l_Invoice.getPhysician().toString();
				
				l_Warning = Translatrix.getTranslationString("InvoiceEditorPanel.DuplicateC38Message")
							.replace("$DATE", l_FormatedDate)
							.replace("$PHYSICIAN", l_FormatedPhysicianName)
							.replace("$PATIENT", l_FormatedPatientName)
							.replace("$INVOICE_NO", String.valueOf(l_Invoice.getId()));
				
				l_Option = JOptionPane.showConfirmDialog(this, 
						l_Warning, 
						Translatrix.getTranslationString("InvoiceEditorPanel.DuplicateC38Title"), 
						JOptionPane.OK_CANCEL_OPTION, 
						JOptionPane.WARNING_MESSAGE);
				
				if (l_Option == JOptionPane.OK_OPTION)
					// jump out of the loop and go on saving
					break;
				else // if (l_Option == JOptionPane.CANCEL_OPTION)
					// do NOT save, cancel
					return false;
				}
			}
	
	l_Action = InvoiceWorkflow.changeInvoiceState(m_Invoice,InvoiceWorkflow.c_SaveAction);
	if (		(l_Action == InvoiceWorkflow.c_DoSave)
		 || (l_Action == InvoiceWorkflow.c_DoUpdate))
		{
		l_OldInvoice = m_Invoice;
		
		BillingModule.getInstance().getInvoiceProperties().updateInvoice(m_Invoice);
		BillingModule.getInstance().getAccidentProperties().updateInvoice(m_Invoice);
		BillingModule.getInstance().getHospitalisationProperties().updateInvoice(m_Invoice);
//		BillingModule.getInstance().getMedTransProperties().updateInvoice(m_Invoice);
		
		if (m_Invoice.getHealthInsurance().getAcronym().trim().equals("-")
				&& (!m_Invoice.isPersistent()
				|| !l_OldInvoice.getHealthInsurance().getAcronym().trim().equals("-")))
		{
			l_Option	= GECAMedBaseDialogImpl.showMessageDialog(this, 
					Translatrix.getTranslationString("InvoiceEditorPanel.NoInsuranceSetTitle"), 
					Translatrix.getTranslationString("InvoiceEditorPanel.NoInsuranceSetMessage"), 
					GECAMedBaseDialogImpl.YES_NO_BUTTON_MODE, 
					GECAMedModule.getBigIcon(GECAMedIconNames.WARNING));
			
			if (l_Option != GECAMedBaseDialogImpl.YES_OPTION)
				return false;
		}
		
		if (m_Invoice.getPrintDate() == null && m_Invoice.getDueDate() == null) 
			m_Invoice.setDueDate(false);
			
//		if (m_ApplyRulesOnSave) TODO: m_Invoice.getActs().iterator().next().monetize()
//			{
//			this.applyRules();
//			}
		else m_Acts.setMajoration(m_Invoice.getMajoration());
		
		//=======================================================================
		// Step 1. Store Invoice into database
		//=======================================================================
			
		l_InvoiceInterface = this.getInvoiceInterface();
	
		if (l_InvoiceInterface != null)
			{
			try {
				l_Acts = m_Acts.getActs();
				m_Invoice = l_InvoiceInterface.saveActs (m_Invoice,l_Acts);
				this.setModified(false);
				this.reflectInvoiceState(m_Invoice);
				
				// Make sure property change event fires if old invoice equals invoice itself
				
				if (m_Invoice.equals(l_OldInvoice)) l_OldInvoice = null;
				
				this.firePropertyChange(InvoiceEditorPanel.c_InvoiceSaved, l_OldInvoice, m_Invoice);

				GECAMedLog.user("Billing","SAVE Invoice","Saved Invoice with ID " + m_Invoice.getId());
				
				l_Filler = new String [1];
				l_Filler [0] = m_Invoice.formatInvoiceNumber(false, true);
				
				MainFrame.getInstance().showMessage(Translatrix.getTranslationString("InvoiceEditorPanel.InvoiceSaved",l_Filler));
				}
			catch (Exception p_Exception) 
				{
				m_Logger.log(Level.ERROR,p_Exception.getLocalizedMessage(),p_Exception);
				}
			}
		}
	
	if (showModifiedWarning())
		m_Invoice.setUnmodified();
	
	return true;
	}

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

private void printInvoice ()
	{
	InvoiceInterface	l_InvoiceInterface;
	InvoicePrinter		l_InvoicePrinter;
	String				l_PrintPermission;
	int					l_Action;
	boolean				l_PrintCopy    = false;
	boolean				l_WasPrinted   = false;
	boolean				l_ReloadRequired = false;
	
	if (m_Invoice == null) return;
	
	if (!m_Invoice.isLocked())
		 l_PrintPermission = BillingModule.c_printOpenStem;
	else l_PrintPermission = BillingModule.c_printStem;
	
	if (BillingModule.userHasPermissionForInvoice (m_Invoice, l_PrintPermission,true) == false) return;		
	
	if (this.isModified()) 
		if (!this.saveInvoice())
			return;
	
	removeEmptyActs();

	l_Action = InvoiceWorkflow.previewStateChange (m_Invoice,InvoiceWorkflow.c_PrintAction);
	if ( (l_Action == InvoiceWorkflow.c_DoPrint) 
//			|| (l_Action == InvoiceWorkflow.c_DoPrintOriginal) 
		) {		
		l_PrintCopy = BillingModule.copyRequired (m_Invoice);
		
		l_InvoiceInterface = this.getInvoiceInterface();
		
		if (l_InvoiceInterface != null)
			{
			try {
				List<Invoice> p_Invoices = new ArrayList<Invoice>();
				
				// Check for Splitting First Class CNS Invoice into CNS and Private Invoice
				if (m_InvoiceInterface.isInvoiceSplittable(m_Invoice)) {
					
					String[] vars = new String[] { m_Invoice.getInvoiceNumber()	};
					int n = JOptionPane.showConfirmDialog(
						    this,
						    Translatrix.getTranslationString("InvoiceEditorPanel.SplitFirstClassInvoiceText", vars),
						    Translatrix.getTranslationString("InvoiceEditorPanel.SplitFirstClassInvoiceTitle"),
						    JOptionPane.YES_NO_CANCEL_OPTION);
					
					if (n == JOptionPane.CANCEL_OPTION) {
						return;
					} else if (n == JOptionPane.YES_OPTION) {
						p_Invoices = l_InvoiceInterface.splitFirstClassHospitalizedInvoice(m_Invoice);
						l_ReloadRequired = true;
						GECAMedLog.user("Billing","SPLITTING Invoice","Splitted First Class Hospitalized Invoice with ID " + m_Invoice.getId() 
								+ " into 2 new Invoices ");						
					} else {
						p_Invoices.add(m_Invoice);
					}
				} else {
					p_Invoices.add(m_Invoice);
				}
				
				for (Invoice invoice : p_Invoices) {

					invoice = l_InvoiceInterface.fetchPatientForInvoice (invoice);

					l_InvoicePrinter = new InvoicePrinter();
					l_WasPrinted = l_InvoicePrinter.printInvoice(invoice, l_PrintCopy, true, PrintParameterFetcher.createDefaultPrintParameter(invoice));
					if (l_WasPrinted)
					{
						this.setModifier();
						InvoiceWorkflow.changeInvoiceState (invoice,InvoiceWorkflow.c_PrintAction);
						//					if (!m_Invoice.alreadyPrinted()) m_Invoice.setPrintDate(new Date ());
						invoice = l_InvoiceInterface.saveInvoice (invoice);

						this.reflectInvoiceState(invoice);
						this.firePropertyChange (InvoiceEditorPanel.c_InvoicePrinted,null,invoice);
						GECAMedLog.user("Billing","PRINT Invoice","Printed Invoice with ID " + invoice.getId());
					}
					l_InvoicePrinter.close();
				}
				if (l_ReloadRequired) {
					BillingModule.getInstance().reloadInvoices();
				}
			}
			catch (Exception p_Exception) 
				{
				m_Logger.log(Level.ERROR,p_Exception.getLocalizedMessage(),p_Exception);
				}
			}
		}
	}

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

	private boolean splitInvoice() {
		InvoiceInterface l_InvoiceInterface;

		if (m_Invoice == null)
			return false;

		if (m_Invoice.isLocked())
			return false;

		if (this.isModified())
			if (!this.saveInvoice())
				return false;

		removeEmptyActs();

		l_InvoiceInterface = this.getInvoiceInterface();

		if (l_InvoiceInterface != null) {
			try {
				// Check for Splitting First Class CNS Invoice into CNS and
				// Private Invoice
				if (m_InvoiceInterface.isInvoiceSplittable(m_Invoice)) {

					String[] vars = new String[] { m_Invoice.getInvoiceNumber() };
					int n = JOptionPane.showConfirmDialog(this, Translatrix.getTranslationString("InvoiceEditorPanel.SplitFirstClassInvoiceText", vars), Translatrix.getTranslationString("InvoiceEditorPanel.SplitFirstClassInvoiceTitle"), JOptionPane.YES_NO_CANCEL_OPTION);

					if (n == JOptionPane.CANCEL_OPTION || n == JOptionPane.NO_OPTION) {
						return false;
					} else if (n == JOptionPane.YES_OPTION) {
						l_InvoiceInterface.splitFirstClassHospitalizedInvoice(m_Invoice);
						GECAMedLog.user("Billing", "SPLITTING Invoice", "Splitted First Class Hospitalized Invoice with ID " + m_Invoice.getId() + " into 2 new Invoices ");
					}
				} else {
					return false;
				}
			} catch (Exception p_Exception) {
				m_Logger.log(Level.ERROR, p_Exception.getLocalizedMessage(), p_Exception);
			}
		}
		return true;
	}

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

private void settleInvoice ()
	{
	if (m_Invoice == null) return;

	if (m_Invoice.getBalance() == 0f)
		{
		MainFrame.getInstance().showMessage(Translatrix.getTranslationString("BillingModule.InvoiceFullySettled"));
		return;
		}
	
	if (this.isModified()) this.saveInvoice();
	
	if (BillingModule.getInstance().splitInvoice(m_Invoice)) {
		BillingModule.getInstance().reloadInvoices();
		return;
	}

	if (BillingModule.getInstance().settleInvoice(m_Invoice, new Date(), false) != null)
		{
		this.reflectInvoiceState(m_Invoice);
		this.firePropertyChange(InvoiceEditorPanel.c_InvoicePaid,null,m_Invoice);
		}
	}

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

private void disableAllButtons ()
	{
	m_AddActButton.setEnabled(false);
	m_RemoveActButton.setEnabled(false);
	m_BrowseActButton.setEnabled(false);
	m_AddHospPeriodButton.setEnabled(false);
	m_OpenTemplateButton.setEnabled(false);
	m_SaveTemplateButton.setEnabled(false);
	m_ApplyRulesButton.setEnabled(false);
	m_SaveInvoiceButton.setEnabled(false);
	m_PrintInvoiceButton.setEnabled(false);
	m_SplitInvoiceButton.setEnabled(false);
	m_SettleInvoiceButton.setEnabled(false);
	m_CancelInvoiceButton.setEnabled(false);	
	}

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

private void reflectInvoiceState (Invoice p_Invoice)
	{
	int			l_InvoiceState;
	boolean[]	l_States;
	
	boolean		l_HasEditPermission;
	boolean		l_HasPrintPermission;
	boolean		l_HasSettlePermission;
	boolean		l_HasCancelPermission;
	boolean		l_InvoiceLocked;
	
//	System.out.println("Global:  " + BillingModule.getInstance().getCurrentInvoice());
//	System.out.println("REFLECT: " + p_Invoice);
	
	if (p_Invoice == null) return;
	
	l_InvoiceState = p_Invoice.getState().intValue();
	
	if (m_ExtendedMode)
		 l_States = m_ExtendedButtonStates;
	else l_States = m_ButtonStateTable[l_InvoiceState];

	l_HasEditPermission = BillingModule.userHasPermissionForInvoice(p_Invoice, BillingModule.c_editStem,false);
		
	m_Acts.setEditable(l_HasEditPermission);
	
	m_AddActButton.setEnabled			((l_HasEditPermission)?l_States[0]:false);
	m_RemoveActButton.setEnabled		((l_HasEditPermission)?l_States[1]:false);
	m_BrowseActButton.setEnabled		((l_HasEditPermission)?l_States[2]:false);
	m_AddHospPeriodButton.setEnabled	((l_HasEditPermission)?l_States[0]:false);
	m_OpenTemplateButton.setEnabled		((l_HasEditPermission)?l_States[3]:false);
	m_SaveTemplateButton.setEnabled		((l_HasEditPermission && doesValidActExist())
															  ?l_States[4]:false);
	m_ApplyRulesButton.setEnabled		((l_HasEditPermission)?l_States[5]:false);
	m_SaveInvoiceButton.setEnabled		((l_HasEditPermission)?l_States[6]:false);
	m_SplitInvoiceButton.setEnabled		((l_HasEditPermission)?l_States[6]:false);
		
	l_HasPrintPermission = BillingModule.userHasPermissionForInvoice(p_Invoice, BillingModule.c_printStem,false);
	
	m_PrintInvoiceButton.setEnabled((l_HasPrintPermission)?l_States[7]:false);
	
	l_HasSettlePermission = BillingModule.userHasPermissionForInvoice(p_Invoice, BillingModule.c_settleStem,false);
	
	m_SettleInvoiceButton.setEnabled((l_HasSettlePermission)?l_States[8]:false);
	
	l_HasCancelPermission = BillingModule.userHasPermissionForInvoice(p_Invoice, BillingModule.c_cancelStem,false);
	
	m_CancelInvoiceButton.setEnabled((l_HasCancelPermission)?l_States[9]:false);
	
	l_InvoiceLocked = (	(p_Invoice.isLocked() || (l_HasEditPermission == false)) && (m_ExtendedMode == false) );
	
	if (l_InvoiceLocked)	
		{
		if (l_HasEditPermission)
			{
			switch (l_InvoiceState)
				{
				case InvoiceWorkflow.c_PrintedState  :
				case InvoiceWorkflow.c_RemindedState :
				
					m_PrintInvoiceButton.setText (Translatrix.getTranslationString(c_PrintCopyButton));
					m_PrintInvoiceButton.setToolTipText (Translatrix.getTranslationString(c_PrintCopyTip));
					break;
				
				case InvoiceWorkflow.c_PaidState :
			
					m_PrintInvoiceButton.setText (Translatrix.getTranslationString(c_PrintSettledButton));
					m_PrintInvoiceButton.setToolTipText (Translatrix.getTranslationString(c_PrintSettledTip));
					break;
					
				default: 
					
					m_PrintInvoiceButton.setText (Translatrix.getTranslationString(c_PrintInvoiceButton));
					m_PrintInvoiceButton.setToolTipText (Translatrix.getTranslationString(c_PrintInvoiceTip));
					break;
				}
			}
		
		m_Acts.setEditable(false);
		BillingModule.getInstance().getInvoiceProperties().setEnabled(false);
		BillingModule.getInstance().getAccidentProperties().setEnabled(false);
		BillingModule.getInstance().getHospitalisationProperties().setEnabled(false);
		}
	else
		{
		m_PrintInvoiceButton.setText (Translatrix.getTranslationString(c_PrintInvoiceButton));
		m_PrintInvoiceButton.setToolTipText (Translatrix.getTranslationString(c_PrintInvoiceTip));
		BillingModule.getInstance().getInvoiceProperties().setEnabled(m_Showing);
		BillingModule.getInstance().getAccidentProperties().setEnabled(m_Showing);
		BillingModule.getInstance().getHospitalisationProperties().setEnabled(m_Showing);
		}
	}

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

/**
 * @return <code>true</code>, if you should proceed as normal, <br>
 * 		<code>false</code> if you should jump to the InvoiceEditorPanel. 
 */
private boolean doUnsavedChangesDialog ()
	{
//	String 		l_UnsavedChangesMessage;
	String[]	l_Filler;
	int			l_UserChoice;
//	boolean		l_IsModified;

	if (isModified() && !m_SavingCanceled)
		{
		l_Filler = new String [1];
		l_Filler[0] = m_Invoice.formatInvoiceNumber(false, true);
		
//		l_UserChoice = BillingModule.getUserConfirmation (c_UnsavedChangesTitle, c_UnsavedChangesMessage, l_Filler);
		l_UserChoice = GECAMedBaseDialogImpl.showMessageDialog(
				MainFrame.getInstance(), 
				Translatrix.getTranslationString(c_UnsavedChangesTitle), 
				Translatrix.getTranslationString(c_UnsavedChangesMessage, l_Filler), 
				GECAMedBaseDialog.YES_NO_CANCEL_BUTTON_MODE);
		
		if (l_UserChoice == GECAMedBaseDialog.YES_OPTION)
			{
			if (!this.saveInvoice())
				{
				/* the tab needs to be setModified(false) before showing the tab, 
				 * because otherwise the dialog, to ask whether this invoice shall 
				 * be saved, will pop up twice.
				 */
				m_SavingCanceled = true;
//				l_IsModified = isModified();
				
				BillingModule.getInstance().showTab(BillingModule.c_EditorTab);
//				setModified(l_IsModified);
				m_SavingCanceled = false;
				}
			}
		else if (	l_UserChoice == GECAMedBaseDialog.CANCEL_OPTION
				|| 	l_UserChoice == GECAMedBaseDialog.CLOSED_OPTION)
			{
			return false;
			}
		
//		m_Acts.stopEditing();
		setModified(false);
		}
	return true;
	}
//---------------------------------------------------------------------------
//***************************************************************************
//* Class Body                                      						*
//***************************************************************************
//---------------------------------------------------------------------------

public void reset ()
	{
	m_Invoice = null;
	m_Acts.removeAllActs();
	this.disableAllButtons();
	this.setInvoice (null);
	this.setModified(false);
	}

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

public void setModified (boolean p_Modified)
	{
	if (p_Modified) this.setModifier();

	super.setModified(p_Modified);
	BillingModule.getInstance().setModified(p_Modified);
	}

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

public Invoice getEditedInvoice ()
	{
	return m_Invoice;
	}

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

public void setInvoice (Invoice p_Invoice)	{
	
//	System.out.println("\nGlobal : " + BillingModule.getInstance().getCurrentInvoice());
//	System.out.println("SET:     " + p_Invoice);
	
	if (m_Invoice != null && !m_Invoice.equals(p_Invoice) 
		&& isModified()
		&& !this.doUnsavedChangesDialog()) {
		/* The cancel button was pressed:
		 * Set the old invoice as global invoice 
		 * and show the invoice editor tab.
		 */
		BillingModule bm = BillingModule.getInstance();
		bm.setInvoice(m_Invoice);
		bm.showTab(BillingModule.c_EditorTab);
		return;
	}
	
	// old = new invoice
	if (m_Invoice != null && m_Invoice.equals(p_Invoice) && isModified())
		return;
	
	//========================================================================
	//= Case 1: No Invoice specified. Clear Act List and Reset Panel
	//========================================================================
	if (p_Invoice == null)
		{
		m_Acts.removeAllActs();
		this.disableAllButtons();
		this.setModified(false);
		m_Invoice = null;
		return;
		}
	
	//========================================================================
	//= Case 2: Specified Invoice differs from current one. In case specified
	//= is in state NEW, then we'll have to clear Act List, otherwise we have
	//= to set Act list to those specified by new invoice. No matter what state
	//= the new invoice is in, the panel has to reflect its state, i.e. enable
	//= or disable buttons accordingly.
	//========================================================================
	if (	(p_Invoice.equals(m_Invoice) == false) || (p_Invoice.getAmount() != m_Invoice.getAmount()))	{
		m_Invoice = p_Invoice;
		
		if ((Boolean)BillingModule.getSetting(BillingAdminSettings.c_HospitalisationSetting)){
			m_Invoice.setActs( this.verifyActs (m_Invoice.getActs()));
		}	
		
		if ((m_Invoice.getActs() == null) || (m_Invoice.getActs().size() == 0)) {
			m_Acts.removeAllActs();
		} else {
			m_Acts.setActs (m_Invoice.getActs());
			m_Acts.packColumns();
		}
			
		m_Acts.setMajoration(m_Invoice.getMajoration());
		
		// set the invoice in the memo tab
		BillingModule.getInstance().getMemoPanel().setInvoice(m_Invoice);
	}
	
	reflectInvoiceState(p_Invoice);
	
	if (showModifiedWarning()) {
		m_Invoice.setUnmodified();		
	}
}

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

public void actionPerformed(ActionEvent p_ActionEvent) 
	{
	if (m_Invoice == null) return;
	
	//=======================================================================
	// Add Act Button 
	//=======================================================================
	
	if (p_ActionEvent.getSource() == m_AddActButton /* && !m_Acts.isEditing() */)
		{
		Act	l_Act = new Act ();
		l_Act.setChanges(Act.CHANGED_USER);
		if (m_Acts.isEditable())
			m_Acts.stopEditing();
		
		this.addAct (l_Act, true, false);
		}

	//=======================================================================
	// Remove Act Button 
	//=======================================================================

	else if (p_ActionEvent.getSource() == m_RemoveActButton && !m_Acts.isEditing())
		{
		this.removeSelectedActs();
		}

	//=======================================================================
	// Save Template Button 
	//=======================================================================

	else if (p_ActionEvent.getSource() == m_SaveTemplateButton)
		{
		this.stopEditing();
		this.saveAsInvoiceTemplate();
		}

	//=======================================================================
	// Open Template Button 
	//=======================================================================

	else if (p_ActionEvent.getSource() == m_OpenTemplateButton)
		{
		this.stopEditing();
		this.createInvoiceFromTemplate();
		}

	//=======================================================================
	// Browse for Act Button 
	//=======================================================================

	else if (p_ActionEvent.getSource() == m_BrowseActButton)
		{
		Act		l_Act;
		Rate[]	l_ChosenRates;
		
		m_RateSearch.pack();
		m_RateSearch.setVisible(true);
		l_ChosenRates = m_RateSearch.getChosenRates();
		
		if (l_ChosenRates != null)
			{
			for (Rate l_ChosenRate : l_ChosenRates)
				{
				this.stopEditing();
				l_Act = new Act ();
//				l_ChosenRate.initializeAct(l_Act);
				try {
					l_Act = getNomenclatureInterface().initializeAct(l_ChosenRate.getCode(), l_Act);			
				} catch (Exception e) {
					m_Logger.error("Error initializing Act", e);
				}
				this.addAct(l_Act,false, false);
				}
			}		
		}

	//=======================================================================
	// Add Hospitalisation Period Button 
	//=======================================================================
	
	else if (p_ActionEvent.getSource() == m_AddHospPeriodButton)
		{

		stopEditing();
		if (m_HospitalisationDialog == null)
			m_HospitalisationDialog = new HospitalisationPeriodDialog();
		
		
		final Vector<Vector<Object>> data = m_HospitalisationDialog.showDialog(m_Invoice.getInvoiceDate());
		
		if (data != null) {
			m_Logger.info("Adding Acts: " + data.size());
			new Thread() {
				Date 	date;
				Rate 	rate;
				Integer	docID;
				Date	time;
				Act 	act;
				
				public void run() {
					MainFrame.getInstance().setWaitCursor(true);
					for (Vector<Object> row : data)
					{
						date 	= (Date) row.get(0);
						rate 	= (Rate) row.get(1);
						act 	= new Act();
						act.setShowTime(false);
						
						// set performed date
						act.setPerformedDate(date);
						
						try {
							// set doc ID
							if (rate.getNonAssignable("PHYSICIANID") != null) {
								docID = (Integer) rate.getNonAssignable("PHYSICIANID");
								act.setPhysicianId(docID);
							}
							
							// set performed Time
							if (rate.getNonAssignable("TIME") != null) {
								time = (Date) rate.getNonAssignable("TIME");
								act.setPerformedTime(time);
							}
						} catch (Exception e) {
							e.printStackTrace();
						}
						
						// initialize keyvalue etc.. from act data and rate.
						try {
							act = getNomenclatureInterface().initializeAct(rate.getCode(), act);			
						} catch (Exception e) {
							m_Logger.error("Error initializing Act", e);
						}
						
						addAct(act, false, true);
						
					}
					
					HospitalisationPanel.changeToHospitalisation();
					removeEmptyActs();
					MainFrame.getInstance().setWaitCursor(false);
				}
			}.start();
			
			}
		
		}

	//=======================================================================
	// Apply Rules Button 
	//=======================================================================

	else if (p_ActionEvent.getSource() == m_ApplyRulesButton)
		{
		this.stopEditing();
		this.applyRules();
		}

	//=======================================================================
	// Save Invoice Button 
	//=======================================================================

	else if (p_ActionEvent.getSource() == m_SaveInvoiceButton)
		{
		this.stopEditing();
		this.saveInvoice();
		}

	//=======================================================================
	// Print Invoice Button 
	//=======================================================================

	else if (p_ActionEvent.getSource() == m_PrintInvoiceButton)
		{
		this.stopEditing();
		this.printInvoice();
		}
	
	//=======================================================================
	// Split Invoice Button 
	//=======================================================================

	else if (p_ActionEvent.getSource() == m_SplitInvoiceButton)
		{
		this.stopEditing();
		if (this.splitInvoice()) {
			BillingModule.getInstance().reloadInvoices();
		}
		}
	
	//=======================================================================
	// Settle Invoice Button 
	//=======================================================================

	else if (p_ActionEvent.getSource() == m_SettleInvoiceButton)
		{
		this.stopEditing();
		this.settleInvoice();
		}
	}

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

@Override
public void preparetoShowup() 
	{
	m_Showing	= true;
	m_AutomaticallyAddActs = (Boolean)BillingModule.getUserSetting(BillingUserSettings.c_AutomaticallyAddActsSetting);
	
//	System.out.println("\nGlobal: " + BillingModule.getInstance().getCurrentInvoice());
//	System.out.println("Show:   " + m_Invoice);
	
	// jh this is no longer needed as current invoice is already set to panel.
//	if (!m_SavingCanceled && !isModified()) {
//		this.setInvoice(BillingModule.getInstance().getCurrentInvoice());		
//	}
	
	boolean l_HasEditPermission = BillingModule.userHasPermissionForInvoice(m_Invoice, BillingModule.c_editStem,false);
	boolean l_InvoiceLocked = (	(m_Invoice.isLocked() || (l_HasEditPermission == false)) && (m_ExtendedMode == false) );

	BillingModule.getInstance().getInvoiceProperties().setEnabled(!l_InvoiceLocked);
	BillingModule.getInstance().getAccidentProperties().setEnabled(!l_InvoiceLocked);
	BillingModule.getInstance().getHospitalisationProperties().setEnabled(!l_InvoiceLocked);
	}

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

@Override
public void preparetoHide ()
	{
//	this.doUnsavedChangesDialog();
//	BillingModule.updateCurrentInvoice(m_Invoice);
//	this.firePropertyChange(InvoiceEditorPanel.c_InvoiceUpdated,null,m_Invoice);
	
	m_Showing	= false;
	
	BillingModule.getInstance().getInvoiceProperties().setEnabled(false);
	BillingModule.getInstance().getAccidentProperties().setEnabled(false);
	BillingModule.getInstance().getHospitalisationProperties().setEnabled(false);
	}

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

public void tableChanged (TableModelEvent p_TableEvent) 
	{
	Act			l_Act;
	
	if (m_Invoice == null) return;

	if (p_TableEvent.getType() == TableModelEvent.UPDATE)
		{
		if (       (p_TableEvent.getColumn()  == ActListModel.c_CodeColumn)
				&& m_LastEditorKey == KeyEvent.VK_ENTER
			    && m_AutomaticallyAddActs )
			{
			setLastEditorKey(-1);
			l_Act = m_Acts.getSelectedAct();
			if (l_Act != null && (l_Act.getCode() != null) && (l_Act.getCode().length() > 0))
				{
				Act n_Act = new Act();
				n_Act.setChanges(Act.CHANGED_USER);
				this.addAct(n_Act, false, false);
				
				SwingUtilities.invokeLater(new Runnable() 
					{
					public void run() 
						{
						m_Acts.focusOnSelectedAct();
						}
					});
				}
			}

		if (m_Invoice.getState().intValue() < InvoiceWorkflow.c_PrintedState)
			{
			m_Invoice.setActs(m_Acts.getActs());
			this.firePropertyChange(InvoiceEditorPanel.c_InvoiceModified,null,m_Invoice);	
			setModified(true);
			}
		
		}
	else if (p_TableEvent.getType() == TableModelEvent.DELETE)
		{
		m_Acts.deselectAll();
		}
	
	// enable or disable the save template button ...
	m_SaveTemplateButton.setEnabled(doesValidActExist());
	}

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

private boolean doesValidActExist () 
	{
	Set<Act>	l_Acts			= m_Invoice.getActs();
	
	if (l_Acts == null) return false;
	
	for (Act act : l_Acts)
		if (act != null && !"".equals(act.getCode().trim()))
			return true;
	
	return false;
	}

public void propertyChange (PropertyChangeEvent p_ChangeEvent) {
	if (m_Invoice == null) return;
	
	if (p_ChangeEvent.getSource() == BillingModule.getInstance().getHospitalisationProperties()) {
		if (	(p_ChangeEvent.getPropertyName() == HospitalisationPanel.c_FirstClassRequired)
			 || (p_ChangeEvent.getPropertyName() == HospitalisationPanel.c_HospitalisationClass)) {
			if (m_Showing) {
				setModified(true);				
			}
		}
	} else if (p_ChangeEvent.getSource() == BillingModule.getInstance().getAccidentProperties()) {
		if (p_ChangeEvent.getPropertyName() == AccidentPropertiesPanel.c_IsAccident) {
			if (m_Showing) {
				setModified(true);
			}
		}
	} else if (InvoicePropertiesPanel.c_HealthInsurance.equals(p_ChangeEvent.getPropertyName())) {
		Insurance newInsurance = (Insurance) p_ChangeEvent.getNewValue();
		
		if (newInsurance != null && !newInsurance.equals(m_Invoice.getHealthInsurance())) {
			m_Invoice.setHealthInsurance(newInsurance);
			if(!newInsurance.getMajoration().equals(m_Invoice.getMajoration())) {
				if (m_Showing) {
					setModified(true);					
				}
				m_Invoice.setAllMajorations(newInsurance.getMajoration());
				m_Invoice.monetize();
			}
			
			if (isShowing()) {
				this.firePropertyChange(InvoiceEditorPanel.c_InvoiceModified,null,m_Invoice);				
			}
		}
	} else if (InvoicePropertiesPanel.c_ThirdPartyPayer.equals(p_ChangeEvent.getPropertyName()) ||
				InvoicePropertiesPanel.c_InvoiceDate.equals(p_ChangeEvent.getPropertyName()) ||
				InvoicePropertiesPanel.c_Physician.equals(p_ChangeEvent.getPropertyName())) {
		if (m_Showing) {
			setModified(true);
		}
	}
}

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

public void relocalize() 
	{
	if (m_AddActButton != null)
		{
		m_AddActButton.setText		(Translatrix.getTranslationString(c_AddActButton));
		m_AddActButton.setToolTipText (Translatrix.getTranslationString(c_AddActTip));
		}
	
	if (m_RemoveActButton != null)
		{
		m_RemoveActButton.setText			(Translatrix.getTranslationString(c_RemoveActButton));
		m_RemoveActButton.setToolTipText 	(Translatrix.getTranslationString(c_RemoveActTip));
		}
		
	if (m_BrowseActButton != null)
		{
		m_BrowseActButton.setText			(Translatrix.getTranslationString(c_BrowseActButton));
		m_BrowseActButton.setToolTipText 	(Translatrix.getTranslationString(c_BrowseActTip));
		}
	
	if (m_AddHospPeriodButton != null)
		{
		m_AddHospPeriodButton.setText		(Translatrix.getTranslationString(c_HospPeriodButton));
		m_AddHospPeriodButton.setToolTipText(Translatrix.getTranslationString(c_HospPeriodTip));
		}
	
	if (m_OpenTemplateButton != null)
		{
		m_OpenTemplateButton.setText			(Translatrix.getTranslationString(c_OpenTemplateButton));
		m_OpenTemplateButton.setToolTipText 	(Translatrix.getTranslationString(c_OpenTemplateTip));
		}
	
	if (m_SaveTemplateButton != null)
		{
		m_SaveTemplateButton.setText			(Translatrix.getTranslationString(c_SaveTemplateButton));
		m_SaveTemplateButton.setToolTipText 	(Translatrix.getTranslationString(c_SaveTemplateTip));
		}
	
	if (m_ApplyRulesButton != null)
		{
		m_ApplyRulesButton.setText			(Translatrix.getTranslationString(c_ApplyRulesButton));
		m_ApplyRulesButton.setToolTipText 	(Translatrix.getTranslationString(c_ApplyRulesTip));
		}
	
	if (m_SaveInvoiceButton != null)
		{
		m_SaveInvoiceButton.setText			(Translatrix.getTranslationString(c_SaveInvoiceButton));
		m_SaveInvoiceButton.setToolTipText 	(Translatrix.getTranslationString(c_SaveInvoiceTip));
		}
	
	if (m_PrintInvoiceButton != null)
		{
		m_PrintInvoiceButton.setText			(Translatrix.getTranslationString(c_PrintInvoiceButton));
		m_PrintInvoiceButton.setToolTipText 	(Translatrix.getTranslationString(c_PrintInvoiceTip));
		}
	
	if (m_SplitInvoiceButton != null)
	{
		m_SplitInvoiceButton.setText			(Translatrix.getTranslationString("InvoiceEditorPanel.SplitFirstClassInvoice"));
		m_SplitInvoiceButton.setToolTipText 	(Translatrix.getTranslationString("InvoiceEditorPanel.SplitFirstClassInvoiceTitle"));
	}
	
	if (m_SettleInvoiceButton != null)
		{
		m_SettleInvoiceButton.setText			(Translatrix.getTranslationString(c_SettleInvoiceButton));
		m_SettleInvoiceButton.setToolTipText 	(Translatrix.getTranslationString(c_SettleInvoiceTip));
		}
	
	if (m_CancelInvoiceButton != null)
		{
		m_CancelInvoiceButton.setText			(Translatrix.getTranslationString(c_CancelInvoiceButton));
		m_CancelInvoiceButton.setToolTipText 	(Translatrix.getTranslationString(c_CancelInvoiceTip));
		}
	}

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

public void userModeChanged (boolean p_SuperUserMode) 
	{
	m_ExtendedMode = p_SuperUserMode;
	this.reflectInvoiceState (m_Invoice);
	}

//---------------------------------------------------------------------------
/**
 * checks whether the specified invoice change event affects the invoice
 * currently shown in this panel.
 * @param p_Event specifies the invoice change event to check.
 * @return <code>true</code> if specified change event affects invoice
 * currently shown in this panel, <code>false</code> otherwise.
 */
//---------------------------------------------------------------------------

private boolean affectsEditingInvoice (InvoiceChangeEvent p_Event)
	{
	Invoice l_Invoice;
	boolean	l_Affected = false;
	
	if (p_Event.isMultiple())
		{
		l_Affected = (m_Invoice != null) && p_Event.getInvoiceIDs().contains(m_Invoice.getId());
		}
	else
		{
		l_Invoice = p_Event.getInvoice();
		l_Affected = ((l_Invoice != null) && (l_Invoice.equals(m_Invoice)));
		}
	
	return l_Affected;
	}

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

public Invoice getInvoiceFromEvent (InvoiceChangeEvent p_Event)
	{
	Invoice l_Invoice = null;
	
	if (p_Event.isMultiple())
		 l_Invoice = BillingModule.getInstance().getInvoiceById(m_Invoice.getId());
	else l_Invoice = p_Event.getInvoice();

	return l_Invoice;
	}

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

public void invoiceChanged (InvoiceChangeEvent p_Event) 
	{
	Invoice 	l_Invoice = null;
	String[]	l_Filler;
	int			l_UserChoice;
		
	// We don't consider events that originated here.
	if (p_Event.getSource() instanceof InvoiceEditorPanel) return;
	
	switch (p_Event.getType())
		{
		case InvoiceChangeEvent.c_InvoiceStatusChanged:
		case InvoiceChangeEvent.c_InvoiceUpdated:
		
			if (this.affectsEditingInvoice (p_Event))
				{
				if (isModified() && p_Event.isRemote()) {
					// If currently shown invoice was modified, we have to ask
					// the user to confirm whether he wishes to cancel his or her
					// changes and to reload the modified version of the invoice
				
					l_UserChoice = BillingModule.getUserConfirmation (c_InvoiceUpdatedTitle, c_InvoiceUpdatedMessage, null);
					if (l_UserChoice == JOptionPane.YES_OPTION)
						{
						setModified (false);
						l_Invoice = this.getInvoiceFromEvent(p_Event);
						this.setInvoice (l_Invoice);
						}
				} else if (isModified())
					{
					// just set the invoice.
					setModified (false);
					l_Invoice = this.getInvoiceFromEvent(p_Event);
					this.setInvoice (l_Invoice);
					}
				else if (isShowing())
					{
					// If invoice was modified and we're currently showing
					// affected invoice, then we'll update it immediately,
					// telling the user that it has been updated.
					
					l_Invoice = this.getInvoiceFromEvent(p_Event);
				
					l_Filler = new String [1];
					l_Filler [0] = l_Invoice.formatInvoiceNumber (false, true);
				
					this.setInvoice (l_Invoice);
					MainFrame.getInstance().showMessage (Translatrix.getTranslationString (c_InvoiceUpdated,l_Filler));
					}
				}
			break;
			
		case InvoiceChangeEvent.c_InvoiceDeleted:
			
			if (this.affectsEditingInvoice (p_Event))
				{
				l_UserChoice = BillingModule.getUserConfirmation (c_InvoiceDeletedTitle, c_InvoiceDeletedMessage, null);
				if (l_UserChoice == JOptionPane.YES_OPTION)
					{
					this.reset();
					}
				else
					{
					m_Invoice.setId (null);
					m_Invoice.setState (InvoiceWorkflow.c_NewState);
					m_Invoice.setOldState (InvoiceWorkflow.c_NewState);
					this.reflectInvoiceState(m_Invoice);
					}
				}
			break;		
		}
	}

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

public void hospitalisationClassChanged(Invoice p_Invoice)
{
//	if (m_Invoice != null)
//		m_Invoice.setHospitalisationClass(p_Invoice.getHospitalisationClass());
	
}

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

public void removeEmptyActs ()
{
	List<Act> 	l_ToRemove 	= new LinkedList<Act>();
	Set<Act> 	l_Acts 		= m_Acts.getActs();
	String 		l_Code;
	
	for (Act l_Act : l_Acts)
	{
		l_Code = l_Act.getCode();
		if (l_Code == null || "".equals(l_Code.trim()))
			l_ToRemove.add(l_Act);
	}
	
	for (Act act : l_ToRemove)
		l_Acts.remove(act);
	
	m_Acts.setActs(l_Acts);
}


private boolean showModifiedWarning ()
{
	int l_WarnRulesOption = (Integer)BillingModule.getUserSetting(BillingUserSettings.c_WarnIfRulesNotApplied);
	
	
	return l_WarnRulesOption == BillingUserSettingsPlugin.c_WarnIfRulesNotAppliedAlways
			|| l_WarnRulesOption == BillingUserSettingsPlugin.c_WarnIfRulesNotAppliedUCM;
}


/**
 * @param p_CodeEditorLeftWithEnter the m_CodeEditorLeftWithEnter to set
 */
public void setLastEditorKey (int p_KeyCode)
{
	m_LastEditorKey = p_KeyCode;
}


public int getLastEditorKey ()
{
	return m_LastEditorKey;
}

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