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

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.JTextComponent;

import lu.tudor.santec.dicom.gui.ErrorDialog;
import lu.tudor.santec.gecamed.billing.gui.TextWrappingCellRenderer;
import lu.tudor.santec.gecamed.core.gui.GECAMedAction;
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.IconFetcher;
import lu.tudor.santec.gecamed.core.gui.LoginScreen;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.RegistrationDesk;
import lu.tudor.santec.gecamed.core.gui.utils.AutoResizeTable;
import lu.tudor.santec.gecamed.core.gui.utils.GECAMedGuiUtils;
import lu.tudor.santec.gecamed.core.gui.utils.LineColorCellRenderer;
import lu.tudor.santec.gecamed.core.gui.utils.TableSorter;
import lu.tudor.santec.gecamed.core.utils.GECAMedUtils;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.esante.gui.ESantePatientListRenderer;
import lu.tudor.santec.gecamed.esante.gui.actions.PatientProvider;
import lu.tudor.santec.gecamed.esante.gui.actions.PdqAction;
import lu.tudor.santec.gecamed.esante.gui.actions.RemoveESanteIdAction;
import lu.tudor.santec.gecamed.esante.gui.tab.ESanteTab;
import lu.tudor.santec.gecamed.esante.gui.utils.ESanteGuiUtils;
import lu.tudor.santec.gecamed.importexport.gui.export.ExportDialog;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Insurance;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.PatientStub;
import lu.tudor.santec.gecamed.patient.ejb.session.beans.InsuranceBean;
import lu.tudor.santec.gecamed.patient.ejb.session.beans.PatientAdminBean;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.IPatientPermissions;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.InsuranceInterface;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.PatientAdminInterface;
import lu.tudor.santec.gecamed.patient.gui.PatientListModule;
import lu.tudor.santec.gecamed.patient.gui.PatientManagerModule;
import lu.tudor.santec.gecamed.patient.gui.SecurityQuestionDialog;
import lu.tudor.santec.gecamed.patient.gui.patientexport.PatientExportPanel;
import lu.tudor.santec.gecamed.usermanagement.gui.settings.UserSettingsPlugin;
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;


/**
 * JPanel for the patient search. shows a searchfield on top and a result list
 * on the bottom.
 * 
 * 
 * @author Johannes Hermen johannes.hermen(at)tudor.lu
 * 
 * @version <br>
 *          $Log: PatientListPanel.java,v $
 *          Revision 1.131  2014-01-21 06:29:31  ferring
 *          checking parameters on length and emptiness
 *
 *          Revision 1.130  2013-12-13 15:26:27  troth
 *          *** empty log message ***
 *
 *          Revision 1.129  2013-11-21 09:44:52  ferring
 *          auto resizing of patient search list
 *
 *          Revision 1.128  2013-10-16 13:03:47  ferring
 *          some small esante bugfixes
 *
 *          Revision 1.127  2013-10-08 08:59:23  ferring
 *          class name refactoring and tree view implementation (first steps)
 *
 *          Revision 1.126  2013-07-15 06:18:35  ferring
 *          logging changed
 *
 *          Revision 1.125  2013-07-09 06:48:01  ferring
 *          Nullpointer when eSante was deactiviated
 *
 *          Revision 1.124  2013-07-03 13:06:35  ferring
 *          eSante module handling changed
 *
 *          Revision 1.123  2013-06-24 12:58:50  ferring
 *          eSante functions in PatientListPanel are only shown, if eSante is loaded. And either the connect or the disconnect option is shown
 *
 *          Revision 1.122  2013-06-10 08:22:02  ferring
 *          eSante POC
 *
 *          Revision 1.121  2013-04-16 13:42:10  ferring
 *          *** empty log message ***
 *
 *          Revision 1.120  2013-04-09 07:37:30  ferring
 *          Patient search unaccented
 *
 *          Revision 1.119  2013-03-20 10:41:19  troth
 *          Add translation. Add icon to popup.
 *
 *          Revision 1.118  2013-03-11 14:37:28  troth
 *          Add column with physician.
 *
 *          Revision 1.117  2013-03-05 14:48:24  troth
 *          Add ProgressBar in export dialog.
 *
 *          Revision 1.116  2013-02-25 10:51:52  troth
 *          Remove some system.out.println.
 *
 *          Revision 1.115  2013-02-25 10:32:17  troth
 *          Add function to add patients from the patientsearch tab the patientexport tab.
 *
 *          Revision 1.114  2013-02-21 14:14:22  ferring
 *          Improved the security dialog layout in order to fix it for linux
 *
 *          Revision 1.113  2013-02-19 10:04:34  troth
 *          Change the search button, add the the export dialog button, to some GUI design and clear up code.
 *
 *          Revision 1.112  2013-02-15 13:58:41  ferring
 *          unused imports removed
 *
 *          Revision 1.111  2013-01-23 16:50:50  troth
 *          add new GUI for the MM Export tab the PatientExportPanel.
 *
 *          Revision 1.110  2013-01-10 12:54:46  ferring
 *          system exit method changed
 *
 *          Revision 1.109  2012-10-19 16:24:42  troth
 *          First version of GECAMed launcher.
 *
 *          Revision 1.108  2012-03-06 14:53:52  ferring
 *          formatting fixed
 * <br>
 *          Revision 1.107 2011-08-22 13:12:47 ferring <br>
 *          Warnings removed <br>
 * <br>
 *          Revision 1.106 2010-08-26 14:28:04 ferring <br>
 *          additional options for main arguments added <br>
 * <br>
 *          Revision 1.105 2010-08-26 13:33:51 hermen <br>
 *          added commandline arg PATIENTSEARCH: <br>
 * <br>
 *          Revision 1.104 2010-06-24 11:55:09 hermen <br>
 *          version 1.1 <br>
 * <br>
 *          Revision 1.103 2010-05-12 08:58:37 hermen <br>
 *          cleanup <br>
 * <br>
 *          Revision 1.102 2010-05-04 14:23:39 hermen <br>
 *          suspended autoreload of patientlist <br>
 * <br>
 *          Revision 1.101 2010-05-03 13:45:21 hermen <br>
 *          enhanced logging <br>
 * <br>
 *          Revision 1.100 2010-04-27 15:11:51 mack <br>
 *          Minor improvement <br>
 * <br>
 *          Revision 1.99 2010-04-08 10:56:40 hermen <br>
 *          enhanced logging <br>
 * <br>
 *          Revision 1.98 2010-04-06 15:37:23 hermen <br>
 *          changed logging <br>
 * <br>
 *          Revision 1.97 2010-03-12 14:17:42 hermen <br>
 *          cleanup of panel layouts and icons <br>
 * <br>
 *          Revision 1.96 2009-12-14 15:34:19 hermen <br>
 *          fixed patient loading via F6/F7 <br>
 * <br>
 *          Revision 1.95 2008-10-21 09:53:34 hermen <br>
 *          fixed patient slot bug <br>
 *          enhanced logging <br>
 *          code cleanup <br>
 * <br>
 *          Revision 1.94 2008-09-25 09:43:07 heinemann <br>
 *          fixed copyrights <br>
 * <br>
 *          Revision 1.93 2008-09-15 09:18:35 heinemann <br>
 *          included deletion of patient files in patient delete process. <br>
 * <br>
 *          Revision 1.92 2008-09-04 14:54:22 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.91 2008-08-29 10:27:58 heinemann <br>
 *          Ticket #167 (closed task: fixed) <br>
 *          Close patient file of deleted patient <br>
 * <br>
 *          Revision 1.90 2008-06-12 11:44:56 hermen <br>
 *          fixed opening patient on reload message <br>
 * <br>
 *          Revision 1.89 2008-06-09 09:07:56 hermen <br>
 *          open patient directly if ssec search returned exactly 1 result <br>
 * <br>
 *          Revision 1.88 2008-05-30 09:12:12 hermen <br>
 *          added new search setting <br>
 * <br>
 *          Revision 1.87 2008-05-28 14:17:54 hermen <br>
 *          only select last selected modul on open patient if this module can
 *          display patient data <br>
 * <br>
 *          Revision 1.86 2008-05-28 08:24:41 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.85 2008-05-27 09:09:10 hermen <br>
 *          fixed search RETURN key behavior <br>
 * <br>
 *          Revision 1.84 2008-05-27 08:23:50 hermen <br>
 *          fixed search in dialog and added new setting <br>
 * <br>
 *          Revision 1.83 2008-04-30 12:18:38 hermen <br>
 *          initial checkin of Addressbook module <br>
 * <br>
 *          Revision 1.82 2008-04-28 08:05:48 hermen <br>
 *          changed patient search to use patient_stub view and bean <br>
 * <br>
 *          Revision 1.81 2008-04-16 08:15:42 hermen <br>
 *          fixed font in patient search <br>
 * <br>
 *          Revision 1.80 2008-04-14 08:11:58 hermen <br>
 *          added option to use big fonts for patient seatrch and reorganized
 *          search settings <br>
 * <br>
 *          Revision 1.79 2008-04-03 15:03:01 hermen <br>
 *          fixed matricule query <br>
 * <br>
 *          Revision 1.78 2008-01-23 08:30:09 hermen <br>
 *          *** empty log message *** <br>
 * 
 */
public class PatientListPanel extends JPanel implements PropertyChangeListener, MouseListener, PatientProvider
{
	// TODO: prepared, but not yet fully in use: ...
	public static final int COLUMN_SSN			= 0;
	public static final int COLUMN_SUR_NAME		= 1;
	public static final int COLUMN_BIRTH_NAME	= 2;
	public static final int COLUMN_FIRST_NAME	= 3;
	public static final int COLUMN_GENDER		= 4;
	public static final int COLUMN_INSURANCE	= 5;
	public static final int COLUMN_ADDRESS		= 6;
	public static final int COLUMN_PHONE		= 7;
	public static final int COLUMN_PHYSICIAN	= 8;
	public static final int COLUMN_ID			= 9;
	public static final int COLUMN_STORAGE		= 10;
	public static final int COLUMN_ESANTE		= 11;
	
	private static Logger				logger				= Logger.getLogger(PatientListPanel.class.getName());
	
	// /**
	// * JMS topic to register patient changes and update the search
	// */
	// private static final String TOPIC_NAME =
	// "topic/GeCam/patientmanagementTopic";
	
	private static final long			serialVersionUID	= 1L;
	/**
	 * global hotkey to show the search panel
	 */
	private static final char			KEY_SEARCH			= KeyEvent.VK_F3;
	
	/**
	 * global hotkey to switch to the previous patient
	 */
	private static final char			KEY_PREVIOUS		= KeyEvent.VK_F6;
	
	/**
	 * global hotkey to switch to the next patient
	 */
	private static final char			KEY_NEXT			= KeyEvent.VK_F7;
	
	/**
	 * hotkey to reload the search panel
	 */
	private static final char			KEY_RELOAD			= KeyEvent.VK_F5;
	
	/**
	 * hotkey to clear the current search
	 */
	private static final char			KEY_CLEAR			= KeyEvent.VK_ESCAPE;
	
	public static final String			OPEN_PATIENT		= "OPEN Patient";
	protected static final String		CLOSE_PATIENT		= "CLOSE Patient";
	protected static final String		UPDATE_PATIENT		= "UPDATE Patient";
	protected static final String		CREATE_PATIENT		= "CREATE Patient";
	
	protected static final long			SEARCH_WAIT_TIMEOUT	= 300;
	
	/**
	 * show a additional searchfield for the ssn
	 */
	private boolean						MATRICULE_SEARCH	= false;
	
	private PatientStubListTableModel	patientListTableModel;
	private TableSorter					tableSorter;
	private AutoResizeTable				patientTable;
	
	private PatientListModule			patientListModule;
	
	private JTextField					searchTextField;
	private JTextField					searchAddressPhoneField;
	private JTextField					searchMatriculeField;
	
	protected boolean					completeList;
	private String						filter				= "";
	private PatientManagerModule		patientManagerModule;
	
	private InsuranceInterface			insuranceManager;
	
	private JScrollPane					jsp;
	
	private GECAMedAction				previousAction;
	
	private GECAMedAction				nextAction;
	
	private GECAMedAction				searchPatientAction;
	
	private JPopupMenu					popup;
	
	private JMenuItem					openWithoutESante;
	
	private JMenuItem					openWithoutESanteInNewTab;
	
	private JMenuItem					connectionPatientAction;
	
	private JMenuItem					disconnectPatientAction;
	
	private Timer						timer;
	
	// private Topic topic;
	//
	// private TopicSession session;
	
	private boolean						searchRunning;
	
	private Font						bgFont				= new Font("Plain", Font.BOLD, 64);
	
	private boolean						BIG_FONTS;
	
	protected boolean					openPatient;
	
	private Timer						openPatientTaskTimer;

	private JLabel l1;
	
	private JLabel l2;

	private JLabel l3;
	
	private GECAMedAction clearAction;

	private GECAMedAction reloadAction;

	private PatientAdminInterface manager;
	
	String[] enabledPanels;

	
	/**
	 * @param patientListModule
	 * @param patientManagerModule
	 */
	public PatientListPanel(final PatientListModule patientListModule, final PatientManagerModule patientManagerModule)
	{
		this.setOpaque(false);
		
		// show ssn search field?
		try
		{
			MATRICULE_SEARCH = (Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.SEARCH_MATRICULE_FIELD);
		}
		catch (Exception e)
		{
			logger.log(Level.WARN, "Can't get patient setting SEARCH_MATRICULE_FIELD.", e);
		}
		
		// use big fonts?
		try
		{
			BIG_FONTS = (Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.SEARCH_BIG_FONTS);
		}
		catch (Exception e)
		{
			logger.log(Level.WARN, "Can't get patient setting SEARCH_BIG_FONTS.", e);
		}
		
		this.patientListModule = patientListModule;
		this.patientManagerModule = patientManagerModule;
		this.setLayout(new BorderLayout());
		this.patientListTableModel = new PatientStubListTableModel();
		
		manager = (PatientAdminInterface) ManagerFactory.getRemote(PatientAdminBean.class);
		insuranceManager = (InsuranceInterface) ManagerFactory.getRemote(InsuranceBean.class);
		
		this.tableSorter = new TableSorter(this.patientListTableModel);
		
		this.patientTable = new AutoResizeTable(this.tableSorter);
		this.patientTable.setOpaque(false);
		this.patientTable.addMouseListener(this);
		this.patientTable.getTableHeader().setReorderingAllowed(false);
		this.patientTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		
		int alpha = 150;
		
		int gap = 0;
		double factor = 1;
		Font font = new JLabel().getFont().deriveFont(Font.PLAIN);
		if (BIG_FONTS)
		{
			font = font.deriveFont(Font.BOLD, 14);
			gap = 5;
			factor = 1.2;
		}
		LineColorCellRenderer renderer			= new LineColorCellRenderer(alpha, font, false);
		LineColorCellRenderer centeredRenderer	= new LineColorCellRenderer(alpha, font, true);
		LineColorCellRenderer eSanteRenderer	= new ESantePatientListRenderer(alpha, font, false);
		
		
//		this.patientTable.getColumnModel().getColumn(COLUMN_SSN).setCellRenderer(renderer);
		this.patientTable.getColumnModel().getColumn(COLUMN_SSN).setCellRenderer(eSanteRenderer);
//		this.patientTable.getColumnModel().getColumn(COLUMN_SSN).setMinWidth((int)(140 * factor));
		this.patientTable.setSizeAsNeeded(COLUMN_SSN, 165);
		this.patientTable.getColumnModel().getColumn(COLUMN_SUR_NAME).setCellRenderer(renderer);
//		this.patientTable.getColumnModel().getColumn(COLUMN_SUR_NAME).setMinWidth((int) (150 * factor));
		this.patientTable.setSizeAsNeeded(COLUMN_SUR_NAME, 200);
		this.patientTable.getColumnModel().getColumn(COLUMN_BIRTH_NAME).setCellRenderer(renderer);
//		this.patientTable.getColumnModel().getColumn(COLUMN_BIRTH_NAME).setMinWidth((int) (150 * factor));
		this.patientTable.setSizeAsNeeded(COLUMN_BIRTH_NAME, 200);
		this.patientTable.getColumnModel().getColumn(COLUMN_FIRST_NAME).setCellRenderer(renderer);
//		this.patientTable.getColumnModel().getColumn(COLUMN_FIRST_NAME).setMinWidth((int) (150 * factor));
		this.patientTable.setSizeAsNeeded(COLUMN_FIRST_NAME, 200);
		this.patientTable.getColumnModel().getColumn(COLUMN_GENDER).setCellRenderer(centeredRenderer);
		this.patientTable.setSizeAsNeeded(COLUMN_GENDER, (int) (20 * factor));
//		this.patientTable.getColumnModel().getColumn(COLUMN_GENDER).setMaxWidth((int) (20 * factor));
		this.patientTable.getColumnModel().getColumn(COLUMN_INSURANCE).setCellRenderer(renderer);
//		this.patientTable.getColumnModel().getColumn(COLUMN_INSURANCE).setMinWidth((int) (50 * factor));
		this.patientTable.setSizeAsNeeded(COLUMN_INSURANCE, 120);
		this.patientTable.getColumnModel().getColumn(COLUMN_ADDRESS).setCellRenderer(new TextWrappingCellRenderer(alpha, font, gap));
//		this.patientTable.getColumnModel().getColumn(COLUMN_ADDRESS).setMinWidth((int) (350 * factor));
		this.patientTable.setSizing(COLUMN_ADDRESS, AutoResizeTable.SIZE_TYPE_FIX, 320);
		this.patientTable.getColumnModel().getColumn(COLUMN_PHONE).setCellRenderer(new TextWrappingCellRenderer(alpha, font, gap));
//		this.patientTable.getColumnModel().getColumn(COLUMN_PHONE).setMinWidth((int) (180 * factor));
		this.patientTable.setSizing(COLUMN_PHONE, AutoResizeTable.SIZE_TYPE_FIX, 150);
		this.patientTable.getColumnModel().getColumn(COLUMN_PHYSICIAN).setCellRenderer(renderer);
//		this.patientTable.getColumnModel().getColumn(COLUMN_PHYSICIAN).setMinWidth((int) (50 * factor));
		this.patientTable.setSizeAsNeeded(COLUMN_PHYSICIAN, 120);
		
		
		this.patientTable.getColumnModel().getColumn(COLUMN_ID).setCellRenderer(renderer);
		this.patientTable.setSizeAsNeeded(COLUMN_ID, 150);
		
		
		this.patientTable.getColumnModel().getColumn(COLUMN_STORAGE).setMinWidth(0);
		this.patientTable.getColumnModel().getColumn(COLUMN_STORAGE).setMaxWidth(0);
		this.patientTable.getColumnModel().getColumn(COLUMN_STORAGE).setPreferredWidth(0);
		
		//Check if storage panel is activated or not in order to show it
		
		manager = (PatientAdminInterface) ManagerFactory.getRemote(PatientAdminBean.class);
		if (enabledPanels == null) {
			// create all optional modules
			enabledPanels = PatientManagerModule.getInstance().administrativeElementsPlugin.getEnabledElements().split(" ");
		}

		for (int i = 0; i < enabledPanels.length; i++) {
		//	System.out.println("------------- " + enabledPanels[i]);
			if(enabledPanels[i].equals("lu.tudor.santec.gecamed.patient.gui.administrative.PatientRemarks"))
			{
				this.patientTable.getColumnModel().getColumn(COLUMN_STORAGE).setCellRenderer(renderer);
				this.patientTable.getColumnModel().getColumn(COLUMN_STORAGE).setMinWidth(100);
				this.patientTable.getColumnModel().getColumn(COLUMN_STORAGE).setMaxWidth(300);
				this.patientTable.getColumnModel().getColumn(COLUMN_STORAGE).setPreferredWidth(200);
				this.patientTable.setSizeAsNeeded(COLUMN_STORAGE, 200);
				break;
			}
		}
		
		
		
		this.patientTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		this.patientTable.getSelectionModel().addListSelectionListener(new ListSelectionListener()
		{
			public void valueChanged(ListSelectionEvent e)
			{
				setPatientButtons();
				patientTable.scrollRectToVisible(patientTable.getCellRect(patientTable.getSelectedRow(), 0, true));
			}
		});
		/* ------------------------------------------------------- */
		// create a popup menu on right clicks
		popup = new JPopupMenu();
		// open in a new tap in the patientview
		JMenuItem openNewtab = new JMenuItem(Translatrix.getTranslationString("list.openInNewTab"), 
				IconFetcher.getSmallIcon(PatientManagerModule.class, PatientManagerModule.OPEN_PATIENT_IN_TAB));
		openNewtab.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				loadPatient(true);
			}
		});
		popup.add(openNewtab);
		
		if (ESanteGuiUtils.isESanteModuleActivated())
		{
			/* ------------------------------------------------------- */
			// open without eSanté tab
			// TODO: Translate
			openWithoutESante = new JMenuItem(Translatrix._("list.openWithoutESante"), 
					GECAMedGuiUtils.createGrayImage(ESanteGuiUtils.getESanteIcon(ESanteGuiUtils.SMALLPIX)));
			openWithoutESante.addActionListener(new ActionListener()
			{
				public void actionPerformed (ActionEvent e)
				{
					loadPatient(false, new String[] { ESanteTab.TAB_NAME });
				}
			});
			popup.add(openWithoutESante);
			
			openWithoutESanteInNewTab = new JMenuItem(Translatrix._("list.openWithoutESanteInNewTab"), 
					GECAMedGuiUtils.createGrayImage(ESanteGuiUtils.getESanteIcon(ESanteGuiUtils.SMALLPIX)));
			openWithoutESanteInNewTab.addActionListener(new ActionListener()
			{
				public void actionPerformed (ActionEvent e)
				{
					loadPatient(true, new String[] { ESanteTab.TAB_NAME });
				}
			});
			popup.add(openWithoutESanteInNewTab);
			
			
			this.connectionPatientAction	= new JMenuItem(new PdqAction(this));
			popup.add(this.connectionPatientAction);
			
			this.disconnectPatientAction	= new JMenuItem(new RemoveESanteIdAction(this));
			popup.add(disconnectPatientAction);
		}
		
		/* ------------------------------------------------------- */
		// Export Patient
		JMenuItem exportPatient = new JMenuItem(Translatrix.getTranslationString("pm.exportPatient"), 
				GECAMedModule.getSmallIcon(GECAMedIconNames.EXPORT));
		exportPatient.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				try {
					ArrayList<Integer> exportPatient = new ArrayList<Integer>();
					Integer pId = patientListTableModel.getPatientIDforRow(tableSorter.modelIndex(patientTable.getSelectedRow()));
					exportPatient.add(pId);
					ExportDialog exportdialog = new ExportDialog(null, exportPatient);
					exportdialog.setOptions(PatientExportPanel.exportDialogOptions);
					exportdialog.setStartDirectory(PatientExportPanel.startDirectory);
					exportdialog.showCenteredDialog();
					PatientExportPanel.exportDialogOptions = exportdialog.getOptions();
					PatientExportPanel.startDirectory = exportdialog.getStartDirectory();					
				} catch (Exception e2) {
					logger.warn("Error Exporting Patient!", e2);
				}
			}
		});
		popup.add(exportPatient); 
		
		/* ------------------------------------------------------- */
		
		/* ------------------------------------------------------- */
		// add a patient to the PatientExportPanel
		JMenuItem addToExportPanel = new JMenuItem(Translatrix.getTranslationString("patientExport.addToExport"), 
				GECAMedModule.getSmallIcon(GECAMedIconNames.DO));
		addToExportPanel.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				addToPatientExportPanel();
			}
		});
		popup.add(addToExportPanel); // TODO activated ExportPanel
		/* ------------------------------------------------------- */
		// only if user has the right to delete patients
		// delete patient menu item
		if (GECAMedModule.userHasPermission(IPatientPermissions.DELETE_PATIENT))
		{
			/* ------------------------------------------------------- */
			JMenuItem deletePatient = new JMenuItem(Translatrix.getTranslationString("pm.deletePatient"), GECAMedModule.getSmallIcon(GECAMedIconNames.REMOVE));
			
			deletePatient.addActionListener(new ActionListener()
			{
				
				public void actionPerformed(ActionEvent e)
				{
					/* ====================================================== */
					deleteSelectedPatient();
					/* ====================================================== */
				}
				
			});
			/* ------------------------------------------------------- */
			popup.add(new JSeparator());
			popup.add(deletePatient);
		}
		/* ------------------------------------------------------- */
		
		// enable sorting the table
		this.tableSorter.setTableHeader(this.patientTable.getTableHeader());
		jsp = new JScrollPane(this.patientTable);
		jsp.setOpaque(false);
		jsp.getViewport().setOpaque(false);
		jsp.setAutoscrolls(true);
		jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		
		
		this.add(jsp, BorderLayout.CENTER);
		PatientSearchTableHeader sth = new PatientSearchTableHeader(patientTable);
		sth.addPropertyChangeListener(this);
		
		// load selected patient on ENTER
		this.patientTable.addKeyListener(new KeyListener()
		{
			
			public void keyTyped(KeyEvent e)
			{
				if (e.getKeyCode() == KeyEvent.VK_ENTER)
					e.consume();
			}
			
			
			public void keyPressed(KeyEvent e)
			{
				if (e.getKeyCode() == KeyEvent.VK_ENTER)
					e.consume();
			}
			
			
			public void keyReleased(KeyEvent e)
			{
				if (e.getKeyCode() == KeyEvent.VK_ENTER)
				{
					e.consume();
					loadPatient((Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.OPEN_PATIENT_IN_NEW_TAB));
				}
			}
		});
				
		SearchFieldListener searchFieldKeyListener = new SearchFieldListener();		
		
		// searchfield for name, ssn
		this.searchTextField = new JTextField(30);
		this.searchTextField.setDocument(new UnaccentDocument());
		this.searchTextField.setToolTipText(Translatrix.getTranslationString("pm.searchHelp"));
		this.searchTextField.addCaretListener(searchFieldKeyListener);
		this.searchTextField.addKeyListener(searchFieldKeyListener);
		
		// searchfield for phone, address
		this.searchAddressPhoneField = new JTextField(15);
		this.searchAddressPhoneField.setToolTipText(Translatrix.getTranslationString("pm.searchHelp"));
		this.searchAddressPhoneField.addCaretListener(searchFieldKeyListener);
		this.searchAddressPhoneField.addKeyListener(searchFieldKeyListener);
		
		// listener for matriculefield
		this.searchMatriculeField = new JTextField(15);
		this.searchMatriculeField.setToolTipText(Translatrix.getTranslationString("pm.searchMatricule"));
		this.searchMatriculeField.setDocument(new UnaccentDocument());
		this.searchMatriculeField.addCaretListener(searchFieldKeyListener);
		this.searchMatriculeField.addKeyListener(searchFieldKeyListener);
		
		// JLabels
		this.l1 = new JLabel(Translatrix.getTranslationString("pm.socialNumber") + ":");
		this.l2 = new JLabel(Translatrix.getTranslationString("list.Names"));
		this.l3 = new JLabel(Translatrix.getTranslationString("list.AddresPhone"));
		
		
		// action to show the searchpanel
		searchPatientAction = new GECAMedAction(this.patientListModule, "pm.searchPatient", GECAMedModule.getIcon(GECAMedIconNames.SEARCH), 0, false, true, false)
		{
			private static final long	serialVersionUID	= 1L;
			
			
			public void actionPerformed(ActionEvent p_Event)
			{
				MainFrame.getInstance().selectModule(patientListModule.getName());
			}
		};
		searchPatientAction.putValue(Action.SHORT_DESCRIPTION, Translatrix.getTranslationString("pm.searchPatient"));
		
		// action to select the previous patient
		previousAction = new GECAMedAction(this.patientListModule, "list.previousPatient", PatientManagerModule.getIcon(PatientManagerModule.PATIENT_PREVIOUS), 0, false, true, false)
		{
			private static final long	serialVersionUID	= 1L;
			
			
			public void actionPerformed(ActionEvent p_Event)
			{
				new Thread()
				{
					public void run()
					{
						int row = patientTable.getSelectedRow() - 1;
						try
						{
							if (row < 0)
							{
								MainFrame.getInstance().showMessage(Translatrix.getTranslationString("list.noPreviousPatient"));
								if ((Boolean) MainFrame.getInstance().userSettings.getValue(UserSettingsPlugin.SOUND_ENABLED))
									Toolkit.getDefaultToolkit().beep();
							}
							patientTable.setRowSelectionInterval(row, row);
							
							startOpenPatientTask();
							// loadPatient((Boolean)
							// patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.OPEN_PATIENT_IN_NEW_TAB));
							
						}
						catch (Exception ee)
						{
						}
					}
					
				}.start();
			}
		};
		
		// action to select the next patient
		nextAction = new GECAMedAction(this.patientListModule, "list.nextPatient", PatientManagerModule.getIcon(PatientManagerModule.PATIENT_NEXT), 0, false, true, false)
		{
			private static final long	serialVersionUID	= 1L;
			
			
			public void actionPerformed(ActionEvent p_Event)
			{
				new Thread()
				{
					public void run()
					{
						int row = patientTable.getSelectedRow() + 1;
						try
						{
							if (row >= patientListTableModel.getRowCount())
							{
								MainFrame.getInstance().showMessage(Translatrix.getTranslationString("list.noNextPatient"));
								if ((Boolean) MainFrame.getInstance().userSettings.getValue(UserSettingsPlugin.SOUND_ENABLED))
									Toolkit.getDefaultToolkit().beep();
							}
							patientTable.setRowSelectionInterval(row, row);
							
							startOpenPatientTask();
							// loadPatient((Boolean)
							// patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.OPEN_PATIENT_IN_NEW_TAB));
							
						}
						catch (Exception ee)
						{
						}
					}
				}.start();
			}
		};
		
		
		// action to clear the search
		clearAction = new GECAMedAction(this.patientListModule, "list.clear", GECAMedModule.getSmallIcon(GECAMedIconNames.EDIT_CLEAR_RTL), 0, false, true, false, KEY_CLEAR)
		{
			private static final long	serialVersionUID	= 1L;
			
			
			public void actionPerformed(ActionEvent p_Event)
			{
				searchMatriculeField.setText("");
				searchTextField.setText("");
				searchAddressPhoneField.setText("");
				if (MATRICULE_SEARCH)
					searchMatriculeField.requestFocus();
				else
					searchTextField.requestFocus();
				searchPatients(false, false);
			}
		};
		clearAction.add();
		
		// action to reload the search
		reloadAction = new GECAMedAction(this.patientListModule, "list.reload", GECAMedModule.getIcon(GECAMedIconNames.RELOAD), 0, false, true, false, KEY_RELOAD)
		{
			private static final long	serialVersionUID	= 1L;
			
			public void actionPerformed(ActionEvent p_Event)
			{
				setWaitCursor(true);
				searchPatients(true, false);
				setWaitCursor(false);
			}
		};
		reloadAction.add();
		
		// register the global hotkeys
		RegistrationDesk.registerHotKey(KEY_SEARCH, searchPatientAction);
		RegistrationDesk.registerHotKey(KEY_PREVIOUS, previousAction);
		RegistrationDesk.registerHotKey(KEY_NEXT, nextAction);
		
		
		try
		{
			// eval PATIENTSEARCH: argument (for devel. purpose)
			String[] commands = LoginScreen.getInstance().commandlineArgs;
			if (commands != null)
			{
				for (int i = 0; i < commands.length; i++)
				{
					String command = commands[i];
					String[] commandline = command.split(":");
					if (commandline[0].equalsIgnoreCase("PATIENTSEARCH"))
					{
						String[] searchArray = command.split(":");
						String search;
						if (searchArray.length > 1)
							search = searchArray[1];
						else
							search = "";
						this.searchTextField.setText(search);
					}
					else if (commandline[0].equalsIgnoreCase("PATIENTMATRICULESEARCH") && MATRICULE_SEARCH)
					{
						String[] searchArray = command.split(":");
						String search;
						if (searchArray.length > 1)
							search = searchArray[1];
						else
							search = "";
						this.searchMatriculeField.setText(search);
					}
				}
			}
		}
		catch (Exception e)
		{
			logger.warn("Couldn't use module load parameters", e);
		}
		
		
		// start an inital patient search to display a list of patients
		try
		{
			if (!(Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.START_WITH_EMPTY_LIST))
			{
				new Thread()
				{
					public void run()
					{
						searchPatients(true, false);
					}
				}.start();
			}
		}
		catch (Exception e)
		{
		}
		
		// TODO suspended for now....
		// // start listener for JMS
		// this.recieveJMS();
		
	}
	
	
	/**
	 * Start a search of a Patient
	 * @param commands
	 */
	public void searchPatient(String[] commands)
	{
		try
		{ // eval PATIENTSEARCH: argument (for devel. purpose)
			//String[] commands = LoginScreen.getInstance().commandlineArgs;
			if (commands != null)
			{
//				System.out.println("serach:" + commands);
				for (int i = 0; i < commands.length; i++)
				{
					String command = commands[i];
					String[] commandline = command.split(":");
					
//					System.out.println("in for serach: " + command);
					if (commandline[0].equalsIgnoreCase("PATIENTSEARCH"))
					{
						String search = command.split(":")[1];
//						System.out.println("search: " + search);
						this.searchTextField.setText(search);
					}
					else if (commandline[0].equalsIgnoreCase("PATIENTMATRICULESEARCH"))
					{
						String search = command.split(":")[1];
//						System.out.println("search: " + search);
						this.searchTextField.setText(search);
					}
				}
			}
		}
		catch (Exception e)
		{
			logger.error("Error while initializing patient search via command line arguments.", e);
		}
		
		
		// start an inital patient search to display a list of patients
		try
		{
			if (!(Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.START_WITH_EMPTY_LIST))
			{
				new Thread()
				{
					public void run()
					{
						searchPatients(true, false);
					}
				}.start();
			}
		}
		catch (Exception e)
		{
			logger.error("Error while starting patient search, initilized by command line arguments.", e);
		}
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.
	 * PropertyChangeEvent)
	 */
	public void propertyChange(PropertyChangeEvent evt)
	{
		if (evt.getNewValue().equals(""))
		{
			filter = "";
			searchPatients(false, false);
			return;
		}
		// System.out.println("Search for column " + evt.getSource()+ " ("+
		// evt.getPropertyName() +") with value: " + evt.getNewValue());
		int column = (Integer) evt.getSource();
		switch (column)
		{
			case 0:
				filter = "patient.socialSecurityNumber LIKE '" + evt.getNewValue() + "%'";
				break;
			case 1:
				filter = "UPPER(patient.surName) LIKE UPPER('%" + evt.getNewValue() + "%')";
				break;
			case 2:
				filter = "UPPER(patient.maidenName) LIKE UPPER('%" + evt.getNewValue() + "%')";
				break;
			case 3:
				filter = "UPPER(patient.firstName) LIKE UPPER('%" + evt.getNewValue() + "%')";
				break;
			case 4:
				filter = "UPPER(patient.gender) LIKE UPPER('" + evt.getNewValue() + "%')";
				break;
			case 5:
				filter = "";
				try
				{
					Collection<Insurance> insurances = insuranceManager.findInsurancesByAcronym((String) evt.getNewValue());
					for (Iterator<Insurance> iter = insurances.iterator(); iter.hasNext();)
					{
						Insurance element = iter.next();
						if (filter != "")
						{
							filter += " OR ";
						}
						filter += " (patient.insuranceID = " + element.getId() + " ) ";
					}
				}
				catch (Exception e1)
				{
					logger.log(Level.WARN, "find insurance failed", e1);
				}
				break;
			case 6:
				filter = "";
				String addrSearch = (String) evt.getNewValue();
				String[] addrSearchParts = addrSearch.split(" ");
				for (int i = 0; i < addrSearchParts.length; i++)
				{
					try
					{
						Long.parseLong(addrSearchParts[i]);
						if (filter != "")
						{
							filter += " AND ";
						}
						filter += " (UPPER(address.zip) LIKE UPPER('" + addrSearchParts[i] + "%') ) ";
					}
					catch (Exception e)
					{
						if (filter != "")
						{
							filter += " AND ";
						}
						filter += " (UPPER(address.locality) LIKE UPPER('%" + evt.getNewValue() + "%') ) OR " + " (UPPER(address.streetName) LIKE UPPER('%" + evt.getNewValue() + "%') )";
					}
				}
				break;
			case 7:
				filter = "";
				try
				{
					String status = ((String) evt.getNewValue()).toUpperCase();
					for (int i = 0; i < Patient.STATES.length; i++)
					{
						if (Patient.STATES[i].equals(status))
						{
							filter += " (patient.status = " + i + " ) ";
						}
					}
				}
				catch (Exception e1)
				{
					e1.printStackTrace();
				}
				break;
			
			case 9:
				filter = "patient.id LIKE '" + evt.getNewValue() + "%'";
				break;
			default:
				break;
		}
		searchPatients(false, false);
	}
	
	
	/**
	 * Reload the patient list. Is the same as searchPatient(true);
	 * 
	 */
	public void reloadList()
	{
		/* ================================================== */
		this.searchPatients(true, false);
		/* ================================================== */
	}
	
	
	/**
	 * start a new patientsearch with the searchstring from the searchfield
	 * 
	 * @param force
	 *            true to force a new search
	 */
	public synchronized void searchPatients(boolean force, boolean openPatient)
	{
		
		boolean ssecSearch = false;
		long start = System.currentTimeMillis();
		
		String searchNameText = "";
		String searchAddressText = "";
		if (MATRICULE_SEARCH && this.searchMatriculeField.getText() != null && !"".equals(this.searchMatriculeField.getText()))
		{
			searchNameText = searchMatriculeField.getText();
			ssecSearch = true;
		}
		else
		{
			searchNameText = searchTextField.getText();
			searchAddressText = searchAddressPhoneField.getText();
		}
		
		
		this.searchRunning = true;
		
		this.setWaitCursor(true);
		
		
		// store selected patient
		int currPatient = this.patientListTableModel.getPatientIDforRow(tableSorter.modelIndex(this.patientTable.getSelectedRow()));
		
		// get number of minimum search characters
		int minChars = (Integer) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.MIN_SEARCH_CHARS);
		// if num of chars is ok, start the search
		if (searchNameText.length() >= minChars || searchAddressText.length() >= minChars || filter != "")
		{
			completeList = false;
			// long now = System.currentTimeMillis();
			try
			{
				// run the search on the db.......
				if (ssecSearch)
				{
					patientListTableModel.setPatients(new ArrayList<PatientStub>(manager.getPatientStubListBySSec(searchNameText, (Integer) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.SEARCH_LIMIT))));
				}
				else
				{
					patientListTableModel.setPatients(new ArrayList<PatientStub>(
							manager.getPatientStubListBySearchString(searchNameText, searchAddressText, filter, 
									(Integer) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.SEARCH_LIMIT))));
				}
				try
				{
					try
					{
						// reselect the last selected patient.
						int row = tableSorter.viewIndex(patientListTableModel.getRowForPatientID(currPatient));
						patientTable.setRowSelectionInterval(row, row);
					}
					catch (Exception e)
					{
						try
						{
							patientTable.setRowSelectionInterval(0, 0);
						}
						catch (Exception e2)
						{
						}
					}
				}
				catch (Exception e)
				{
				}
			}
			catch (Exception e1)
			{
				MainFrame.reportServerError(e1);
				this.searchRunning = false;
			}
		}
		else if (force || !completeList)
		{
			completeList = true;
			try
			{
				// loading complete list
				patientListTableModel.setPatients(new ArrayList<PatientStub>(manager.getPatientStubListBySearchString("", "", filter, (Integer) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.SEARCH_LIMIT))));
				try
				{
					// reselect the last selected patient.
					int row = tableSorter.viewIndex(patientListTableModel.getRowForPatientID(currPatient));
					patientTable.setRowSelectionInterval(row, row);
				}
				catch (Exception e)
				{
					try
					{
						patientTable.setRowSelectionInterval(0, 0);
					}
					catch (Exception e2)
					{
					}
				}
			}
			catch (Exception e1)
			{
				MainFrame.reportServerError(e1);
				this.searchRunning = false;
			}
		}
		
		// search finished
		this.setWaitCursor(false);
		this.searchRunning = false;
		// logger.info("finished search: " + searchtext);
		
		long took = (System.currentTimeMillis() - start);
		GECAMedLog.user(PatientListModule.MODULE_NAME, PatientManagerModule.SEARCH_PATIENT, "Search for \"" + searchNameText + " returned " + patientListTableModel.getRowCount() + " results " + "\" took " + took + "ms", took);
		
		// if Matricule Search returned 1 result, open the patient directly
		if (openPatient && ssecSearch && patientListTableModel.getRowCount() == 1)
			loadPatient((Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.OPEN_PATIENT_IN_NEW_TAB));
	}
	
	
	public synchronized boolean isSearchRunning()
	{
		return this.searchRunning;
	}
	

	/**
	 * load the patient
	 * 
	 * @param inNewTab
	 *            if true patient is loaded in a new tab.
	 */
	private void loadPatient (boolean inNewTab)
	{
		loadPatient(inNewTab, null);
	}
	
	
	private void loadPatient (boolean inNewTab, String[] disabledTabs)
	{
		// wait for search finished
		if (searchRunning)
		{
			MainFrame.getInstance().showMessage(Translatrix.getTranslationString("pm.searchingPleaseWait"));
			return;
		}
		
		int patientID = -1;
		if (this.patientTable.getSelectedRow() == -1)
		{
			logger.info("unable to open patient: No patient selected");
			return;
		}
		
		// if search has been done in the search module, open the last selected
		// module
		if (patientListModule.getName().equals(MainFrame.getInstance().getSelectedModule()))
		{
			// get the last selected module
			String moduleName = (String) patientListModule.patientListSettingsPlugin
					.getValue(PatientSearchSettingsPlugin.OPEN_PATIENT_IN_MODULE);
			if (moduleName.equals(GECAMedModule.LAST_SELECTED_MODULE))
			{
				if (MainFrame.getInstance().lastModule != null && MainFrame.getInstance().lastModule.canDisplayPatient())
					moduleName = MainFrame.getInstance().lastModule.getName();
				else
					moduleName = PatientManagerModule.MODULE_NAME;
			}
			// System.out.println("switch Module: " + moduleName);
			MainFrame.getInstance().selectModule(moduleName);
		}
		
		try
		{
			// now we load the patient!
			patientID = this.patientListTableModel.getPatientIDforRow(
					this.tableSorter.modelIndex(this.patientTable.getSelectedRow()));
			this.patientManagerModule.addPatient(this.manager.getPatient(patientID), inNewTab, disabledTabs);
		}
		catch (Exception e1)
		{
			logger.info("unable to open patient with ID: " + patientID);
			// log
			GECAMedLog.error(PatientListModule.MODULE_NAME, OPEN_PATIENT, 
					"unable to open patient with ID: " + patientID, null);
		}
	}
	
	/**
	 * Add a patient to the PatientenExportPanel. Will add the selected one
	 */
	private void addToPatientExportPanel()
	{
		Integer pId = patientListTableModel.getPatientIDforRow(tableSorter.modelIndex(patientTable.getSelectedRow()));
		patientListModule.getPatientExportPanel().addPatient(pId);
	}
	
	/**
	 * DELETES a patient from the system. Will take the selected one.
	 */
	private void deleteSelectedPatient()
	{
		/* ------------------------------------------------------- */
		if (patientTable.getSelectedRow() > -1)
		{
			Integer pId = patientListTableModel.getPatientIDforRow(this.tableSorter.modelIndex(patientTable.getSelectedRow()));
			/* ------------------------------------------------------- */
			// open a popup to aks if the patient really should be deleted.
			boolean b = SecurityQuestionDialog.getInstance().showDialog();
			if (b)
			{
				/* ------------------------------------------------------- */
				// delete
				/* ------------------------------------------------------- */
				PatientAdminInterface pManager = (PatientAdminInterface) ManagerFactory.getRemote(PatientAdminBean.class);
				try
				{
					pManager.deletePatient(pId);
					/* ------------------------------------------------------- */
					MainFrame.getInstance().showMessage(Translatrix.getTranslationString("pm.deletingPatientConfirm"));
					// reload the list
					this.reloadList();
					/* ------------------------------------------------------- */
					// close an open patientfile
					/* ------------------------------------------------------- */
					PatientManagerModule.getInstance().closePatient(pId);
					/* ------------------------------------------------------- */
					
				}
				catch (Exception e)
				{
					ErrorDialog.showErrorDialog(MainFrame.getInstance(), "Error deleting Patient", e.getMessage(), e);
				}
				
			}
			/* ------------------------------------------------------- */
		}
		/* ------------------------------------------------------- */
	}
	
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
	 */
	public void mouseClicked(MouseEvent e)
	{
		if ((e.getClickCount() >= 2) && this.patientTable.equals(e.getSource()))
		{
			loadPatient((Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.OPEN_PATIENT_IN_NEW_TAB));
		}
		else if (e.isPopupTrigger())
		{
			showPopup(e);
		}
		else if (e.getButton() == MouseEvent.BUTTON2)
		{
			int row = patientTable.rowAtPoint(e.getPoint());
			patientTable.setRowSelectionInterval(row, row);
			loadPatient(true);
		}
	}
	
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
	 */
	public void mousePressed(MouseEvent e)
	{
		if (e.isPopupTrigger())
		{
			showPopup(e);
		}
	}
	
	
	public void showPopup (MouseEvent e)
	{
		int row = patientTable.rowAtPoint(e.getPoint());
		patientTable.setRowSelectionInterval(row, row);
		if (ESanteGuiUtils.isESanteModuleActivated())
		{
			Object eSanteId = this.patientListTableModel.getValueAt(
					this.tableSorter.modelIndex(this.patientTable.getSelectedRow()), 
					PatientListPanel.COLUMN_ESANTE);
			
			connectionPatientAction.setVisible(eSanteId == null);
			disconnectPatientAction.setVisible(eSanteId != null);
			openWithoutESante.setVisible(eSanteId != null);
			openWithoutESanteInNewTab.setVisible(eSanteId != null);
		}
		
		popup.show(e.getComponent(), e.getX(), e.getY());
	}
	
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
	 */
	public void mouseReleased(MouseEvent e)
	{
		if (e.isPopupTrigger())
		{
			showPopup(e);
		}
	}
	
	
	public void mouseEntered(MouseEvent e)
	{
	}
	
	
	public void mouseExited(MouseEvent e)
	{
	}
	
	
	public JComponent getSearchComponent()
	{
		CellConstraints cc = new CellConstraints();
		
		JPanel jp = new JPanel(new FormLayout("pref, 2dlu, pref:grow, 2dlu, pref", "pref, pref"));
		jp.setOpaque(false);
		if (MATRICULE_SEARCH)
		{
			l1.setOpaque(false);
			jp.add(l1, cc.xy(1, 1));
			jp.add(this.searchMatriculeField, cc.xy(1, 2));
		}
//		JLabel l2 = new JLabel(Translatrix.getTranslationString("list.Names"));
		//l2.setOpaque(false);
		jp.add(this.l2, cc.xy(3, 1));
		jp.add(this.searchTextField, cc.xy(3, 2));
//		JLabel l3 = new JLabel(Translatrix.getTranslationString("list.AddresPhone"));
		//l3.setOpaque(false);
		jp.add(this.l3, cc.xy(5, 1));
		jp.add(this.searchAddressPhoneField, cc.xy(5, 2));
		return jp;
	}
	
	
	/**
	 * set the focus to the searchfield
	 */
	public void setFocus()
	{
		if (MATRICULE_SEARCH)
		{
			this.searchMatriculeField.selectAll();
			this.searchMatriculeField.requestFocus();
		}
		else
		{
			this.searchTextField.selectAll();
			this.searchTextField.requestFocus();
		}
	}
	
	
	/**
	 * sets the Mousecursor of the MainFrame to a WaitCursor and Back
	 * 
	 * @param on
	 *            true=waitcursor false=normalcursor
	 */
	public void setWaitCursor(boolean on)
	{
		if (on)
		{
			this.jsp.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
			this.patientTable.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
			this.searchTextField.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
			this.searchAddressPhoneField.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
			this.searchMatriculeField.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		}
		else
		{
			this.jsp.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			this.patientTable.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			this.searchTextField.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			this.searchAddressPhoneField.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			this.searchMatriculeField.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		}
	}
	
	
	/**
	 * generates the ToolTip for the previous patient button
	 * 
	 * @param row
	 * @return
	 */
	public String buildPreviousPatientToolTip(int row)
	{
		return "<html><h2>" + Translatrix.getTranslationString("list.previousPatient") + " (" + KeyEvent.getKeyText(KEY_PREVIOUS) + "):  </h2> <h3>" + patientListTableModel.getValueAt(row, 1) + ", " + patientListTableModel.getValueAt(row, 3) + "<br> " + patientListTableModel.getValueAt(row, 0)
				+ "</h3>";
	}
	
	
	/**
	 * generates the ToolTip for the next patient button
	 * 
	 * @param row
	 * @return
	 */
	public String buildNextPatientToolTip(int row)
	{
		return "<html><h2>" + Translatrix.getTranslationString("list.nextPatient") + " (" + KeyEvent.getKeyText(KEY_NEXT) + "):  </h2> <h3>" + patientListTableModel.getValueAt(row, 1) + ", " + patientListTableModel.getValueAt(row, 3) + "<br> " + patientListTableModel.getValueAt(row, 0) + "</h3>";
	}
	
	
	/**
	 * sets the text to the next/previous patient button
	 */
	public void setPatientButtons()
	{
		
		int row = patientTable.getSelectedRow();
		if (row != -1)
		{
			row = this.tableSorter.modelIndex(row);
		}
		
		boolean prefEnabled = true;
		String prev = buildPreviousPatientToolTip(row - 1);
		boolean nextEnabled = true;
		String next = buildNextPatientToolTip(row + 1);
		if (row <= 0)
		{
			prefEnabled = false;
			prev = "<html><h2>" + Translatrix.getTranslationString("list.previousPatient") + " (" + KeyEvent.getKeyText(KEY_PREVIOUS) + "):  </h2>";
		}
		if (row >= patientListTableModel.getRowCount() - 1)
		{
			nextEnabled = false;
			next = "<html><h2>" + Translatrix.getTranslationString("list.nextPatient") + " (" + KeyEvent.getKeyText(KEY_NEXT) + "):  </h2>";
		}
		
		previousAction.setEnabled(prefEnabled);
		previousAction.putValue(Action.SHORT_DESCRIPTION, prev);
		
		nextAction.setEnabled(nextEnabled);
		nextAction.putValue(Action.SHORT_DESCRIPTION, next);
		
	}
	
	
	public GECAMedAction getClearAction ()
	{
		return clearAction;
	}
	
	
	public GECAMedAction getReloadAction ()
	{
		return reloadAction;
	}
	
	
	/**
	 * Threaded task for the search
	 * 
	 * @author Johannes Hermen johannes.hermen(at)tudor.lu
	 * 
	 * @version <br>
	 *          $Log: PatientListPanel.java,v $
	 *          Revision 1.131  2014-01-21 06:29:31  ferring
	 *          checking parameters on length and emptiness
	 *
	 *          Revision 1.130  2013-12-13 15:26:27  troth
	 *          *** empty log message ***
	 *
	 *          Revision 1.129  2013-11-21 09:44:52  ferring
	 *          auto resizing of patient search list
	 *
	 *          Revision 1.128  2013-10-16 13:03:47  ferring
	 *          some small esante bugfixes
	 *
	 *          Revision 1.127  2013-10-08 08:59:23  ferring
	 *          class name refactoring and tree view implementation (first steps)
	 *
	 *          Revision 1.126  2013-07-15 06:18:35  ferring
	 *          logging changed
	 *
	 *          Revision 1.125  2013-07-09 06:48:01  ferring
	 *          Nullpointer when eSante was deactiviated
	 *
	 *          Revision 1.124  2013-07-03 13:06:35  ferring
	 *          eSante module handling changed
	 *
	 *          Revision 1.123  2013-06-24 12:58:50  ferring
	 *          eSante functions in PatientListPanel are only shown, if eSante is loaded. And either the connect or the disconnect option is shown
	 *
	 *          Revision 1.122  2013-06-10 08:22:02  ferring
	 *          eSante POC
	 *
	 *          Revision 1.121  2013-04-16 13:42:10  ferring
	 *          *** empty log message ***
	 *
	 *          Revision 1.120  2013-04-09 07:37:30  ferring
	 *          Patient search unaccented
	 *
	 *          Revision 1.119  2013-03-20 10:41:19  troth
	 *          Add translation. Add icon to popup.
	 *
	 *          Revision 1.118  2013-03-11 14:37:28  troth
	 *          Add column with physician.
	 *
	 *          Revision 1.117  2013-03-05 14:48:24  troth
	 *          Add ProgressBar in export dialog.
	 *
	 *          Revision 1.116  2013-02-25 10:51:52  troth
	 *          Remove some system.out.println.
	 *
	 *          Revision 1.115  2013-02-25 10:32:17  troth
	 *          Add function to add patients from the patientsearch tab the patientexport tab.
	 *
	 *          Revision 1.114  2013-02-21 14:14:22  ferring
	 *          Improved the security dialog layout in order to fix it for linux
	 *
	 *          Revision 1.113  2013-02-19 10:04:34  troth
	 *          Change the search button, add the the export dialog button, to some GUI design and clear up code.
	 *
	 *          Revision 1.111  2013-01-23 16:50:50  troth
	 *          add new GUI for the MM Export tab the PatientExportPanel.
	 *
	 *          Revision 1.110  2013-01-10 12:54:46  ferring
	 *          system exit method changed
	 *
	 *          Revision 1.109  2012-10-19 16:24:42  troth
	 *          First version of GECAMed launcher.
	 *
	 *          Revision 1.108  2012-03-06 14:53:52  ferring
	 *          formatting fixed
	 * <br>
	 *          Revision 1.107 2011-08-22 13:12:47 ferring <br>
	 *          Warnings removed <br>
	 * <br>
	 *          Revision 1.106 2010-08-26 14:28:04 ferring <br>
	 *          additional options for main arguments added <br>
	 * <br>
	 *          Revision 1.105 2010-08-26 13:33:51 hermen <br>
	 *          added commandline arg PATIENTSEARCH: <br>
	 * <br>
	 *          Revision 1.104 2010-06-24 11:55:09 hermen <br>
	 *          version 1.1 <br>
	 * <br>
	 *          Revision 1.103 2010-05-12 08:58:37 hermen <br>
	 *          cleanup <br>
	 * <br>
	 *          Revision 1.102 2010-05-04 14:23:39 hermen <br>
	 *          suspended autoreload of patientlist <br>
	 * <br>
	 *          Revision 1.101 2010-05-03 13:45:21 hermen <br>
	 *          enhanced logging <br>
	 * <br>
	 *          Revision 1.100 2010-04-27 15:11:51 mack <br>
	 *          Minor improvement <br>
	 * <br>
	 *          Revision 1.99 2010-04-08 10:56:40 hermen <br>
	 *          enhanced logging <br>
	 * <br>
	 *          Revision 1.98 2010-04-06 15:37:23 hermen <br>
	 *          changed logging <br>
	 * <br>
	 *          Revision 1.97 2010-03-12 14:17:42 hermen <br>
	 *          cleanup of panel layouts and icons <br>
	 * <br>
	 *          Revision 1.96 2009-12-14 15:34:19 hermen <br>
	 *          fixed patient loading via F6/F7 <br>
	 * <br>
	 *          Revision 1.95 2008-10-21 09:53:34 hermen <br>
	 *          fixed patient slot bug <br>
	 *          enhanced logging <br>
	 *          code cleanup <br>
	 * <br>
	 *          Revision 1.94 2008-09-25 09:43:07 heinemann <br>
	 *          fixed copyrights <br>
	 * <br>
	 *          Revision 1.93 2008-09-15 09:18:35 heinemann <br>
	 *          included deletion of patient files in patient delete process. <br>
	 * <br>
	 *          Revision 1.92 2008-09-04 14:54:22 heinemann <br>
	 *          *** empty log message *** <br>
	 * <br>
	 *          Revision 1.91 2008-08-29 10:27:58 heinemann <br>
	 *          Ticket #167 (closed task: fixed) <br>
	 *          Close patient file of deleted patient <br>
	 * <br>
	 *          Revision 1.90 2008-06-12 11:44:56 hermen <br>
	 *          fixed opening patient on reload message <br>
	 * <br>
	 *          Revision 1.89 2008-06-09 09:07:56 hermen <br>
	 *          open patient directly if ssec search returned exactly 1 result <br>
	 * <br>
	 *          Revision 1.88 2008-05-30 09:12:12 hermen <br>
	 *          added new search setting <br>
	 * <br>
	 *          Revision 1.87 2008-05-28 14:17:54 hermen <br>
	 *          only select last selected modul on open patient if this module
	 *          can display patient data <br>
	 * <br>
	 *          Revision 1.86 2008-05-28 08:24:41 heinemann <br>
	 *          *** empty log message *** <br>
	 * <br>
	 *          Revision 1.85 2008-05-27 09:09:10 hermen <br>
	 *          fixed search RETURN key behavior <br>
	 * <br>
	 *          Revision 1.84 2008-05-27 08:23:50 hermen <br>
	 *          fixed search in dialog and added new setting <br>
	 * <br>
	 *          Revision 1.83 2008-04-30 12:18:38 hermen <br>
	 *          initial checkin of Addressbook module <br>
	 * <br>
	 *          Revision 1.82 2008-04-28 08:05:48 hermen <br>
	 *          changed patient search to use patient_stub view and bean <br>
	 * <br>
	 *          Revision 1.81 2008-04-16 08:15:42 hermen <br>
	 *          fixed font in patient search <br>
	 * <br>
	 *          Revision 1.80 2008-04-14 08:11:58 hermen <br>
	 *          added option to use big fonts for patient seatrch and
	 *          reorganized search settings <br>
	 * <br>
	 *          Revision 1.79 2008-04-03 15:03:01 hermen <br>
	 *          fixed matricule query <br>
	 * <br>
	 *          Revision 1.78 2008-01-23 08:30:09 hermen <br>
	 *          *** empty log message *** <br>
	 * 
	 */
	class SearchTask extends TimerTask
	{
		@Override
		public void run()
		{
			searchPatients(false, true);
		}
	}
	
	
	class OpenPatientTask extends TimerTask
	{
		@Override
		public void run()
		{
			loadPatient((Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.OPEN_PATIENT_IN_NEW_TAB));
		}
	}
	
	
	private void startOpenPatientTask()
	{
		if (openPatientTaskTimer != null)
		{
			// System.out.println("Cancel " + openPatientTaskTimer.hashCode());
			openPatientTaskTimer.cancel();
		}
		openPatientTaskTimer = new Timer();
		openPatientTaskTimer.schedule(new OpenPatientTask(), 200);
		// System.out.println("Schedule " + openPatientTaskTimer.hashCode());
	}
	
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JComponent#paint(java.awt.Graphics)
	 */
	@Override
	public void paint(Graphics g)
	{
		if (GECAMedUtils.isDemo())
		{
			g.setColor(new Color(0, 0, 0, 100));
			g.setFont(bgFont);
			g.drawString(Translatrix.getTranslationString("core.demo"), 200, 350);
		}
		super.paint(g);
	}
	
	
	/* ======================================== */
	// 		CLASS: SearchFieldListener
	/* ======================================== */
	private class SearchFieldListener implements CaretListener, KeyListener
	{
		/* ======================================== */
		// 		MEMBERS
		/* ======================================== */
		
		private String	ssnSearchText;
		
		private String	nameSearchText;
		
		private String	addressSearchText;
		
		
		
		/* ======================================== */
		// 		CLASS BODY
		/* ======================================== */
		
		public void caretUpdate(CaretEvent e)
		{
			String	oldSearchString;
			
			
			if (!e.getSource().equals(searchMatriculeField))
			{
				// reset the matricule field if there is some text in the
				// otgher fields
				searchMatriculeField.setText("");
			}
			
			if (e.getSource().equals(searchMatriculeField))
			{
				oldSearchString		= ssnSearchText;
				ssnSearchText		= ((JTextComponent)e.getSource()).getText();
			} 
			else if (e.getSource().equals(searchTextField))
			{
				oldSearchString		= nameSearchText;
				nameSearchText		= ((JTextComponent)e.getSource()).getText();
			}
			else if (e.getSource().equals(searchAddressPhoneField))
			{
				oldSearchString		= addressSearchText;
				addressSearchText	= ((JTextComponent)e.getSource()).getText();
			}
			else 
			{
				logger.log(Level.WARN, "Unsupported textfield in class "+this.getClass());
				return;
			}
			
			if (oldSearchString == null || !oldSearchString.equals(((JTextComponent)e.getSource()).getText()))
			{
				if ((Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.START_SEARCH_AUTOMATIC))
				{
					// start the search
					search((Integer) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.SEARCH_DELAY));
				}
				openPatient = false;
			}
		}
		
		
		public void keyTyped(KeyEvent e)
		{
			if (e.getKeyCode() == KeyEvent.VK_TAB)
			{
				try
				{
					((JComponent) e.getSource()).transferFocus();
				}
				catch (Exception ee)
				{
				}
			}
		}
		
		
		public void keyPressed(KeyEvent e)
		{
			/* ================================================ */
			// select next patient
			if (e.getKeyCode() == KeyEvent.VK_DOWN)
			{
				openPatient = true;
				try
				{
					int row = patientTable.getSelectedRow();
					patientTable.setRowSelectionInterval(row + 1, row + 1);
				}
				catch (Exception ee)
				{
				}
				// select prev patient
			}
			else if (e.getKeyCode() == KeyEvent.VK_UP)
			{
				openPatient = true;
				try
				{
					int row = patientTable.getSelectedRow();
					patientTable.setRowSelectionInterval(row - 1, row - 1);
				}
				catch (Exception ee)
				{
				}
				// open selected patient
			}
			else if (e.getKeyCode() == KeyEvent.VK_ENTER)
			{
				if (openPatient || (Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.START_SEARCH_AUTOMATIC))
				{
					loadPatient((Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.OPEN_PATIENT_IN_NEW_TAB));
				}
				else
				{
					search(0);
					openPatient = true;
				}
				// all other keys start new search
			}
			/* ================================================ */
		}
		
		
		public void keyReleased(KeyEvent e) {}
	}
	
	
	public void search (int delay)
	{
		if (timer != null)
		{
			timer.cancel();
		}
		timer = new Timer();
		timer.schedule(new SearchTask(), delay);
	}


	public Patient getPatientToQuery ()
	{
		try
		{
			Integer patientID = this.patientListTableModel.getPatientIDforRow(
					this.tableSorter.modelIndex(this.patientTable.getSelectedRow()));
			return this.manager.getPatient(patientID);
		}
		catch (Exception e)
		{
			logger.log(Level.ERROR, e.getMessage(), e);
			return null;
		}
	}
	
}
