package lu.tudor.santec.gecamed.esante.gui.tab;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.font.TextAttribute;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.net.SocketException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.AbstractAction;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
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.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.text.JTextComponent;

import lu.tudor.santec.gecamed.core.gui.GECAMedColors;
import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.IconFetcher;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
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.widgets.ErrorDialog;
import lu.tudor.santec.gecamed.core.utils.GECAMedUtils;
import lu.tudor.santec.gecamed.esante.ejb.entity.beans.Dsp;
import lu.tudor.santec.gecamed.esante.gui.IconNames;
import lu.tudor.santec.gecamed.esante.gui.data.Configuration;
import lu.tudor.santec.gecamed.esante.gui.dialogs.LoginDialog;
import lu.tudor.santec.gecamed.esante.gui.utils.ESanteGuiUtils;
import lu.tudor.santec.gecamed.esante.gui.webservice.SOAPUtilities;
import lu.tudor.santec.gecamed.esante.gui.webservice.SoapSender;
import lu.tudor.santec.gecamed.esante.gui.webservice.WebserviceException;
import lu.tudor.santec.gecamed.esante.utils.exceptions.HtmlErrorCodeException;
import lu.tudor.santec.gecamed.esante.utils.exceptions.SendingStoppedException;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient;
import lu.tudor.santec.gecamed.patient.gui.PatientManagerModule;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.log4j.Logger;

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

/**
 * @author jens.ferring(at)tudor.lu
 * 
 * @version
 * <br>$Log: DspListPanel.java,v $
 * <br>Revision 1.27  2014-02-19 10:02:59  ferring
 * <br>dsp ID taken out when querying DSPs (at first)
 * <br>
 * <br>Revision 1.26  2014-02-18 13:17:33  ferring
 * <br>Patients with Luxembourg ID, but without DSP, are now connected to their DSP or Luxembourg ID is removed, if no DSP was found.
 * <br>If only one DSP was found in search, the compare DSP and patient dialog is shown directly.
 * <br>
 * <br>Revision 1.25  2014-02-06 14:31:12  ferring
 * <br>SendingStoppedException handling and logging changed
 * <br>
 * <br>Revision 1.24  2014-01-27 10:08:17  ferring
 * <br>colons added
 * <br>
 * <br>Revision 1.23  2014-01-23 17:15:21  ferring
 * <br>make sure DSP ID is null, so it will not be queried for the DSP ID
 * <br>
 * <br>Revision 1.22  2014-01-23 15:02:11  ferring
 * <br>DSP last names changed
 * <br>
 * <br>Revision 1.21  2014-01-22 14:42:06  ferring
 * <br>SSN search implemented
 * <br>
 * <br>Revision 1.20  2014-01-16 15:49:02  ferring
 * <br>DSP Warning color is now darker
 * <br>
 * <br>Revision 1.19  2014-01-13 07:38:50  ferring
 * <br>Label used for PDQ warnings instead of dialog
 * <br>
 * <br>Revision 1.18  2014-01-10 10:03:16  ferring
 * <br>DSPs without an ID are now displayed grey
 * <br>
 * <br>Revision 1.17  2014-01-10 08:26:20  ferring
 * <br>tranlsations added
 * <br>
 * <br>Revision 1.16  2014-01-06 12:33:11  ferring
 * <br>Mandate info added
 * <br>
 * <br>Revision 1.15  2013-12-19 12:36:29  ferring
 * <br>GECAMedBaseDialogImpl.showMessage changed to ESanteDialog.showMessage
 * <br>
 * <br>Revision 1.14  2013-12-16 12:13:48  ferring
 * <br>Exception handling changed
 * <br>
 * <br>Revision 1.13  2013-12-13 15:02:24  ferring
 * <br>Exception handling changed
 * <br>
 * <br>Revision 1.12  2013-12-13 12:31:31  ferring
 * <br>Exception handling changed
 * <br>
 * <br>Revision 1.11  2013-12-11 08:13:25  ferring
 * <br>translations added
 * <br>and SSN function added / prepared
 * <br>
 * <br>Revision 1.10  2013-12-10 11:57:11  ferring
 * <br>webservice error handling improved
 * <br>
 * <br>Revision 1.9  2013-11-26 10:30:03  ferring
 * <br>translated
 * <br>
 * <br>Revision 1.8  2013-11-21 09:48:07  ferring
 * <br>auto resizing improved
 * <br>
 * <br>Revision 1.7  2013-11-18 15:36:49  ferring
 * <br>Restructured methods with SoapSender and DocumentWorker restructured.
 * <br>Checking the IPID, if it changes and refreshing the data.
 * <br>
 * <br>Revision 1.6  2013-11-15 16:08:00  ferring
 * <br>tidied up the unneeded methods
 * <br>
 * <br>Revision 1.5  2013-11-15 10:07:52  ferring
 * <br>Sizing of the table now depends on the column, not on the column index
 * <br>
 * <br>Revision 1.4  2013-11-14 16:51:49  ferring
 * <br>Auto resizing of table columns
 * <br>
 * <br>Revision 1.3  2013-11-12 09:34:59  ferring
 * <br>DSP list will be reloaded only after clicking one of the refresh buttons and the data will not be changed back after reload
 * <br>
 * <br>Revision 1.2  2013-11-08 08:46:15  ferring
 * <br>dsp renamed
 * <br>
 * <br>Revision 1.1  2013-11-05 09:47:56  ferring
 * <br>ESantePatient changed to Dsp. The Dsp object will be stored in the database, if a patient is linked with eSanté.
 * <br>
 * <br>Revision 1.12  2013-10-29 13:42:43  ferring
 * <br>bug fixes when showing patient DSPs to link to
 * <br>
 * <br>Revision 1.11  2013-10-29 10:04:08  donak
 * <br>Fixed: Unlinked patient records possessed the possibility to upload documents to the DSP, which is impossible
 * <br>Fixed: User will now be informed if client time is out of sync with the server and thus the saml assertion is denied
 * <br>
 * <br>Revision 1.10  2013-10-28 16:54:12  ferring
 * <br>eSante and GECAMed patient compare dialog added and a lot of bug fixes
 * <br>
 * <br>Revision 1.9  2013-10-23 07:32:32  ferring
 * <br>icon names changed to constants
 * <br>
 * <br>Revision 1.8  2013-10-21 08:20:30  ferring
 * <br>rendering changed
 * <br>
 * <br>Revision 1.7  2013-09-13 14:18:56  ferring
 * <br>eSante bugs fixed and database implementation started
 * <br>
 * <br>Revision 1.6  2013-09-10 06:16:28  ferring
 * <br>eSante improvements
 * <br>
 * <br>Revision 1.5  2013-09-06 13:12:03  ferring
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.4  2013-07-15 06:18:37  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.3  2013-07-05 06:08:01  ferring
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.2  2013-07-03 13:06:21  ferring
 * <br>eSante module handling changed
 * <br>
 * <br>Revision 1.1  2013-06-26 11:19:37  ferring
 * <br>migrating eSante view from dialogs to eSante patient tab
 * <br>
 */

public class DspListPanel extends JPanel implements TableCellRenderer, ListSelectionListener, 
		MouseListener, FocusListener, CaretListener, PropertyChangeListener, ItemListener
{
	/* ======================================== */
	// CONSTANTS
	/* ======================================== */
	
	private static final long	serialVersionUID	= 3507362859489815033L;
	
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(DspListPanel.class.getName());
	
	
	
	/* ======================================== */
	// MEMBERS
	/* ======================================== */
	
	private static String[]			columnNames;
	
	private static int[]			columnWidths;
	
	
	private Patient					gecamedPatient;
	
	private Dsp						dspInfo;
	
	private AutoResizeTable			dspTable;
	
	private DspListModel			dspTableModel;
	
	private JButton					reloadButton;
	
	private	JRadioButton			nameSearchButton;

	private	JLabel					patientFirstNameLabel;
	private JTextField				patientFirstNameField;
	
	private	JLabel					patientSurNameLabel;
	private JTextField				patientSurNameField;
	
	private	JLabel					patientMaidenNameLabel;
	private JTextField				patientMaidenNameField;
	
	private JRadioButton			ssnSearchButton;
	
	private	JLabel					ssnLabel;
	private JTextField				patientSsnField;
	
	private JLabel					warningLabel;
	
	private String					focusedValue;
	
	private	JLabel					patientBirthDayLabel;
	private JDateChooser			patientBirthdayChooser;
	
	private JPopupMenu				patientPopup;
	
//	private boolean					reloadActivated = false;
	
	private	boolean					alreadyLoaded			= false;
	
	
	private Set<DspListListener>	listener		= new HashSet<DspListListener>();
	
	
	
	/* ======================================== */
	// CONSTRUCTORS
	/* ======================================== */
	
	static
	{
		columnNames = new String [DspListModel.COLUMN_COUNT];
		columnNames[DspListModel.IPID]			= Translatrix.getTranslationString("esante.DspList.table.ipid");
		columnNames[DspListModel.MATCH]			= Translatrix.getTranslationString("esante.DspList.table.match");
		columnNames[DspListModel.FIRST_NAME]	= Translatrix.getTranslationString("esante.DspList.table.firstName");
		columnNames[DspListModel.FAMILY_NAME]	= Translatrix.getTranslationString("esante.DspList.table.familyName");
		columnNames[DspListModel.COMMON_NAME]	= Translatrix.getTranslationString("esante.DspList.table.commonName");
		columnNames[DspListModel.BIRTH_DATE]	= Translatrix.getTranslationString("esante.DspList.table.birthday");
		columnNames[DspListModel.GENDER]		= Translatrix.getTranslationString("esante.DspList.table.gender");
//		columnNames[DspListModel.EHR_STATE]		= "EHR state";
		columnNames[DspListModel.ADDRESS]		= Translatrix.getTranslationString("esante.DspList.table.address");
		
		columnWidths= new int[DspListModel.COLUMN_COUNT];
		columnWidths[DspListModel.IPID]			= -1;
		columnWidths[DspListModel.MATCH]		= -1;
		columnWidths[DspListModel.FIRST_NAME]	= 2;
		columnWidths[DspListModel.COMMON_NAME]	= 2;
		columnWidths[DspListModel.FAMILY_NAME]	= 2;
		columnWidths[DspListModel.BIRTH_DATE]	= -1;
		columnWidths[DspListModel.GENDER]		= -1;
		columnWidths[DspListModel.ADDRESS]		= 3;
	}
	
	
	public DspListPanel (boolean autoRefresh)
	{
		initComponents(autoRefresh);
	}
	
	
	
	/* ======================================== */
	// CLASS BODY
	/* ======================================== */
	
	public void setDsp (Dsp dsp)
	{
		this.dspInfo = dsp;
	}
	
	
	public void setPatientList (List<Dsp> patients)
	{
		dspTableModel.setValues(patients);
		patientSelected();
		
		if (dspTableModel.getRowCount() == 1)
		{
			dspTable.getSelectionModel().setSelectionInterval(0, 0);
			patientChoosen();
		}
	}
	
	
	public void clearPanel ()
	{
		nameSearchButton.setSelected(true);
		patientFirstNameField.setText("");
		patientSurNameField.setText("");
		patientMaidenNameField.setText("");
		patientSsnField.setText("");
		warningLabel.setText("");
		patientBirthdayChooser.setDate(null);
		dspTableModel.setValues(null);
		setPatient(null);
		
		validate();
	}
	
	
	public void addPatientListListener (DspListListener l)
	{
		listener.add(l);
	}
	
	
	public boolean removePatientListListener (DspListListener l)
	{
		return listener.remove(l);
	}
	
	
	public void writePatientDataIntoFields (Patient patient)
	{
		setPatient(patient);
		
		if (alreadyLoaded)
			return;
		
		nameSearchButton.setSelected(true);
		if (patient == null)
		{
			patientFirstNameField.setText(	"");
			patientSurNameField.setText(	"");
			patientMaidenNameField.setText(	"");
			patientSsnField.setText(		"");
			warningLabel.setText("");
			patientBirthdayChooser.setDate(	null);
		}
		else
		{
			patientFirstNameField.setText(	patient.getFirstName()	== null ? "" : patient.getFirstName());
			patientSurNameField.setText(	patient.getSurName()	== null ? "" : patient.getSurName());
			patientMaidenNameField.setText(	patient.getMaidenName()	== null ? "" : patient.getMaidenName());
			patientSsnField.setText(		getValidSsn(patient.getSocialSecurityNumber()));
			patientBirthdayChooser.setDate(	patient.getBirthDate());
		}
	}
	
	
	private String getValidSsn (String ssn)
	{
		if (ssn == null)
			return "";
		else
			return ssn;
//		else if (ssn.length() < 11 || ssn.length() >= 13)
//			return ssn;
//		else
//			return CheckSsnDigits.get13DigitsMatricule(ssn);
	}
	
	
	public void writeFieldDataIntoDsp (Dsp dsp)
	{
		if (dsp == null)
			return;
		
		dsp.setGivenName(	patientFirstNameField.getText());
		dsp.setCommonName(	patientSurNameField.getText());
		dsp.setFamilyName(	patientMaidenNameField.getText());
		dsp.setBirthDate(	patientBirthdayChooser.getDate());
		dsp.setSsn(			patientSsnField.getText());
	}
	
	
	public Boolean queryPatients ()
	{
		SoapSender	sender;
		List<Dsp>	dspList	= null;
//		String		message;
		Boolean		patientsLoaded = Boolean.FALSE;
		
		
		if (dspInfo == null)
			dspInfo = new Dsp(gecamedPatient);
		// TODO
//		dspInfo.setDspOid(gecamedPatient.getIdLuxembourg());
		dspInfo.setDspOid(null);
		
		try
		{
			writeFieldDataIntoDsp(dspInfo);
			Configuration config = LoginDialog.getConfiguration();
			if (config == null)
				return null;
			
			sender	= new SoapSender(dspInfo, false);
			
			// try to query for the SSN
			if (!alreadyLoaded && !GECAMedUtils.isEmpty(dspInfo.getSsn()))
			{
				dspList = SOAPUtilities.queryPatient(sender, config);
				
				if (dspList.isEmpty())
					nameSearchButton.setSelected(true);
				else
					ssnSearchButton.setSelected(true);
			}
			
			/* if it wasn't queried for the SSN or that didnn't provide any result, 
			 * try to query for name and birth date.
			 */
			if (dspList == null || dspList.isEmpty())
			{
				if (dspList != null
						|| !ssnSearchButton.isSelected())
					dspInfo.setSsn(null);
				else 
					dspInfo.setSsn(patientSsnField.getText().trim());
				
				sender.clear();
				dspList = SOAPUtilities.queryPatient(sender, config);
			}
			
			if (sender.getStatus() == SoapSender.STATUS_WARNING)
			{
//				message = sender.getErrorDetail();
				warningLabel.setText(sender.getErrorDetail());
				warningLabel.setToolTipText(sender.getErrorDetail());
			}
			else
			{
//				message = null;
				warningLabel.setText("");
				warningLabel.setToolTipText(null);
			}
			
			patientsLoaded	= Boolean.TRUE;
		}
		catch (HtmlErrorCodeException e)
		{
			ESanteGuiUtils.showHtmlErrorCodeException(e.getMessage());
			return null;
		}
		catch (SendingStoppedException e)
		{
			// user cancelled the operation, simply log it as warning and return
			logger.info(e.getMessage());
			return Boolean.FALSE;
		}
		catch (SocketException e)
		{
			ESanteGuiUtils.showConnectionError(e);
			return null;
		}
		catch (WebserviceException e)
		{
			switch (e.getErrorType())
			{
				case WebserviceException.TYPE_TIME_OUT_OF_SYNC:

					// report to the user to connect his client to an ntp service
					SOAPUtilities.asynchClientTimeError(gecamedPatient.getId());
					return null;
					
				case WebserviceException.TYPE_INVALID_LOGIN_DATA:
					
					LoginDialog.incorrectLoginData();
					return queryPatients();
				
				// shouldn't occur
//				case WebserviceException.TYPE_NOT_AUTHORIZED:
//
//					return null;

				case WebserviceException.TYPE_SERVER:

					ESanteGuiUtils.showConnectionError(e);
					return null;
				
				default:
					
					ESanteGuiUtils.showAndLogWebserviceException(e);
					return null;
			}
		}
		catch (Exception e)
		{
			logger.error(e.getMessage(), e);
			ErrorDialog.showErrorDialog(
					MainFrame.getInstance(), 
					Translatrix.getTranslationString("esante.DspList.error.searching"), 
					e.getMessage(), e);
			return null;
		}
		
		setPatientList(dspList);
		
//		if (message != null)
//		{
//			ESanteDialog.showMessageDialog(this, 
//					Translatrix.getTranslationString("esante.DspList.warning.loading"), 
//					message, 
//					GECAMedBaseDialogImpl.OK_BUTTON_MODE, 
//					GECAMedModule.getBigIcon(GECAMedIconNames.WARNING));
//		}
		
		// it was loaded once, until another patient is set, there will only be reloads
		alreadyLoaded = true;
		
		if (Boolean.TRUE.equals(patientsLoaded))
			reloadButton.setEnabled(false);
		
		return patientsLoaded;
	}
	
	
	public boolean wasAlreadyLoaded ()
	{
		return alreadyLoaded;
	}
	
	
	public void setAlreadyLoaded (boolean loaded)
	{
		this.alreadyLoaded = loaded;
	}
	
	
	/* ---------------------------------------- */
	// TABLE CELL RENDERER METHOD
	/* ---------------------------------------- */
	
	public Component getTableCellRendererComponent (JTable table, Object value, 
			boolean isSelected, boolean hasFocus, int row, int column)
	{
		String	text		= (String)value;
		JLabel	cell		= new JLabel();
		double	matching	= 0.0d;
		Dsp		dsp			= dspTableModel.getDspAtRow(row);
		boolean	hasOid		= !GECAMedUtils.isEmpty(dsp.getDspOid());
		
		
		// set the text
		cell.setText(text == null ? "" : (text).replace("\n", " "));
		
		switch (column)
		{
			case DspListModel.IPID:
				cell.setToolTipText(dsp.getDspOid());
				break;
				
			case DspListModel.ADDRESS:
				if (GECAMedUtils.isEmpty(text))
					cell.setToolTipText(null);
				else
					cell.setToolTipText("<html>"+text.replace("\n", "<br>")+"</html>");
				break;
				
			default:
				if (GECAMedUtils.isEmpty(text))
					cell.setToolTipText(null);
				else
					cell.setToolTipText(text);
		}
		
		// set the background color
		if (isSelected)
			cell.setBackground(table.getSelectionBackground());
		else if (row % 2 == 0)
			cell.setBackground(GECAMedColors.c_EvenLineBackground);
		else
			cell.setBackground(GECAMedColors.c_OddLineBackground);
		cell.setOpaque(true);
		
		if (!hasOid)
			cell.setEnabled(false);
		
		// remove bold, if it's not matching 100%
		@SuppressWarnings("unchecked")
		Map<TextAttribute, Object> attributes = (Map<TextAttribute, Object>) cell.getFont().getAttributes();
		if (matching < 99.0d)
			attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR);
		else
			attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
		cell.setFont(new Font(attributes));
		
		return cell;
	}
	
	
	/* ---------------------------------------- */
	// LIST SELECTION LISTENER METHOD
	/* ---------------------------------------- */
	
	public void valueChanged (ListSelectionEvent e)
	{
		patientSelected();
	}
	
	
	/* ---------------------------------------- */
	// MOUSE LISTENER METHODS
	/* --------------------------------------- */
	
	public void mouseClicked (MouseEvent e)
	{
		if (selectRow(e.getPoint()) && e.getClickCount() == 2)
		{
			patientChoosen();
		}
	}
	
	
	public void mousePressed (MouseEvent e) 
	{
		if (e.isPopupTrigger() && selectRow(e.getPoint()))
		{
			patientPopupTriggerTriggered(e);
		}
	}
	
	
	public void mouseReleased (MouseEvent e) 
	{
		if (e.isPopupTrigger() && selectRow(e.getPoint()))
		{
			patientPopupTriggerTriggered(e);
		}
	}
	
	
	public void mouseEntered (MouseEvent e) {}
	public void mouseExited (MouseEvent e) {}
	
	
	public void caretUpdate (CaretEvent e)
	{
		if (focusedValue != null)
		{
			try {
				if (!((JTextField)e.getSource()).getText().equals(focusedValue))
				{
					reloadButton.setEnabled(true);
				}				
			} catch (Exception e2) {}
		}
	}
	
	
	/* ---------------------------------------- */
	// FOCUS LISTENER METHODS 
	/* ---------------------------------------- */
	
	public void focusGained (FocusEvent e)
	{
		try {
			if (e.getSource() instanceof JTextComponent)
				focusedValue = ((JTextComponent)e.getSource()).getText();			
		} catch (Exception e2) {}
	}
	
	
	public void focusLost (FocusEvent e) {}
	
	
	/* ---------------------------------------- */
	// PROPERTY CHANGED LISTENER METHOD
	/* ---------------------------------------- */
	
	public void propertyChange (PropertyChangeEvent evt)
	{
		reloadButton.setEnabled(true);
	}
	
	
	/* ---------------------------------------- */
	// ITEM LISTENER METHOD
	/* ---------------------------------------- */
	
	public void itemStateChanged (ItemEvent e)
	{
		boolean	ssnSearchEnabled	= ssnSearchButton.isSelected();
		
		ssnLabel.setEnabled(ssnSearchEnabled);
		patientSsnField.setEditable(ssnSearchEnabled);
		
		patientFirstNameLabel.setEnabled(!ssnSearchEnabled);
		patientFirstNameField.setEditable(!ssnSearchEnabled);
		patientSurNameLabel.setEnabled(!ssnSearchEnabled);
		patientSurNameField.setEditable(!ssnSearchEnabled);
		patientMaidenNameLabel.setEnabled(!ssnSearchEnabled);
		patientMaidenNameField.setEditable(!ssnSearchEnabled);
		patientBirthDayLabel.setEnabled(!ssnSearchEnabled);
		patientBirthdayChooser.setEnabled(!ssnSearchEnabled);
		
		reloadButton.setEnabled(true);
	}
	
	
	
	/* ======================================== */
	// HELP METHODS
	/* ======================================== */
	
	private void initComponents (boolean autoRefresh)
	{
		CellConstraints		cc	= new CellConstraints();
		JScrollPane			tableScroller;
		int					row	= 0;
		String				patientSurName;
		String				patientMaidenName;
		
		
		if (PatientManagerModule.isMaidenConfig()) 
		{
			patientSurName		= Translatrix.getTranslationString("pm.maidenName")+":";
			patientMaidenName	= Translatrix.getTranslationString("pm.familyName")+":";
    	}
		else
		{
    		patientSurName		= Translatrix.getTranslationString("pm.lastName")+":";
    		patientMaidenName	= Translatrix.getTranslationString("pm.maidenName")+":";
    	}
		
		reloadButton			= new JButton(new AbstractAction("", 
				GECAMedModule.getIcon(GECAMedIconNames.SEARCH))
		{
			private static final long	serialVersionUID	= 1L;

			public void actionPerformed (ActionEvent e)
			{
				queryPatients();
			}
		});
		reloadButton.setToolTipText(Translatrix.getTranslationString("esante.DspList.reload"));
		reloadButton.setPreferredSize(new Dimension(36, 36));
		reloadButton.setBackground(null);
		
		nameSearchButton		= new JRadioButton(Translatrix.getTranslationString(
				"esante.DspList.table.searchForName"));
		nameSearchButton.setOpaque(false);
		nameSearchButton.addItemListener(this);

		ssnSearchButton			= new JRadioButton(Translatrix.getTranslationString(
				"esante.DspList.table.searchForSsn"));
		ssnSearchButton.setOpaque(false);
		ssnSearchButton.addItemListener(this);
		
		// show the information of the GECAMed patient to get the eSanté ID for
		patientFirstNameLabel	= new JLabel(Translatrix.getTranslationString(
				"esante.ComparePatientData.firstName"));
		patientFirstNameLabel.setOpaque(false);
		patientFirstNameField	= new JTextField();
		patientFirstNameField.addFocusListener(this);
		patientFirstNameField.addCaretListener(this);
		
		patientSurNameLabel		= new JLabel(patientSurName);
		patientSurNameLabel.setOpaque(false);
		patientSurNameField		= new JTextField();
		patientSurNameField.addFocusListener(this);
		patientSurNameField.addCaretListener(this);
		
		patientMaidenNameLabel	= new JLabel(patientMaidenName);
		patientMaidenNameLabel.setOpaque(false);
		patientMaidenNameField	= new JTextField();
		patientMaidenNameField.addFocusListener(this);
		patientMaidenNameField.addCaretListener(this);
		
		ssnLabel				= new JLabel(Translatrix.getTranslationString(
				"esante.ComparePatientData.ssn"));
		ssnLabel.setOpaque(false);
		patientSsnField			= new JTextField();
		patientSsnField.addFocusListener(this);
		patientSsnField.addCaretListener(this);
		
		patientBirthDayLabel	= new JLabel(Translatrix.getTranslationString(
				"esante.ComparePatientData.birthday"));
		patientBirthDayLabel.setOpaque(false);
		
		patientBirthdayChooser = GECAMedGuiUtils.getDateChooser(false);
		patientBirthdayChooser.addPropertyChangeListener("date", this);
		
		if (patientBirthdayChooser.getDateEditor() instanceof JTextComponent)
		{
			try {
				JTextComponent dateEditor = (JTextComponent) patientBirthdayChooser.getDateEditor();
				dateEditor.addFocusListener(this);
				dateEditor.addCaretListener(this);				
			} catch (Exception e) {}
		}
		
		warningLabel			= new JLabel();
		warningLabel.setOpaque(false);
		warningLabel.setForeground(GECAMedColors.c_WARNING);
		
		dspTableModel			= new DspListModel();
		dspTable				= new AutoResizeTable(dspTableModel);
		dspTable.setDefaultRenderer(String.class, this);
		dspTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		dspTable.setModel(dspTableModel);
		dspTable.addMouseListener(this);
//		dspTable.getTableHeader().setReorderingAllowed(false);
		dspTable.getSelectionModel().addListSelectionListener(this);
		tableScroller			= new JScrollPane(dspTable);
		tableScroller.setOpaque(false);
		tableScroller.getViewport().setOpaque(false);
		
		
		// define the column headlines
		TableColumnModel columnModel	= dspTable.getColumnModel();
		TableColumn column;
		for (int columnNo = 0; columnNo < columnModel.getColumnCount(); columnNo++)
		{
			column = columnModel.getColumn(columnNo);
			column.setHeaderValue(columnNames[columnNo]);
			column.setCellRenderer(this);
			dspTable.setSizing(dspTable.getColumnModel().getColumn(columnNo), columnWidths[columnNo] < 0 
							? AutoResizeTable.SIZE_TYPE_AS_NEEDED 
							: AutoResizeTable.SIZE_TYPE_PROPORTIONAL, 
					columnWidths[columnNo]);
		}
		
		// create the popups
		patientPopup		= new JPopupMenu();
		patientPopup.add(new AbstractAction(
				Translatrix.getTranslationString("esante.DspList.linkPatient"),
				ESanteGuiUtils.getIcon(IconNames.LINK_PATIENT, IconFetcher.SMALLPIX))
		{
			private static final long	serialVersionUID	= 1L;

			public void actionPerformed (ActionEvent e)
			{
				patientChoosen();
			}
		});
		
		// define the layout
		setLayout(new FormLayout(
				// columns
				"5px, 10px, f:p, 5px, f:150px, 3px, f:p, 0px:g, 5px",
				// rows
				" 5px,f:p," +		// radio button: search for name and birth date
				" 5px,f:p," +		// first name
				" 5px,f:p," +		// surname
				" 5px,f:p," +		// maiden name
				" 5px,f:p," +		// birth day
				" 5px,f:p," +		// radio button: search for SSN
				" 5px,f:p," +		// social security number
				" 5px,f:p," +		// warning
				"15px,f:50px:g," +	// table
				" 5px"));
		setOpaque(false);
		
		// add the components
		add(reloadButton,			cc.xywh(7, 2, 1, 12, CellConstraints.FILL, CellConstraints.TOP));
		add(nameSearchButton,		cc.xyw(2, row+=2, 4));
		add(patientFirstNameLabel,	cc.xy (3, row+=2));
		add(patientFirstNameField,	cc.xy (5, row));
		add(patientSurNameLabel,	cc.xy (3, row+=2));
		add(patientSurNameField,	cc.xy (5, row));
		add(patientMaidenNameLabel,	cc.xy (3, row+=2));
		add(patientMaidenNameField,	cc.xy (5, row));
		add(patientBirthDayLabel,	cc.xy (3, row+=2));
		add(patientBirthdayChooser,	cc.xy (5, row));
		add(ssnSearchButton,		cc.xyw(2, row+=2, 4));
		add(ssnLabel,				cc.xy (3, row+=2));
		add(patientSsnField,		cc.xy (5, row));
		add(warningLabel,			cc.xyw(2, row+=2, 7));
		add(tableScroller,			cc.xyw(2, row+=2, 7));
		
		ButtonGroup	searchGroup	= new ButtonGroup();
		searchGroup.add(nameSearchButton);
		searchGroup.add(ssnSearchButton);
		nameSearchButton.setSelected(true);
	}
	
	
	private void setPatient (Patient patient)
	{
		if (patient == null || !patient.equals(gecamedPatient))
			alreadyLoaded = false;
		
		gecamedPatient = patient;
	}
	
	
	private void patientSelected ()
	{
		Dsp patient = dspTableModel.getDspAtRow(
				dspTable.getSelectedRow());
		
		for (DspListListener l : listener)
			l.dspSelected(patient);
	}
	
	
	private void patientChoosen ()
	{
		Dsp patient = dspTableModel.getDspAtRow(
				dspTable.getSelectedRow());
		
		for (DspListListener l : listener)
			l.dspChosen(patient);
	}
	
	
	private void patientPopupTriggerTriggered (MouseEvent e)
	{
		patientPopup.show(dspTable, e.getX(), e.getY());
	}
	
	
	private boolean selectRow (Point p)
	{
		int	row	= dspTable.rowAtPoint(p);
		
		
		if (row < 0 && row >= dspTable.getRowCount())
		{
			return false;
		}
		else
		{
			ListSelectionModel	sm	= dspTable.getSelectionModel();
			sm.setSelectionInterval(row, row);
			
			return true;
		}
	}
}
