/*******************************************************************************
 * 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.KeyListener;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Invoice;
import lu.tudor.santec.gecamed.billing.ejb.session.beans.InvoiceBean;
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.event.invoice.InvoiceChangeEvent;
import lu.tudor.santec.gecamed.billing.gui.event.invoice.InvoiceEventDispatcher;
import lu.tudor.santec.gecamed.billing.gui.event.invoice.InvoiceEventSource;
import lu.tudor.santec.gecamed.billing.gui.event.invoice.InvoiceListener;
import lu.tudor.santec.gecamed.billing.gui.event.search.SearchEventSource;
import lu.tudor.santec.gecamed.billing.gui.event.search.SearchModeEvent;
import lu.tudor.santec.gecamed.billing.gui.event.search.SearchModeEventDispatcher;
import lu.tudor.santec.gecamed.billing.gui.event.search.SearchModeListener;
import lu.tudor.santec.gecamed.billing.gui.event.usermode.UserModeListener;
import lu.tudor.santec.gecamed.billing.utils.BillingAdminSettings;
import lu.tudor.santec.gecamed.billing.utils.InvoiceWorkflow;
import lu.tudor.santec.gecamed.core.gui.GECAMedColors;
import lu.tudor.santec.gecamed.core.gui.GECAMedLog;
import lu.tudor.santec.gecamed.core.gui.GECAMedTab;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.PhysicianListener;
import lu.tudor.santec.gecamed.core.gui.utils.SwingWorker;
import lu.tudor.santec.gecamed.core.gui.widgets.searchtableheader.SearchResetAction;
import lu.tudor.santec.gecamed.core.gui.widgets.searchtableheader.SearchableTable;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.core.utils.querybuilder.HibernateCondition;
import lu.tudor.santec.gecamed.core.utils.querybuilder.HibernateOperator;
import lu.tudor.santec.gecamed.core.utils.querybuilder.WhereClause;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient;
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;

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

public class InvoiceListingPanel extends GECAMedTab implements SearchableTable,
															   InvoiceEventSource,
															   SearchEventSource,
															   ListSelectionListener,
															   ActionListener,
															   InvoiceListener,
															   UserModeListener,
															   PhysicianListener,
															   Relocalizable 
	{
	private static final long serialVersionUID = 1L;

	private	InvoiceListBox		m_InvoiceListing	= null;
	private Patient				m_Patient			= null;
	private InvoiceInterface	m_InvoiceInterface	= null;
	
	private Timer				m_MessageDelay;
	private SwingWorker  		m_SearchWorker;
	private boolean				m_SearchMode;
	private boolean				m_ExtendedMode;
	private boolean 			m_FilterByPhysician;

	private InvoiceEventDispatcher		m_InvoiceListeners;
	private SearchModeEventDispatcher 	m_SearchModeListeners;	
	
	private static Logger m_Logger = Logger.getLogger ("gecamed.billing.gui.InvoiceListingPanel");
		
//***************************************************************************
//* Class Constants                                                         *
//***************************************************************************

	private final static int	c_Delay  = 500;
	
	private final static String c_Columns= "fill:pref:grow";		
	private final static String c_Rows=    "fill:pref:grow";

//***************************************************************************
//* Constructor(s)                                                          *
//***************************************************************************
//---------------------------------------------------------------------------

public InvoiceListingPanel ()
	{
	CellConstraints	l_Constraints;
	FormLayout		l_Layout;
	
	m_SearchMode  	= false;
	m_ExtendedMode  = false;
	m_MessageDelay = new Timer (c_Delay,this);
	m_MessageDelay.stop ();
	
	l_Constraints  	= new CellConstraints();
	l_Layout		= new FormLayout(c_Columns, c_Rows);
	
  	this.setLayout (l_Layout); 
 	this.setOpaque(false);
 	
 	m_InvoiceListing = new InvoiceListBox ();
  	m_InvoiceListing.getViewport().setOpaque(false);
  	m_InvoiceListing.setBackground(GECAMedColors.c_ScrollPaneBackground);
  	m_InvoiceListing.addPropertyChangeListener (this);
  	m_InvoiceListing.addListSelectionListener(this);
   	this.add (m_InvoiceListing,l_Constraints.xywh(1, 1, 1, 1));
	
	m_InvoiceListeners 		= new InvoiceEventDispatcher ();
	m_SearchModeListeners 	= new SearchModeEventDispatcher ();
	
	BillingModule.getInstance().addInvoiceListener(this);

	KeyStroke l_Stroke = KeyStroke.getKeyStroke("ESCAPE");
	
	this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(l_Stroke,"cancelSearch");
	this.getActionMap().put("cancelSearch", new SearchResetAction (this,"cancelSearch"));	

	BillingModule.getInstance().addUserModeListener(this);
	
	m_FilterByPhysician = getDefaultFilterByPhysician();
	}

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

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

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


	return m_InvoiceInterface;
	}

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

private Invoice saveStateChange (Invoice p_Invoice)
	{
	InvoiceInterface 	l_InvoiceInterface = null;
	String[]			l_Filler;
	
	if (p_Invoice == null) return null;
	
	l_InvoiceInterface = this.getInvoiceInterface();
	
	if (l_InvoiceInterface != null)
		{
		try	{
			p_Invoice = l_InvoiceInterface.saveInvoice(p_Invoice);
		
			GECAMedLog.user("Billing","CHANGE State","Set State of Invoice with ID " + p_Invoice.getId() + " to " + InvoiceWorkflow.getInvoiceStateName(p_Invoice));
				
			l_Filler = new String [1];
			l_Filler [0] = p_Invoice.formatInvoiceNumber(false, true);
				
			MainFrame.getInstance().showMessage(Translatrix.getTranslationString("InvoiceListingPanel.StateChanged",l_Filler));
			}
		catch (Exception p_Exception) 
			{
			m_Logger.log(Level.ERROR,p_Exception.getLocalizedMessage(),p_Exception);
			}
		}
	
	return p_Invoice;
	}

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

private void resetSearchCriteria ()
	{
	m_SearchMode = false;
	m_InvoiceListing.resetSearchCriteria();
	}

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

private void updateListing ()
	{
	InvoiceInterface		l_InvoiceInterface 	= null;
	Collection <Invoice>	l_Invoices			= null;
	
	if (m_Patient == null) return;
	
	if (!m_Patient.isPersistent())
		{
		this.reset ();
		return;
		}
		
	l_InvoiceInterface = getInvoiceInterface ();
	
	if (l_InvoiceInterface == null) return;

	try {
//		if ((Boolean)BillingModule.getSetting(BillingAdminSettings.c_SplitBillingSetting)
//				|| m_FilterByPhysician)
			if (m_FilterByPhysician) {
				l_Invoices = l_InvoiceInterface.getInvoicesByPatientAndPhysician(m_Patient,BillingModule.getCurrentPhysician());			
			} else {
				l_Invoices = l_InvoiceInterface.getInvoicesByPatient (m_Patient);
			}
		}
	catch (Exception p_Exception) 
		{
		m_Logger.warn(p_Exception.getLocalizedMessage());
		}
	
	if (l_Invoices != null) 
		{
		m_InvoiceListing.setInvoices(l_Invoices);
		m_InvoiceListing.packColumns();
		m_InvoiceListing.repaint();
		}
	else this.reset ();
	}

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

/**
 * @author ferring
 * Returns whether the table shall be filtered by physician by default or not.
 * 
 * @return
 */
public static boolean getDefaultFilterByPhysician ()
	{
	Boolean l_FilterByPhysician;
	
	l_FilterByPhysician = (Boolean)BillingModule.getSetting(BillingAdminSettings.c_SplitBillingSetting);
	if (l_FilterByPhysician == null) l_FilterByPhysician = true;
	
	return l_FilterByPhysician;
//	return BillingModule.userHasPermission (MainFrame.PERMISSIONS_CORE, MainFrame.PERMISSION_CHANGE_PHYSICIAN)
//			|| l_FilterByPhysician.booleanValue();
	}

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

public void searchInvoices (WhereClause p_Clause)
	{
	InvoiceInterface		l_InvoiceInterface = null;
	Collection <Invoice>	l_Invoices;
	long					l_Time;
	long					l_Delta;
	
	
	l_InvoiceInterface = getInvoiceInterface ();
	
	if (l_InvoiceInterface == null) return;
	
	try {
		l_Time = System.currentTimeMillis();
		
		l_Invoices = l_InvoiceInterface.getInvoicesByWhereClause(p_Clause);
		
		l_Delta = System.currentTimeMillis() - l_Time;
		
		m_Logger.info("Search took " + l_Delta + " ms");
	
		m_InvoiceListing.setInvoices(l_Invoices);
		m_InvoiceListing.selectFirstInvoice();
		m_SearchMode = true;
		
		l_Delta = System.currentTimeMillis() - l_Time;
		
		m_Logger.info("Total time required is " + l_Delta + " ms");
		}
	catch (Exception p_Exception) 
		{
		m_Logger.warn(p_Exception.getLocalizedMessage());
		}
	}

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

//public void searchInvoices ()
//	{
//	InvoiceSearchDialog	l_Dialog;
//	SearchModeEvent	l_Event;
//	
//	l_Dialog = new InvoiceSearchDialog ();
//	l_Dialog.pack ();
//	
//	MainFrame.showDialogCentered (l_Dialog);	
//
//	if (l_Dialog.wasValidated()) 
//		{
//		this.resetSearchCriteria();
//		this.startSearchWorker(l_Dialog.getWhereClause());
//	
//		l_Event = new SearchModeEvent (this,true);
//		m_SearchModeListeners.notifySearchModeListeners (l_Event);
//		}
//	}


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

public void addMouseListener (MouseListener p_Listener)
    {
	m_InvoiceListing.addMouseListener (p_Listener);
    }    

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

public void addKeyListener (KeyListener p_Listener)
    {
	m_InvoiceListing.addKeyListener (p_Listener);
    }    

//---------------------------------------------------------------------------
/**
 * attempts to locate the specified invoice in this panels invoice list
 * and returns the row it is located in when found.
 * @param p_Invoice specifies the invoice to locate.
 * @return the row the specified invoice is located if found, <code>-1</code>
 * otherwise.
 */
//---------------------------------------------------------------------------

public int locateInvoice (Invoice p_Invoice)
	{
	int l_Row = -1;
	
	if ((p_Invoice != null) && (m_InvoiceListing.containsInvoice(p_Invoice)))
		{
		l_Row = m_InvoiceListing.findInvoice(p_Invoice.formatInvoiceNumber(Invoice.c_LongFormat, true));
		}
	
	return l_Row;
	}

//---------------------------------------------------------------------------
//***************************************************************************
//* Search Worker                                    						*
//***************************************************************************
//---------------------------------------------------------------------------

Object SearchWorker (WhereClause p_Clause)
	{
	this.searchInvoices (p_Clause);
	return "";
	}

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

private void startSearchWorker (final WhereClause p_Clause)
	{
    m_SearchWorker = new SwingWorker() 
		{
		public Object construct() 
			{
			return SearchWorker (p_Clause);
			}
		public void start ()
			{
			MainFrame.getInstance().setWaitCursor(true);
			super.start();
			}
		public void finished ()
			{
			String []	l_Filler;
		
			m_InvoiceListing.packColumns();
			m_InvoiceListing.revalidate();
			MainFrame.getInstance().setWaitCursor(false);		
			
			l_Filler = new String [1];
			
			if (m_InvoiceListing.getNumberOfInvoices() > 1)
				{
				l_Filler[0] = Integer.valueOf(m_InvoiceListing.getNumberOfInvoices()).toString();
				MainFrame.getInstance().showMessage(Translatrix.getTranslationString("InvoiceListingPanel.InvoicesFound", l_Filler));
				}
			else if (m_InvoiceListing.getNumberOfInvoices() == 1)
				{
				MainFrame.getInstance().showMessage(Translatrix.getTranslationString("InvoiceListingPanel.InvoiceFound"));
				}
			else 
				{
				MainFrame.getInstance().showMessage(Translatrix.getTranslationString("InvoiceListingPanel.NoInvoicesFound"));
				}
			}
		public void interrupt ()
			{
			MainFrame.getInstance().setWaitCursor(false);
			super.interrupt();
			}
		};

	m_SearchWorker.start ();  
	}

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

public void addInvoiceListener (InvoiceListener p_Listener)
	{
	m_InvoiceListeners.addInvoiceListener(p_Listener);
	}

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

public void removeInvoiceListener (InvoiceListener p_Listener)
	{
	m_InvoiceListeners.removeInvoiceListener(p_Listener);
	}

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

public void addSearchModeListener(SearchModeListener p_Listener) 
	{
	m_SearchModeListeners.addSearchModeListener(p_Listener);
	}

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

public void removeSearchModeListener(SearchModeListener p_Listener) 
	{
	m_SearchModeListeners.removeSearchModeListener(p_Listener);
	}

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

public void setPatient (Patient p_Patient)
	{	
	if (m_SearchMode == false)
  		{	
		m_Patient = p_Patient;		
  		if ((m_Patient != null) && (m_Patient.isPersistent())) 
  			{
  			m_InvoiceListing.resetSearchCriteria();
 			this.updateListing();
  			}
  		}
  	}

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

public boolean isInSearchMode ()
	{
	return m_SearchMode;
	}

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

/**
 * @author ferring
 * Sets the filter option for the template list.
 * 
 * @param p_FilterByPhysician
 */
public void setFilterByPhysician (boolean p_FilterByPhysician)
	{
	m_FilterByPhysician = p_FilterByPhysician;
	}

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

public void resetSearch ()
	{
	SearchModeEvent l_Event;
	
	l_Event = new SearchModeEvent (this,false);
	
	this.resetSearchCriteria();
	m_SearchModeListeners.notifySearchModeListeners (l_Event);
	}

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

public void addInvoice (Invoice p_Invoice)
	{
	if (p_Invoice == null) return;
	
	m_InvoiceListing.addInvoice(p_Invoice);
	}

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

public boolean selectInvoice (String p_InvoiceNumber)
	{
	return m_InvoiceListing.selectInvoice(p_InvoiceNumber);
	}

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

public void selectLastInvoice ()
	{
	m_InvoiceListing.selectLastInvoice();
	}

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

public Invoice getSelectedInvoice ()
	{
	Invoice	l_Invoice;
	
	l_Invoice = m_InvoiceListing.getSelectedInvoice();
	if (l_Invoice != null)
		{
		l_Invoice = BillingModule.getInstance().fetchLazyDependencies(l_Invoice);
	
		if ((m_SearchMode) && (l_Invoice.getPatient() != null)) 
			m_Patient = l_Invoice.getPatient();
		}
		
	return l_Invoice;
	}

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

public void setInvoice (Invoice p_Invoice)
	{
	int	l_Row;
	
	if (p_Invoice == null) return;
	
	if (p_Invoice.equals (m_InvoiceListing.getSelectedInvoice()))
		{
		this.setSelectedInvoice(p_Invoice);
		}
	else if (m_InvoiceListing.containsInvoice(p_Invoice))
			{
			l_Row = m_InvoiceListing.findInvoice(p_Invoice.formatInvoiceNumber(Invoice.c_LongFormat, true));
			if (l_Row >= 0) m_InvoiceListing.setInvoiceAt(p_Invoice, l_Row);
			}
	}

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

public void setSelectedInvoice (Invoice p_Invoice)
	{
	m_InvoiceListing.setSelectedInvoice(p_Invoice);
//	p_Invoice = this.fetchLazyDependencies(p_Invoice);
//    this.notifyInvoiceListeners(p_Invoice);
	}

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

public Invoice[] getSelectedInvoices ()
	{
	Invoice []   l_SelectedInvoices;
    Invoice		l_Invoice; 
     
    l_SelectedInvoices = m_InvoiceListing.getSelectedInvoices();
    if (l_SelectedInvoices != null && l_SelectedInvoices.length == 1)
   		{
    	l_Invoice = l_SelectedInvoices[0];
    	if (l_Invoice.isPersistent()) 
    		{
    		l_Invoice = BillingModule.getInstance().fetchLazyDependencies(l_Invoice);
    		}
    	l_SelectedInvoices[0] = l_Invoice;
    	this.setSelectedInvoice(l_Invoice);
   		}   
 	
	return l_SelectedInvoices;
	}

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

public void deleteSelectedInvoices ()
	{
	Invoice []				l_SelectedInvoices;
	String []				l_Filler;
	InvoiceInterface		l_InvoiceInterface = null;
	Invoice					l_Invoice;
	Collection <Invoice>	l_DeletedInvoices;
	Iterator <Invoice>		l_InvoiceIterator;
	int						l_UserChoice;
	int						l_Index;
	int						l_Action;
	boolean					l_Allowed;
	
	l_UserChoice = JOptionPane.NO_OPTION;
	
	if (BillingModule.userHasPermission (BillingModule.c_BillingModule, BillingModule.c_deleteInvoices))
		{
		l_SelectedInvoices = this.getSelectedInvoices ();
		if (l_SelectedInvoices == null) return;
		if (l_SelectedInvoices.length == 1)
			{
			if (BillingModule.userHasPermissionForInvoice (l_SelectedInvoices[0], BillingModule.c_deleteStem,true))
				{
				l_Filler = new String [1];
				l_Filler [0] = l_SelectedInvoices[0].formatInvoiceNumber(false, true);
			
				l_UserChoice = BillingModule.getUserConfirmation("InvoiceListingPanel.DeleteSingleInvoiceTitle",
																 "InvoiceListingPanel.DeleteSingleInvoiceMessage",
					  							  			 	 l_Filler);
				}
			}
		else
			{
			l_Filler = new String [1];			
			l_Filler [0] = Integer.valueOf(l_SelectedInvoices.length).toString();
			
			l_UserChoice = BillingModule.getUserConfirmation("InvoiceListingPanel.DeleteMultipleInvoicesTitle",
					  							  			 "InvoiceListingPanel.DeleteMultipleInvoicesMessage",
					  							  			 l_Filler);
			}
		
		if (l_UserChoice == JOptionPane.YES_OPTION)
			{
			l_InvoiceInterface = getInvoiceInterface ();	
			if (l_InvoiceInterface == null) return;
		
			l_Allowed = true;
			l_Index   = 0;
			
			while (	l_Allowed && (l_Index < l_SelectedInvoices.length))
				{
				l_Invoice = l_SelectedInvoices[l_Index++];
				if (BillingModule.userHasPermissionForInvoice (l_Invoice, BillingModule.c_deleteStem,false))
					{
					l_Action = InvoiceWorkflow.previewStateChange (l_Invoice,InvoiceWorkflow.c_DeleteAction);
					l_Allowed &= (l_Action == InvoiceWorkflow.c_DoDelete);
					}
				else l_Allowed = false;	
				}
				
			if (l_Allowed == false)
				{
				BillingModule.notifyUser("InvoiceListingPanel.CanNotDeleteTitle", "InvoiceListingPanel.CanNotDeleteMessage", null);
				return;
				}
			
			l_DeletedInvoices = new ArrayList <Invoice> ();
			
			for (l_Index = 0; l_Index < l_SelectedInvoices.length; l_Index++)
				{
				l_Invoice = l_SelectedInvoices[l_Index];
			
				if (l_Invoice.getStatement() != null)
					{
					l_Filler = new String [2];
					l_Filler [0] = l_Invoice.formatInvoiceNumber(false, true);
					l_Filler [1] = l_Invoice.getStatement().formatStatementNumber();
								
					l_UserChoice = BillingModule.getUserConfirmation("InvoiceListingPanel.DeleteStatementInvoiceTitle",
					  			 					  				 "InvoiceListingPanel.DeleteStatementInvoiceMessage",
					  			 					  				 l_Filler);
					
					
					if (l_UserChoice == JOptionPane.NO_OPTION) continue;
					}
				
				try {
					l_InvoiceInterface.deleteInvoice(l_Invoice);
					l_DeletedInvoices.add (l_Invoice);
					
					GECAMedLog.user("Billing","DELETE Invoice","Deleted Invoice with ID " + l_Invoice.getId());
					}
				catch (Exception p_Exception) 
					{
					m_Logger.warn(p_Exception.getLocalizedMessage());
					}
				}

			m_InvoiceListing.removeSelectedInvoices();
			
			if (l_DeletedInvoices.size() > 1)
				 BillingModule.getInstance().fireMultipleInvoiceChange(InvoiceChangeEvent.c_InvoiceDeleted,Invoice.getInvoiceIDs(l_DeletedInvoices));
			else 
				{
				l_InvoiceIterator = l_DeletedInvoices.iterator();
				BillingModule.getInstance().fireInvoiceChange(InvoiceChangeEvent.c_InvoiceDeleted,l_InvoiceIterator.next());
				}
			}
		}
	}

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

public void selectFirstInvoice ()
	{
	m_InvoiceListing.selectFirstInvoice();
	}

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

public boolean selectNextInvoice ()
	{
	boolean l_NextOneSelected;
	
	l_NextOneSelected = m_InvoiceListing.selectNextInvoice();
	if (l_NextOneSelected == false)
		MainFrame.getInstance().showMessage(Translatrix.getTranslationString("InvoiceListingPanel.LastInvoice"));

	return l_NextOneSelected;
	}

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

public boolean selectPreviousInvoice ()
	{
	boolean l_PreviousOneSelected;
	
	l_PreviousOneSelected = m_InvoiceListing.selectPreviousInvoice();
	if (l_PreviousOneSelected == false)
		MainFrame.getInstance().showMessage(Translatrix.getTranslationString("InvoiceListingPanel.FirstInvoice"));

	return l_PreviousOneSelected;
	}

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

@Override
public void preparetoShowup() 
	{
	Patient l_Patient;
	Invoice l_CurrentInvoice;
	
	if (!this.isInSearchMode())
		{
//		l_Patient 			= BillingModule.getCurrentPatient();
		l_Patient 			= BillingModule.getInstance().getPatientSummaryPanel().getPatient();
		l_CurrentInvoice 	= BillingModule.getInstance().getCurrentInvoice();
		
		if ((l_Patient != null) && (l_Patient.isPersistent()))
			{
			if (l_Patient.equals(m_Patient) == false) 
				this.setPatient (l_Patient);
			
			if (l_CurrentInvoice == null)
				 m_InvoiceListing.selectFirstInvoice();
			else m_InvoiceListing.selectInvoice(l_CurrentInvoice.getInvoiceNumber());
			}
		
		/**
		 * @author ferring
		 * Shows the check box, to set the filter option for the template list
		 */
		BillingModule.getInstance().getInvoiceProperties()
				.setFilterByPhysicianBoxVisible(true);
		}
	}

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

public void preparetoHide ()
	{
	/**
	 * @author ferring
	 * Hides the check box, to set the filter option for the template list
	 */
	BillingModule.getInstance().getInvoiceProperties()
			.setFilterByPhysicianBoxVisible(false);
	}

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

public void reset ()
	{
	this.resetSearchCriteria();
	m_InvoiceListing.removeAllInvoices();
	m_Patient = null;
	}

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

public Integer getNumberOfMemosForInvoice (Invoice p_Invoice)
	{
	if (p_Invoice!= null) return p_Invoice.getNumberOfMemos();
					else return 0;
	}

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

public void relocalize() 
	{
	if (m_InvoiceListing != null) m_InvoiceListing.relocalize();
	}

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

public void propertyChange(PropertyChangeEvent p_Event) 
	{
	String 				l_Column;
	Object 				l_Criterion;
	Invoice				l_Invoice;
	WhereClause			l_Clause;
	HibernateCondition	l_Condition;
	
	SearchModeEvent	l_Event;
	
//	Hashtable <String, Object>	l_Criterions;
	
	if (p_Event.getSource() == m_InvoiceListing)
		{
		
		if (InvoiceListBox.c_SearchCriterionChanged.equals(p_Event.getPropertyName()))
			{
			l_Column 	 = (String) p_Event.getOldValue();
			l_Criterion = 			p_Event.getNewValue();		
		
			if (l_Criterion == null) 
				{
				this.resetSearch();
				return;
				}
			
			l_Clause    = new WhereClause ();
						
			l_Event = new SearchModeEvent (this,true);
				
			if (InvoiceListModel.c_InvoiceNumberHeader.equals (l_Column))
				{	
				l_Condition = new HibernateCondition ("id",
													  HibernateOperator.c_EqualOperator,
													  (Integer)l_Criterion);
				l_Clause.addCondition(l_Condition);													  
				this.startSearchWorker(l_Clause);
				m_SearchModeListeners.notifySearchModeListeners (l_Event);
				}
			else if (InvoiceListModel.c_InvoiceDateHeader.equals (l_Column))
				{
				l_Condition = new HibernateCondition ("invoiceDate",
													  HibernateOperator.c_EqualOperator,
													  (Date)l_Criterion);
				l_Condition.setParameter("date");
				l_Clause.addCondition(l_Condition);													  
				this.startSearchWorker(l_Clause);
				m_SearchModeListeners.notifySearchModeListeners (l_Event);
				}
			else if (InvoiceListModel.c_StatementHeader.equals (l_Column))
				{	
				l_Criterion = Integer.valueOf (StatementNumberFormatter.getStatementID((String)l_Criterion));
				l_Condition = new HibernateCondition ("statement.id",
													  HibernateOperator.c_EqualOperator,
													  (Integer)l_Criterion);
				l_Clause.addCondition(l_Condition);													  
				this.startSearchWorker(l_Clause);
				m_SearchModeListeners.notifySearchModeListeners (l_Event);
				}
			}
		else if (InvoiceListBox.c_FilterCriterionChanged.equals(p_Event.getPropertyName()))
			{
			l_Column 	 = (String) p_Event.getOldValue();
			l_Criterion = 			p_Event.getNewValue();		

			if (InvoiceListModel.c_StatusHeader.equals (l_Column)) 	
				{
				if (l_Criterion == null)
					{
					m_InvoiceListing.resetFilterCriteria(InvoiceListModel.c_StatusColumn);
					}
				else
					{
					m_InvoiceListing.setFilterCriteria(InvoiceListModel.c_StatusColumn, l_Criterion);
					}
				}
			}
		else if (InvoiceListBox.c_InvoiceStateChanged.equals(p_Event.getPropertyName()))
			{
			if (m_ExtendedMode)
				{
				l_Invoice = (Invoice) p_Event.getNewValue();
				this.saveStateChange(l_Invoice);
				}
			}
		}
	}

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

public void actionPerformed (ActionEvent p_Event) 
	{
	if (p_Event.getSource() == m_MessageDelay)
		{
		m_MessageDelay.stop ();
		MainFrame.getInstance().showMessage("Please be patient");
		MainFrame.getInstance().setWaitCursor(true);
		}
	
	}

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

public void valueChanged (ListSelectionEvent p_SelectionEvent) 
	{
	Invoice				l_Invoice; 
	InvoiceChangeEvent	l_Event; 
	
	if (!p_SelectionEvent.getValueIsAdjusting()) {    
	    l_Invoice = m_InvoiceListing.getSelectedInvoice();
	    l_Invoice = BillingModule.getInstance().fetchLazyDependencies(l_Invoice);
	    BillingModule.getInstance().setInvoice(l_Invoice);
//	    l_Event = new InvoiceChangeEvent (this, InvoiceChangeEvent.c_InvoiceSelectionChanged,l_Invoice);
//	    m_InvoiceListeners.notifyInvoiceListeners(l_Event);
	} else {
//		System.out.println("adjusting " + p_SelectionEvent);
	}
}

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

public void invoiceChanged (InvoiceChangeEvent p_Event) 
	{
	Invoice					l_Invoice;
	Collection <Integer>	l_UpdatedInvoiceIds;
	Collection <Integer>	l_ListedInvoiceIds;
	Collection <Invoice>	l_UpdatedInvoices;
	Iterator <Invoice>		l_InvoiceIterator;

//	if ((p_Event.getSource() == null) || (p_Event.getSource().equals(BillingModule.getInstance())))
	if (!(p_Event.getSource() instanceof InvoiceListingPanel))
		{
		if (p_Event.isMultiple())
			{
			// Multiple Invoices have been changed. First step consists in identifying
			// among these invoices those that are currently listed. To do so, we form
			// the intersection between the set of update invoices IDs and the set of
			// of currently listed IDs.
			
			l_UpdatedInvoiceIds = new Vector <Integer> (p_Event.getInvoiceIDs());
			l_ListedInvoiceIds  = Invoice.getInvoiceIDs (m_InvoiceListing.getInvoices());			
			l_UpdatedInvoiceIds.retainAll (l_ListedInvoiceIds);
			
			l_UpdatedInvoices = BillingModule.getInstance().getInvoicesByIds (l_UpdatedInvoiceIds);
			if (l_UpdatedInvoices != null)
				{
				l_InvoiceIterator = l_UpdatedInvoices.iterator();
				while (l_InvoiceIterator.hasNext())
					{
					l_Invoice = l_InvoiceIterator.next();
					this.processInvoiceChangeEvent (p_Event.getType(), l_Invoice);
					}
				}
			}
		else
			{
			l_Invoice = p_Event.getInvoice();
			this.processInvoiceChangeEvent (p_Event.getType(), l_Invoice);
			}
		}
	}
	
//---------------------------------------------------------------------------

private void processInvoiceChangeEvent (int p_Type, Invoice p_Invoice)
	{
	switch (p_Type)
		{
		case InvoiceChangeEvent.c_InvoiceStatusChanged:
		
			processInvoiceStatusChangedEvent (p_Invoice);
			break;
			
		case InvoiceChangeEvent.c_InvoiceUpdated:	
			
			processInvoiceUpdatedEvent (p_Invoice);
			break;
			
		case InvoiceChangeEvent.c_InvoiceDeleted:
			
			processInvoiceDeletedEvent (p_Invoice);
			break;
		}
	}

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

private void processInvoiceStatusChangedEvent (Invoice p_Invoice)
	{
	int	l_Row;

	l_Row = this.locateInvoice(p_Invoice);
	if (l_Row >= 0) m_InvoiceListing.setInvoiceAt(p_Invoice, l_Row);
	}

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

private void processInvoiceUpdatedEvent (Invoice p_Invoice)
	{
	int	l_Row;

	l_Row = this.locateInvoice(p_Invoice);
	if (l_Row >= 0) 
		{
		m_InvoiceListing.setInvoiceAt (p_Invoice, l_Row);
		}
	else 
		{
		p_Invoice = BillingModule.getInstance().fetchLazyDependencies(p_Invoice);
		if (p_Invoice.getPatient().equals(m_Patient))
			{
			m_InvoiceListing.addInvoice (p_Invoice);
			}
		}
	}

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

private void processInvoiceDeletedEvent (Invoice p_Invoice)
	{
	int	l_Row;

	l_Row = this.locateInvoice(p_Invoice);
	if (l_Row >= 0) m_InvoiceListing.removeInvoiceAt (l_Row);
	}

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

public void userModeChanged (boolean p_SuperUserMode) 
	{
	m_ExtendedMode = p_SuperUserMode;
	m_InvoiceListing.setEditable(m_ExtendedMode);
	}


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

public void physicianChanged (Physician p_Physician) 
	{
	/**
	 * @author ferring
	 * Whether the data is filtered by physician, does not depend from the split 
	 * billing option only anymore.
	 */
//	if ((Boolean)BillingModule.getSetting(BillingAdminSettings.c_SplitBillingSetting))
	if (m_FilterByPhysician)
		{
		this.updateListing();
		}
	}
	
//***************************************************************************
//* End Of Class                                                            *
//***************************************************************************
}

