/*******************************************************************************
 * 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.event.ActionEvent;
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.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

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.LoginScreen;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.utils.LineColorCellRenderer;
import lu.tudor.santec.gecamed.core.gui.utils.TableSorter;
import lu.tudor.santec.gecamed.core.gui.widgets.ModuleHeader;
import lu.tudor.santec.gecamed.core.utils.GECAMedUtils;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
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.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.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. This file was a modify copy of the PatientListPanel an it works for the new PatientSearchDialog. 
 * 
 * @author Thorsten Roth thorsten.roth(at)tudor.lu
 *
 * @version
 * <br>$Log: PatientListPanelforPatientSearchDialog.java,v $
 * <br>Revision 1.8  2013-12-27 18:09:23  donak
 * <br>Cleanup of imports
 * <br>
 * <br>Revision 1.7  2013-09-04 06:22:23  ferring
 * <br>patient search dialog extends now GECAMedBaseDialogImpl
 * <br>
 * <br>Revision 1.6  2013-07-15 06:18:35  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.5  2013-02-15 13:58:40  ferring
 * <br>unused imports removed
 * <br>
 * <br>Revision 1.4  2013-02-06 15:20:25  troth
 * <br>Remove some printStackTrace.
 * <br>
 * <br>Revision 1.3  2012-10-19 16:24:42  troth
 * <br>First version of GECAMed launcher.
 * <br>
 * <br>Revision 1.2  2012-06-20 09:53:30  troth
 * <br>Fix bug: Causes NullPointerException when the minChars for search in settings not set.
 * <br>
 * <br>Revision 1.1  2012-04-12 15:29:57  troth
 * <br>Release new search dialog panel.
 * <br>
 * <br>Revision 1.2  2012-03-14 10:21:09  troth
 * <br>Code clearup.
 * <br>
 * <br>Revision 1.1  2012-03-13 17:15:09  troth
 * <br>Add testversion of new PatientSearchDialog in first step only in the agenda GeneralPanel in the AppointmentDialog.
 * <br>
 */
public class PatientListPanelforPatientSearchDialog extends JPanel implements PropertyChangeListener, MouseListener
{
	
	private static Logger				logger					= Logger.getLogger(PatientListPanelforPatientSearchDialog.class.getName());
	
	private static final long			serialVersionUID		= 1L;
	
	/**
	 * 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;
	
	protected static final long			SEARCH_WAIT_TIMEOUT		= 300;
	
	/**
	 * show a additional searchfield for the ssn
	 */
	private boolean						MATRICULE_SEARCH		= false;
	
	public PatientStubListTableModel	patientListTableModel;
	
	private TableSorter					tableSorter;
	
	public JTable						patientTable;
	
	public PatientAdminInterface		manager;
	
	private JTextField					searchTextField;
	
	private JTextField					searchAddressPhoneField;
	
	private JTextField					searchMatriculeField;
	
	protected boolean					completeList;
	
	private String						filter					= "";
	
	private InsuranceInterface			insuranceManager;
	
	private JScrollPane					jsp;
	
	private boolean						searchRunning;
	
	private Font						bgFont					= new Font("Plain", Font.BOLD, 64);
	
	private boolean						BIG_FONTS				= false;
	
	protected boolean					openPatient;
	
	private PatientSearchDialog 	patientSearchDialog;
	
	private MainFrame mainFrame;
	
	
	public PatientListPanelforPatientSearchDialog(
			PatientSearchDialog patientSearchDialog,
			ModuleHeader moduleHeader)
	{
		this.setOpaque(false);
		
		mainFrame = MainFrame.getInstance();
		
		// show ssn search field?
		try
		{
			MATRICULE_SEARCH = (Boolean) this.mainFrame.settingsPanel.getValue(PatientSearchSettingsPlugin.NAME, PatientSearchSettingsPlugin.SEARCH_MATRICULE_FIELD);
		}
		catch (Exception e)
		{
//			e.printStackTrace();
			logger.log(Level.INFO, "Warring: Unable to get the search setting MATRICULE_SEARCH!\n", e);
		}
		
		// use big fonts?
		try
		{
			BIG_FONTS = (Boolean) this.mainFrame.settingsPanel.getValue(PatientSearchSettingsPlugin.NAME, PatientSearchSettingsPlugin.SEARCH_BIG_FONTS);
		}
		catch (Exception e)
		{
//			e.printStackTrace();
			logger.log(Level.INFO, "Warring: Unable to get the search setting BIG_FONTS!\n", e);
		}
		
		this.patientSearchDialog = patientSearchDialog;
		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 JTable(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);
		
		this.patientTable.getColumnModel().getColumn(0).setCellRenderer(renderer);
		this.patientTable.getColumnModel().getColumn(0).setMinWidth((int) (100 * factor));
		this.patientTable.getColumnModel().getColumn(1).setCellRenderer(renderer);
		this.patientTable.getColumnModel().getColumn(1).setMinWidth((int) (150 * factor));
		this.patientTable.getColumnModel().getColumn(2).setCellRenderer(renderer);
		this.patientTable.getColumnModel().getColumn(2).setMinWidth((int) (150 * factor));
		this.patientTable.getColumnModel().getColumn(3).setCellRenderer(renderer);
		this.patientTable.getColumnModel().getColumn(3).setMinWidth((int) (150 * factor));
		this.patientTable.getColumnModel().getColumn(4).setCellRenderer(centeredRenderer);
		this.patientTable.getColumnModel().getColumn(4).setMaxWidth((int) (20 * factor));
		this.patientTable.getColumnModel().getColumn(5).setCellRenderer(renderer);
		this.patientTable.getColumnModel().getColumn(5).setMinWidth((int) (50 * factor));
		this.patientTable.getColumnModel().getColumn(6).setCellRenderer(new TextWrappingCellRenderer(alpha, font, gap));
		this.patientTable.getColumnModel().getColumn(6).setMinWidth((int) (350 * factor));
		this.patientTable.getColumnModel().getColumn(7).setCellRenderer(new TextWrappingCellRenderer(alpha, font, gap));
		this.patientTable.getColumnModel().getColumn(7).setMinWidth((int) (180 * factor));
		this.patientTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		
		this.patientTable.getSelectionModel().addListSelectionListener(new ListSelectionListener()
		{
			public void valueChanged(ListSelectionEvent e)
			{
				patientTable.scrollRectToVisible(patientTable.getCellRect(patientTable.getSelectedRow(), 0, true));
			}
		});
		
		// 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();
					// close dialog and return Patient
					loadPatient();					
				}
			}
			
			
			public void keyReleased(KeyEvent e)
			{
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
					e.consume();

				} else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
					e.consume();
					//setVisible(false);
				}
			}
		});
		
		// searchfield for the ssn
		this.searchMatriculeField = new JTextField(15);
		this.searchMatriculeField.setToolTipText(Translatrix.getTranslationString("pm.searchMatricule"));
		// this.searchMatriculeField.addActionListener(new ActionListener() {
		// public void actionPerformed(ActionEvent e) {
		// searchTextField.setText("");
		// setWaitCursor(true);
		// searchPatients(true);
		// setWaitCursor(false);
		// if (patientListTableModel.getRowCount() == 1)
		// loadPatient((Boolean)
		// patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.OPEN_PATIENT_IN_NEW_TAB));
		// }
		// });
		
		KeyListener searchFieldKeyListener = new KeyListener()
		{
			private Timer	timer;
			
			
			public void keyTyped(KeyEvent e)
			{
				if (!e.getSource().equals(searchMatriculeField))
				{
					// reset the matricule field if there is some text in the
					// otgher fields
					searchMatriculeField.setText("");
				}
				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 || isAutomaticSearch())
					{
						// TODO CLOSE DIALOG AND RETURN PATIENT
//						loadPatient((Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.OPEN_PATIENT_IN_NEW_TAB));
					}
					else
					{
						if (timer != null)
						{
							timer.cancel();
						}
						timer = new Timer();
						timer.schedule(new SearchTask(), 0);
						openPatient = true;
					}
					// all other keys start new search
				}
				else
				{
					if (timer != null)
					{
						timer.cancel();
					}
					if (isAutomaticSearch())
					{
						Integer delay = (Integer) mainFrame.settingsPanel.getValue(PatientSearchSettingsPlugin.NAME, PatientSearchSettingsPlugin.SEARCH_DELAY);
						if (delay == null) {
							delay = 300;
						}
						
						timer = new Timer();
						timer.schedule(new SearchTask(), delay);
					}
					openPatient = false;
				}
				/* ================================================ */
			}

			public void keyReleased(KeyEvent e)
			{
				
			}
		};
		
		// searchfield for name, ssn
		this.searchTextField = new JTextField(30);
		this.searchTextField.setToolTipText(Translatrix.getTranslationString("pm.searchHelp"));
		this.searchTextField.addKeyListener(searchFieldKeyListener);
		
		// searchfield for phone, address
		this.searchAddressPhoneField = new JTextField(15);
		this.searchAddressPhoneField.setToolTipText(Translatrix.getTranslationString("pm.searchHelp"));
		this.searchAddressPhoneField.addKeyListener(searchFieldKeyListener);
		
		// listener for matriculefield
		this.searchMatriculeField.addKeyListener(searchFieldKeyListener);
		
		
		// action to clear the search
		GECAMedAction clearAction = new GECAMedAction(null, "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);
			}
		};
		
		// action to reload the search
		GECAMedAction reloadAction = new GECAMedAction(null, "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);
			}
		};
		
		JButton jb = new JButton(clearAction);
		jb.setText("");
		jb.setToolTipText((String)clearAction.getValue(Action.SHORT_DESCRIPTION));

		
		JButton jb2 = new JButton(reloadAction);
		jb2.setText("");
		jb2.setToolTipText((String)reloadAction.getValue(Action.SHORT_DESCRIPTION));
		
		moduleHeader.addButton(jb);
		moduleHeader.addButton(jb2);
		
		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 search = command.split(":")[1];
						this.searchTextField.setText(search);
					}
					else if (commandline[0].equalsIgnoreCase("PATIENTMATRICULESEARCH") && MATRICULE_SEARCH)
					{
						String search = command.split(":")[1];
						this.searchMatriculeField.setText(search);
					}
				}
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
		
		// start an inital patient search to display a list of patients
		try
		{
			Boolean startEmpty = (Boolean) this.mainFrame.settingsPanel.getValue(PatientSearchSettingsPlugin.NAME, PatientSearchSettingsPlugin.START_WITH_EMPTY_LIST);
			if (startEmpty == null) startEmpty = false;
			if (! startEmpty) {
				new Thread()
				{
					public void run()
					{
						searchPatients(true, false);
					}
				}.start();
			}
		}
		catch (Exception e)
		{
		}
		
		// TODO suspended for now....
		// // start listener for JMS
		// this.recieveJMS();
	}
	
	/**
	 * loads the selected patient
	 */
	private void loadPatient() {
		int patientID = -1;
		this.patientSearchDialog.setPatient(null);
		if (this.patientTable.getSelectedRow() == -1) {
			logger.info("unable to open patient: No patient selected");
			this.patientSearchDialog.setVisible(false);
			return;
		}
        try {
        	patientID = this.patientListTableModel.getPatientIDforRow(this.tableSorter.modelIndex(this.patientTable.getSelectedRow()));
//        	this.patient = this.manager.getPatient(patientID);
        	this.patientSearchDialog.setPatient(this.manager.getPatient(patientID));
		} catch (Exception e1) {
			logger.info("unable to open patient with ID: " + patientID);
		}
			this.patientSearchDialog.setVisible(false);
	}
	
	
	public Patient getSelectedPatient ()
	{
		Integer	patientId = patientListTableModel.getPatientIDforRow(tableSorter.modelIndex(patientTable.getSelectedRow()));
		Patient	patient;
		
		if (patientId == null)
		{
			patient = null;
		}
		else
		{
			try
			{
				patient = manager.getPatient(patientId);
			}
			catch (Exception e)
			{
				logger.log(Level.ERROR, e.getMessage(), e);
				patient = null;
			}
		}
		
		return patient;
	}
	
	
	/*
	 * (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;
			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)
	{
		Integer searchLimit = (Integer) this.mainFrame.settingsPanel.getValue(PatientSearchSettingsPlugin.NAME, PatientSearchSettingsPlugin.SEARCH_LIMIT);
		if (searchLimit == null) searchLimit = 100;
		
		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);
		
		this.patientListTableModel.setPatients(new ArrayList<PatientStub>());
		
		// store selected patient
		int currPatient = this.patientListTableModel.getPatientIDforRow(this.patientTable.getSelectedRow());
		
		// get number of minimum search characters
		Integer minChars = (Integer) this.mainFrame.settingsPanel.getValue(PatientSearchSettingsPlugin.NAME, PatientSearchSettingsPlugin.MIN_SEARCH_CHARS);
		if (minChars == null) minChars = 2;
		// 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, searchLimit)));
				}
				else
				{
					patientListTableModel.setPatients(new ArrayList<PatientStub>(manager.getPatientStubListBySearchString(searchNameText, searchAddressText, filter, searchLimit)));
				}
				try
				{
					patientTable.setRowSelectionInterval(0, 0);
//					try
//					{
//						// reselect the last selected patient.
//						int row = 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, searchLimit)));
				try
				{
					// reselect the last selected patient.
					int row = 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);
		logger.info("Search for \"" + searchNameText + " returned " + patientListTableModel.getRowCount() + " results " + "\" took " + took + "ms");
		
		// 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;
	}
	
	
	/*
	 * (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()))
		{
			// close dialog and return patient
			loadPatient();
		}
	}
	
	public void mousePressed(MouseEvent e) {}
	
	public void mouseReleased(MouseEvent 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)
		{
			JLabel l1 = new JLabel(Translatrix.getTranslationString("pm.socialNumber") + ":");
			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(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(l3, cc.xy(5, 1));
		jp.add(this.searchAddressPhoneField, cc.xy(5, 2));
		return jp;
	}
	
	public JTextField getSearchTextField()
	{
		return this.searchTextField;
	}
	
	
	/**
	 * 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));
		}
	}
	
	
	private boolean isAutomaticSearch() {
		Boolean autoSearch = (Boolean) mainFrame.settingsPanel.getValue(PatientSearchSettingsPlugin.NAME, PatientSearchSettingsPlugin.START_SEARCH_AUTOMATIC);
		if (autoSearch == null) {
			return false;					
		} else {
			return autoSearch;
		}
	}
	
	/**
	 * Threaded task for the search
	 * 
	 * @author Johannes Hermen johannes.hermen(at)tudor.lu
	 * 
	 * @version <br>
	 *          $Log: PatientListPanelforPatientSearchDialog.java,v $
	 *          Revision 1.8  2013-12-27 18:09:23  donak
	 *          Cleanup of imports
	 *
	 *          Revision 1.7  2013-09-04 06:22:23  ferring
	 *          patient search dialog extends now GECAMedBaseDialogImpl
	 *
	 *          Revision 1.6  2013-07-15 06:18:35  ferring
	 *          logging changed
	 *
	 *          Revision 1.5  2013-02-15 13:58:40  ferring
	 *          unused imports removed
	 *
	 *          Revision 1.4  2013-02-06 15:20:25  troth
	 *          Remove some printStackTrace.
	 *
	 *          Revision 1.3  2012-10-19 16:24:42  troth
	 *          First version of GECAMed launcher.
	 *
	 *          Revision 1.2  2012-06-20 09:53:30  troth
	 *          Fix bug: Causes NullPointerException when the minChars for search in settings not set.
	 *
	 *          Revision 1.1  2012-04-12 15:29:57  troth
	 *          Release new search dialog panel.
	 *
	 *          Revision 1.2  2012-03-14 10:21:09  troth
	 *          Code clearup.
	 *
	 *          Revision 1.1  2012-03-13 17:15:09  troth
	 *          Add testversion of new PatientSearchDialog in first step only in the agenda GeneralPanel in the AppointmentDialog.
	 *
	 *          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);
		}
	}
	
	/*
	 * (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);
	}
}
