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

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.SocketException;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;

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.listener.EntryTypeRegister;
import lu.tudor.santec.gecamed.core.gui.utils.LineColorListRenderer;
import lu.tudor.santec.gecamed.core.gui.widgets.ButtonPanel;
import lu.tudor.santec.gecamed.core.gui.widgets.ErrorDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
import lu.tudor.santec.gecamed.core.utils.GECAMedUtils;
import lu.tudor.santec.gecamed.esante.ejb.entity.beans.CdaDocument;
import lu.tudor.santec.gecamed.esante.ejb.entity.beans.Dsp;
import lu.tudor.santec.gecamed.esante.ejb.session.beans.CDAManagerBean;
import lu.tudor.santec.gecamed.esante.gui.IconNames;
import lu.tudor.santec.gecamed.esante.gui.dialogs.ComparePatientDataDialog;
import lu.tudor.santec.gecamed.esante.gui.dialogs.ESanteDialog;
import lu.tudor.santec.gecamed.esante.gui.dialogs.LoginDialog;
import lu.tudor.santec.gecamed.esante.gui.history.CdaHistoryHandler;
import lu.tudor.santec.gecamed.esante.gui.luxtrust.DisconnectListener;
import lu.tudor.santec.gecamed.esante.gui.luxtrust.UserInactivityMonitor;
import lu.tudor.santec.gecamed.esante.gui.utils.ESanteGuiUtils;
import lu.tudor.santec.gecamed.esante.gui.webservice.DspPrivileges;
import lu.tudor.santec.gecamed.esante.gui.webservice.SOAPUtilities;
import lu.tudor.santec.gecamed.esante.gui.webservice.Security;
import lu.tudor.santec.gecamed.esante.gui.webservice.SoapSender;
import lu.tudor.santec.gecamed.esante.gui.webservice.WebserviceException;
import lu.tudor.santec.gecamed.esante.gui.webservice.XDS;
import lu.tudor.santec.gecamed.esante.gui.worker.DocumentWorker;
import lu.tudor.santec.gecamed.esante.utils.ESanteUtils;
import lu.tudor.santec.gecamed.esante.utils.exceptions.DspLinkingException;
import lu.tudor.santec.gecamed.esante.utils.exceptions.HtmlErrorCodeException;
import lu.tudor.santec.gecamed.esante.utils.exceptions.SendingStoppedException;
import lu.tudor.santec.gecamed.formeditor.gui.model.ComboBoxElement;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.IncidentManager;
import lu.tudor.santec.gecamed.patient.gui.PatientListModule;
import lu.tudor.santec.gecamed.patient.gui.PatientManagerModule;
import lu.tudor.santec.gecamed.patient.gui.PatientViewTab;
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;

/**
 * @author jens.ferring(at)tudor.lu
 * 
 * @version
 * <br>$Log: ESanteTab.java,v $
 * <br>Revision 1.61  2014-03-05 13:08:04  ferring
 * <br>eSante bug fixed, where user was asked several times, to link with DSP when compare dialog was shown automatically, because there was only one DSP for choice
 * <br>
 * <br>Revision 1.60  2014-02-20 16:37:47  ferring
 * <br>eSante menu added
 * <br>
 * <br>Revision 1.59  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.58  2014-02-06 14:28:04  ferring
 * <br>Button order changed
 * <br>
 * <br>Revision 1.57  2014-02-04 10:08:33  ferring
 * <br>eSante ID management completed
 * <br>Only those documents will be shown, that are retrieved by the RSQ
 * <br>
 * <br>Revision 1.56  2014-01-30 17:05:44  ferring
 * <br>Presence password button added
 * <br>
 * <br>Revision 1.55  2014-01-23 15:02:46  ferring
 * <br>logout button added
 * <br>
 * <br>Revision 1.54  2014-01-22 14:42:06  ferring
 * <br>SSN search implemented
 * <br>
 * <br>Revision 1.53  2014-01-09 16:44:33  ferring
 * <br>Error handling for SAML assertions changed
 * <br>
 * <br>Revision 1.52  2014-01-09 14:30:27  ferring
 * <br>mandate not shown, if it can't be translated
 * <br>
 * <br>Revision 1.51  2013-12-19 12:35:07  ferring
 * <br>GECAMedBaseDialogImpl.showMessage changed to ESanteDialog.showMessage
 * <br>
 * <br>Revision 1.50  2013-12-16 12:13:48  ferring
 * <br>Exception handling changed
 * <br>
 * <br>Revision 1.49  2013-12-16 12:05:12  ferring
 * <br>logging eSanté actions
 * <br>
 * <br>Revision 1.48  2013-12-13 12:31:31  ferring
 * <br>Exception handling changed
 * <br>
 * <br>Revision 1.47  2013-12-10 11:58:02  ferring
 * <br>webservice error handling improved
 * <br>
 * <br>Revision 1.46  2013-12-04 13:12:15  ferring
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.45  2013-11-29 09:10:52  ferring
 * <br>first changes for eSanté test platform
 * <br>
 * <br>Revision 1.44  2013-11-28 16:38:56  ferring
 * <br>Exception caught and message shown
 * <br>
 * <br>Revision 1.43  2013-11-28 16:10:20  ferring
 * <br>cleaned
 * <br>
 * <br>Revision 1.42  2013-11-27 07:58:22  ferring
 * <br>avoiding not updating CDA view error
 * <br>
 * <br>Revision 1.41  2013-11-27 07:16:00  ferring
 * <br>Raise condition, where CDA list wasn't updated when opening new patient (hopefully) erased.
 * <br>
 * <br>Revision 1.40  2013-11-26 10:30:03  ferring
 * <br>translated
 * <br>
 * <br>Revision 1.39  2013-11-26 08:38:45  ferring
 * <br>Property initialised and changed to lower case
 * <br>
 * <br>Revision 1.38  2013-11-26 08:16:23  ferring
 * <br>Option added for temporary downloads of CDA documents
 * <br>Property names changed
 * <br>
 * <br>Revision 1.37  2013-11-22 14:51:12  ferring
 * <br>Restructured CDA tree and list notification, in order not to use an EntityBean as model.
 * <br>Buttons added to delete the CDA file and remove the incident entry
 * <br>
 * <br>Revision 1.36  2013-11-21 12:24:00  ferring
 * <br>button tooltipps added
 * <br>
 * <br>Revision 1.35  2013-11-21 10:12:40  ferring
 * <br>notify tab buttons to change enabling when documents is finished
 * <br>
 * <br>Revision 1.34  2013-11-21 09:48:29  ferring
 * <br>refactored
 * <br>
 * <br>Revision 1.33  2013-11-20 10:32:59  ferring
 * <br>integration and opening will be enqueued to the thread in any case
 * <br>
 * <br>Revision 1.32  2013-11-18 15:36:36  ferring
 * <br>Restructured methods with SoapSender and DocumentWorker restructured.
 * <br>Checking the IPID, if it changes and refreshing the data.
 * <br>
 * <br>Revision 1.31  2013-11-15 16:07:19  ferring
 * <br>tidied up the unneeded methods
 * <br>
 * <br>Revision 1.30  2013-11-14 17:56:33  ferring
 * <br>check if document needs to be downloaded and better check if documents can be integrated
 * <br>
 * <br>Revision 1.29  2013-11-14 16:51:36  ferring
 * <br>Auto resizing of table columns
 * <br>
 * <br>Revision 1.28  2013-11-12 15:37:53  ferring
 * <br>downloads can now be stopped
 * <br>
 * <br>Revision 1.27  2013-11-12 09:33:37  ferring
 * <br>show compare dialog when unlinking patient
 * <br>
 * <br>Revision 1.26  2013-11-11 11:46:32  ferring
 * <br>load documents from database before synchronising with eSante,
 * <br>expand all option added,
 * <br>Download documents option added
 * <br>and stop option removed
 * <br>
 * <br>Revision 1.25  2013-11-11 11:43:56  ferring
 * <br>stop download option removed
 * <br>and load documents from database before synchronising with eSante
 * <br>
 * <br>Revision 1.24  2013-11-08 08:48:55  ferring
 * <br>DSP information added
 * <br>
 * <br>Revision 1.23  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.22  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.21  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.20  2013-10-23 13:19:31  ferring
 * <br>FileOpening fixed
 * <br>
 * <br>Revision 1.18  2013-10-23 07:32:32  ferring
 * <br>icon names changed to constants
 * <br>
 * <br>Revision 1.17  2013-10-22 14:33:19  ferring
 * <br>Thread canceling prepared
 * <br>
 * <br>Revision 1.16  2013-10-22 05:55:41  ferring
 * <br>download folder status changed
 * <br>
 * <br>Revision 1.15  2013-10-21 08:22:07  ferring
 * <br>linking and unlinking patient changed
 * <br>dequeuing downloads
 * <br>
 * <br>Revision 1.14  2013-10-11 07:50:08  ferring
 * <br>Switching document view changed
 * <br>
 * <br>Revision 1.13  2013-10-09 13:36:35  ferring
 * <br>eSanté icon changed and tree view initialised
 * <br>
 * <br>Revision 1.12  2013-10-08 08:54:14  ferring
 * <br>class name refactoring and tree view implementation (first steps)
 * <br>
 * <br>Revision 1.11  2013-10-01 13:14:57  ferring
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.10  2013-09-30 11:53:49  ferring
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.9  2013-09-30 10:56:34  ferring
 * <br>eSante integration in GECAMed and synchronise funktion added
 * <br>
 * <br>Revision 1.8  2013-09-19 12:24:43  ferring
 * <br>eSante bugs fixed and documents stored in database
 * <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-07-15 06:18:37  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.4  2013-07-05 06:08:01  ferring
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.3  2013-07-03 13:06:20  ferring
 * <br>eSante module handling changed
 * <br>
 * <br>Revision 1.2  2013-06-27 14:12:39  ferring
 * <br>*** empty log message ***
 * <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 ESanteTab extends PatientViewTab implements 
		DspListListener, CdaDocumentListListener, ListDataListener, DisconnectListener
{
	/* ======================================== */
	// CONSTANTS
	/* ======================================== */
	
	private static final long	serialVersionUID	= -3249167419971442329L;
	
	
//	private static final int	STATUS_NO_PERMISSIONS		= 0;
	private static final int	STATUS_PATIENT_NOT_SET		= 1;
	private static final int	STATUS_PATIENT_NOT_LINKED	= 2;
	private static final int	STATUS_LOADING_PATIENTS		= 3;
	private static final int	STATUS_MATCHES_LOADED		= 4;
	private static final int	STATUS_PATIENT_MATCHED		= 5;
	private static final int	STATUS_LOADING_REPOSITORY	= 6;
	private static final int	STATUS_REPOSITORY_LOADED	= 7;
	
	private static final int	SHOW_PATIENT_PANEL			= 0;
	private static final int	SHOW_DOCUMENT_PANEL			= 1;
//	private static final int	SHOW_LOADING_PANEL			= 2;
	private static final int	ENABLE_REFRESH_BUTTON		= 3;
	private static final int	ENABLE_LINK_BUTTON			= 4;
	private static final int	ENABLE_UNLINK_BUTTON		= 5;
	private static final int	ENABLE_DOCUMENT_BUTTONS		= 6;
	
	private static final boolean[][]	STATUS_TABLE = new boolean[][] 
			{
				// SHOW or ENABLE:	
				//	|patient panel	|loading panel	|link button	|document buttons	
				//			|document panel	|refresh button	|unlink button
				// no permission
				{ 	false, 	false,	false,	false,	false,	false,	false},
				// patient not set
				{ 	false,	false,	false,	false,	false,	false,	false},
				// patient not linked
				{ 	false,	false,	false,	true,	true,	false,	false},
				// loading patients
				{ 	true,	false,	true,	true,	true,	false,	false},
				// matches loaded
				{ 	true,	false,	false,	true,	true,	false,	false},
				// patient matched
				{ 	false,	true,	false,	true,	false,	true,	true},
				// loading repository
				{ 	false,	true,	true,	true,	false,	true,	true},
				// repository loaded
				{ 	false,	true,	false,	true,	false,	true,	true}
				// loading document
//				{ 	false,	true,	true,	true,	false,	true,	true}
			}; 
	
	private static final ComboBoxElement<?>[]	TIME_PERIODS	= new ComboBoxElement[] 
			{
				new ComboBoxElement<Object>(Translatrix.getTranslationString("esante.eSanteTab.timePeriod.1year"),	
						Integer.valueOf(1),	Translatrix.getTranslationString("esante.eSanteTab.timePeriod.1yearToolTip")),
				new ComboBoxElement<Object>(Translatrix.getTranslationString("esante.eSanteTab.timePeriod.2years"),	
						Integer.valueOf(2),	Translatrix.getTranslationString("esante.eSanteTab.timePeriod.2yearsToolTip")),
				new ComboBoxElement<Object>(Translatrix.getTranslationString("esante.eSanteTab.timePeriod.5years"),	
						Integer.valueOf(5),	Translatrix.getTranslationString("esante.eSanteTab.timePeriod.5yearsToolTip")),
				new ComboBoxElement<Object>(Translatrix.getTranslationString("esante.eSanteTab.timePeriod.all"),	
						null,				Translatrix.getTranslationString("esante.eSanteTab.timePeriod.allToolTip"))
			};
	
	
	public static final String NAME		= "eSante";
	
	public static final String TAB_NAME	= "eSanteViewTab";
	
	public static final int	CONNECTION_STATUS_LOGGED_OUT	= 0;
	public static final int	CONNECTION_STATUS_LOGGED_IN		= 1;
	
	
	
	/* ======================================== */
	// MEMBERS
	/* ======================================== */
	
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(ESanteTab.class.getName());
	
	private static Map<Integer, ESanteTab> patientESanteTabs = new HashMap<Integer, ESanteTab>();
	
	private static boolean connected = false;
	
	// the top menu bar items to control the 
	private static JMenu		eSanteMenu;
	private static JMenuItem	disconnectItem;
	private static JMenuItem	presencePasswordItem;
	private static JMenuItem	refreshItem;
	private static JMenuItem	linkDspItem;
	private static JMenuItem	unlinkDspItem;
	private static JMenuItem	openDocItem;
	private static JMenuItem	integrateDocItem;
	private static JMenuItem	downloadDocItem;
	private static JMenuItem	downloadAllItem;
	private static JMenuItem	stopActionsItem;
//	private static JMenuItem	shwitchViewItem;
	
	
	private int						status			= STATUS_LOADING_PATIENTS;
	
	
//	private boolean					modified		= false;
	
	private boolean					isLoading		= false;
	
	private boolean					patientsLoaded	= false;
	
	private boolean					documentsLoaded	= false;
	
	private Patient					gecamedPatient;
	
	private Dsp						linkedDsp;
	
	private Dsp						selectedDsp;
	
	private DspListPanel			patientListPanel;
	
	private List<CdaDocument>		selectedDocuments;
	
	private CdaDocumentListPanel	documentListPanel;
	
	private JComboBox				timePeriodBox;
	
	private JButton					connectionStatusButton;
	
	private JButton					presencePasswordButton;
	
	private JButton					refreshButton;
	
	private JButton 				linkPatientButton;
	
	private JButton 				unlinkPatientButton;
	
	private JButton					downloadSelectionButton;
	
//	private JButton					downloadFolderButton;
	
	private JButton 				openDocumentButton;
	
//	private JButton					integrateDocumentButton;
	
//	private JButton					uploadedDocumentsBox;
	
	private JButton					switchDocumentViewButton;
	
	private JButton					stopDownloadsButton;
	
	private boolean					downloadIsRunning = false;
	
	private boolean					allDocumentsLoaded = false;
	
//	private String					patientPresencePassword;
	
//	private int						downloadFolderStatus	= DOWNLOAD_STOPPED;
	
	
	
	/* ======================================== */
	// CONSTRUCTORS
	/* ======================================== */
	
	public ESanteTab ()
	{
		setIcon(ESanteGuiUtils.getIcon(IconNames.ESANTE_LOGO_SQUARE, ESanteGuiUtils.NORMALPIX));
//		setIcon(null);
		setTitle(Translatrix.getTranslationString("esante.eSanteTab"));
		setBackground(GECAMedColors.c_GECAMedBackground);
		
		initComponents();
	}
	
	
	
	/* ======================================== */
	// CLASS BODY
	/* ======================================== */
	
	@Override
	public String getName ()
	{
		return TAB_NAME;
	}
	
	
	@Override
	public void setPatient (Patient newPatient)
	{
		if (gecamedPatient != null && gecamedPatient.equals(newPatient))
			return;
		
//		patientPresencePassword = null;
		patientListPanel.clearPanel();
		allDocumentsLoaded = false;
		
		if (gecamedPatient != null)
		{
			patientESanteTabs.remove(gecamedPatient.getId());
			UserInactivityMonitor.removeDisconnectListner(this);
		}
		
		if (newPatient != null)
			patientListPanel.writePatientDataIntoFields(newPatient);
		
		gecamedPatient	= newPatient;
		setStatus(STATUS_PATIENT_NOT_SET);
		documentsLoaded	= false;
		patientsLoaded	= false;
		
		if (gecamedPatient != null)
		{
			if (gecamedPatient.getIdLuxembourg() != null)
			{
//				linkedDsp	= CDAManagerBean.getInstance().getLinkedDsp(gecamedPatient.getId());
				try
				{
					linkedDsp	= SOAPUtilities.getValidDsp(newPatient, false);
				}
				catch (SendingStoppedException e)
				{
					linkedDsp	= null;
				}
				
				if (linkedDsp == null)
				{
					gecamedPatient.setIdLuxembourg(null);
					CDAManagerBean.getInstance().updateDspOid(null, gecamedPatient.getId(), null);
					PatientManagerModule.getInstance().eSanteIdChanged(null, gecamedPatient.getId());
				}
			}
			else
			{
				linkedDsp	= null;
			}
			patientESanteTabs.put(gecamedPatient.getId(), this);
			UserInactivityMonitor.addDisconnectListener(this);
		}
		else
		{
			linkedDsp	= null;
		}
		getCdaHandler().setDsp(null);
		patientListPanel.setDsp(linkedDsp);
		
		if (super.isVisible() && gecamedPatient != null)
			setVisible(true);
	}
	
	
	public CdaDocumentListPanel getDocumentListPanel ()
	{
		return documentListPanel;
	}
	
	
	public CdaHandler getCdaHandler ()
	{
		return documentListPanel.getCdaHandler();
	}
	
	
	@Override
	public void setVisible (boolean show)
	{
		if (show && !isLoading)
		{
			if (gecamedPatient == null)
			{
				setStatus(STATUS_PATIENT_NOT_SET);
			}
			else if (gecamedPatient.getIdLuxembourg() == null)
			{
				if (!patientsLoaded)
					setStatus(STATUS_LOADING_PATIENTS);
				else
					setStatus(STATUS_MATCHES_LOADED);
			}
			else if (!documentsLoaded) 
			{
				setStatus(STATUS_LOADING_REPOSITORY);
			}
			else
			{
				setStatus(STATUS_REPOSITORY_LOADED);
			}
		}
		
		super.setVisible(show);
		
		if (patientListPanel != null
				&& gecamedPatient != null 
				&& gecamedPatient.isPersistent() 
				&& show && !isLoading 
				&& (
						(gecamedPatient.getIdLuxembourg() != null && !allDocumentsLoaded)
					||	(gecamedPatient.getIdLuxembourg() == null && patientListPanel.wasAlreadyLoaded())))
		{
			allDocumentsLoaded = false;
			UpdateWorker.updateList(this);
		}
	}
	
	
	public void downloadIsRunning (boolean isDownloading)
	{
		downloadIsRunning = isDownloading;
		stopDownloadsButton.setEnabled(isDownloading);
	}
	
	
	/**
	 * This paint checks the status. When a document was linked or unlinked from another 
	 * screen, the refreshing screen should be called, when the window shown the next time.
	 * 
	 * @see javax.swing.JComponent#paint(java.awt.Graphics)
	 */
	@Override
	public void paint (Graphics g)
	{
		super.paint(g);
		
		if (!isLoading 
				&& (status == STATUS_LOADING_PATIENTS
				|| status == STATUS_LOADING_REPOSITORY))
		{
			UpdateWorker.updateList(this);
		}
	}
	
	
//	public void run ()
//	{
//		if (!isLoading 
//				&& (status == STATUS_LOADING_PATIENTS
//				|| status == STATUS_LOADING_REPOSITORY))
//		{
//			UpdateWorker.update(this);
//		}
//	}
	
	
	/* ---------------------------------------- */
	// ESANTE PATIENT LIST LISTENER METHODS
	/* ---------------------------------------- */
	
	public void dspSelected (Dsp dsp) 
	{
		selectedDsp	= dsp;
		
		if (selectedDsp == null)
		{
			linkPatientButton.setEnabled(false);
		}
		else if (STATUS_TABLE[status][ENABLE_LINK_BUTTON])
		{
			linkPatientButton.setEnabled(true);
		}
	}
	
	
	public void dspChosen (Dsp chosenDsp)
	{
		dspChosen(chosenDsp, false);
	}
	
	
	public void dspChosen (Dsp chosenDsp, boolean alreadyApprovedByUser)
	{
		if (!alreadyApprovedByUser && !ComparePatientDataDialog.getInstance().compareData(gecamedPatient, chosenDsp))
			return;
		
		chosenDsp.setPatient(gecamedPatient);
		try
		{
			// save the link in the DB
			linkedDsp	= CDAManagerBean.getInstance().linkDsp(chosenDsp);
		}
		catch (DspLinkingException e)
		{
			linkedDsp	= CDAManagerBean.getInstance().getLinkedDsp(chosenDsp.getPatientId());
			
			if (!linkedDsp.getDspOid().equals(chosenDsp.getDspOid()))
			{
				// warn, if the patient is linked to a different DSP
				GECAMedBaseDialogImpl.showMessageDialog(
						MainFrame.getInstance(), 
						Translatrix.getTranslationString("Patient already linked to an DSP"), 
						Translatrix.getTranslationString("<html>The patient is already linked to another DSP.<br>"
								+ "The existing DSP is loaded instead."), 
						GECAMedBaseDialogImpl.OK_BUTTON_MODE, 
						GECAMedModule.getMediumIcon(GECAMedIconNames.WARNING));
			}
		}
		
		gecamedPatient.setIdLuxembourg(chosenDsp.getDspOid());
//		getCdaHandler().setDsp(linkedDsp);
		
//		linkedDsp.addListDataListener(this);
//		PatientListModule.getInstance().research();
		PatientManagerModule.getInstance().eSanteIdChanged(
				gecamedPatient.getIdLuxembourg(), gecamedPatient.getId());
		
		setStatus(STATUS_PATIENT_MATCHED);
//		updateRepository(true);
		allDocumentsLoaded = false;
		UpdateWorker.updateList(this);
	}
	
	
	
	/* ---------------------------------------- */
	// ESANTE DOCUMENT LIST LISTENER METHODS
	/* ---------------------------------------- */
	
	public void documentSelectionChanged (List<CdaDocument> documents)
	{
		selectedDocuments	= documents;
		enableAndShow(false);
	}
	
	
	public void openDocuments (List<CdaDocument> documents)
	{
		if (documents.size() > 5)
		{
			// warn before opening more than 5 documents
			int option = ESanteDialog.showMessageDialog(
					MainFrame.getInstance(), 
					Translatrix.getTranslationString("esante.eSanteTab.openWarningTitle"), 
					Translatrix.getTranslationString("esante.eSanteTab.openWarning", 
							new String[] { String.valueOf(documents.size()) } ),
					GECAMedBaseDialogImpl.YES_NO_BUTTON_MODE,
					GECAMedModule.getBigIcon(GECAMedIconNames.WARNING));
			
			if (option != GECAMedBaseDialogImpl.YES_OPTION)
				return;
		}
		
		
		for (CdaDocument doc : documents)
			openDocument(doc, false);
	}
	
	
	public void downloadDocuments (List<CdaDocument> documents)
	{
		for (CdaDocument document : documents)
		{
			DocumentWorker.downloadDocument(document, getCdaHandler());
		}
	}
	
	
	public void integrateDocuments (List<CdaDocument> documents)
	{
		for (CdaDocument document : documents)
		{
			DocumentWorker.integrateDocument(document, getCdaHandler());
		}
	}
	
	
	public void startPatientDspDownload ()
	{
		DocumentWorker.downloadAll(getCdaHandler());
	}
	
	
	public void unlinkCurrentPatient ()
	{
		if (ComparePatientDataDialog.getInstance().compareData(gecamedPatient, linkedDsp))
		{
			// remove all items of this patient from the DocumentWorker
			DocumentWorker.dequeuePatient(gecamedPatient);
			
			// unlink the patient and delete the whole DSP, including the download history entries
			CDAManagerBean.getInstance().unlinkDsp(gecamedPatient.getId());
			gecamedPatient.setIdLuxembourg(null);
			linkedDsp = null;
			allDocumentsLoaded = false;
			getCdaHandler().setDsp(null);
			
			// refresh the view
			PatientListModule.getInstance().research();
			PatientManagerModule.getInstance().getPatientPanel().reloadHistory();
			PatientManagerModule.getInstance().eSanteIdChanged(null, gecamedPatient.getId());
			loadMatchingPatients();
		}
	}
	
	
	public void fireDocumentChanged (CdaDocument document)
	{
		getCdaHandler().fireDocumentChanged(document);
	}
	
	
	public void enablePresencePasswordButton ()
	{
		boolean			enable	= false;
		DspPrivileges	privileges;
		
		if (STATUS_TABLE[this.status][SHOW_DOCUMENT_PANEL]
				&& linkedDsp != null)
		{
			privileges	= Security.getCachedDspPrivileges(linkedDsp.getDspOid());
			if (privileges != null
					&& privileges.isPresencePasswordAllowed())
			{
				enable	= true;
			}
		}
		
		presencePasswordButton.setEnabled(enable);
	}
	
	
	/* ---------------------------------------- */
	// LIST DATA LISTENER METHODS
	/* ---------------------------------------- */
	
	public void intervalAdded (ListDataEvent e) {}
	public void intervalRemoved (ListDataEvent e) {}
	
	
	public void contentsChanged (ListDataEvent e)
	{
		enableAndShow(false);
	}
	
	
	/* ---------------------------------------- */
	// DISCONNECT LISTENER METHOD
	/* ---------------------------------------- */
	
	public void disconnected ()
	{
		if (linkedDsp != null)
		{
			linkedDsp.setDocuments(null);
			getCdaHandler().setDsp(linkedDsp);
		}
	}
	
	
	
	/* ======================================== */
	// STATIC METHODS
	/* ======================================== */
	
	public static ESanteTab getESanteTab (Integer patientId)
	{
		return patientESanteTabs.get(patientId);
	}
	
	
	public static Collection<ESanteTab> getESanteTabs ()
	{
		return patientESanteTabs.values();
	}
	
	
	public static void connectionStatusChanged (int status)
	{
		connected = (status == CONNECTION_STATUS_LOGGED_IN);
		
		for (ESanteTab tab : getESanteTabs())
		{
			switch (status)
			{
				case CONNECTION_STATUS_LOGGED_OUT:
					
					tab.connectionStatusButton.setEnabled(false);
					tab.connectionStatusButton.setToolTipText(Translatrix.getTranslationString(
							"esante.eSanteTab.logout.LoggedOutToolTipp"));
					break;
				
				case CONNECTION_STATUS_LOGGED_IN:
					
					tab.connectionStatusButton.setEnabled(true);
					tab.connectionStatusButton.setToolTipText(Translatrix.getTranslationString(
							"esante.eSanteTab.logout.LoggedInToolTipp"));
					break;
			}
		}
	}
	
	
	/**
	 * Checks if the tabs in the list of ESanteTabs still exists.
	 * 
	 * @param existingPatientIds A list of open patient IDs
	 */
	public static void checkExistence (Set<Integer> existingPatientIds)
	{
		Collection<Integer>	patientTabIds2Destruct	= new LinkedList<Integer>();
		
		
		synchronized (patientESanteTabs)
		{
			for (Integer tabPatientId : patientESanteTabs.keySet())
			{
				if (tabPatientId != null && !existingPatientIds.contains(tabPatientId))
					patientTabIds2Destruct.add(tabPatientId);
			}
			
			ESanteTab tab;
			for (Integer tabPatientId : patientTabIds2Destruct)
			{
				tab = patientESanteTabs.get(tabPatientId);
				// remove the tab from the list of existing tabs
				patientESanteTabs.remove(tabPatientId);
				// remove the tab as DisconnectListener
				UserInactivityMonitor.removeDisconnectListner(tab);
			}
		}
	}
	
	
	public static JMenu getMenu ()
	{
		if (eSanteMenu == null)
		{
			disconnectItem			= new JMenuItem(new AbstractAction(
					Translatrix.getTranslationString("esante.eSanteTab.menu.disconnect"),
					ESanteGuiUtils.getIcon(IconNames.DISCONNECT, IconFetcher.SMALLPIX))
			{
				private static final long	serialVersionUID	= 1L;
	
				public void actionPerformed (ActionEvent e)
				{
					UserInactivityMonitor.logout("esante.eSanteTab.logout.manualLogoutMessage");
				}
			});
			
			presencePasswordItem	= new JMenuItem(new AbstractAction(
					Translatrix.getTranslationString("esante.eSanteTab.menu.presencePassword"),
					GECAMedModule.getSmallIcon(GECAMedIconNames.PASSWORD))
			{
				private static final long	serialVersionUID	= 1L;
	
				public void actionPerformed (ActionEvent e)
				{
					Patient currentPatient = GECAMedModule.getCurrentPatient();
					ESanteTab tab;
					
					
					if (!currentPatient.isPersistent())
						return;
					
					tab = ESanteTab.getESanteTab(currentPatient.getId());
					
					if (tab != null)
						tab.askForPresencePassword();
				}
			});
			
			refreshItem	= new JMenuItem(new AbstractAction(
					Translatrix.getTranslationString("esante.eSanteTab.menu.refresh"),
					GECAMedModule.getSmallIcon(GECAMedIconNames.RELOAD))
			{
				private static final long	serialVersionUID	= 1L;
	
				public void actionPerformed (ActionEvent e)
				{
					Patient currentPatient = GECAMedModule.getCurrentPatient();
					ESanteTab tab;
					
					
					if (!currentPatient.isPersistent())
						return;
					
					tab = ESanteTab.getESanteTab(currentPatient.getId());
					
					if (tab != null)
						UpdateWorker.updateList(tab);
				}
			});
			
			linkDspItem	= new JMenuItem(new AbstractAction(
					Translatrix.getTranslationString("esante.eSanteTab.menu.link"),
					ESanteGuiUtils.getIcon(IconNames.LINK_PATIENT, IconFetcher.SMALLPIX))
			{
				private static final long	serialVersionUID	= 1L;
	
				public void actionPerformed (ActionEvent e)
				{
					Patient currentPatient = GECAMedModule.getCurrentPatient();
					ESanteTab tab;
					
					
					if (!currentPatient.isPersistent())
						return;
					
					tab = ESanteTab.getESanteTab(currentPatient.getId());
					
					if (tab != null)
						tab.dspChosen(tab.selectedDsp);
				}
			});
			
			unlinkDspItem	= new JMenuItem(new AbstractAction(
					Translatrix.getTranslationString("esante.eSanteTab.menu.unlink"),
					ESanteGuiUtils.getIcon(IconNames.UNLINK_PATIENT, IconFetcher.SMALLPIX))
			{
				private static final long	serialVersionUID	= 1L;
	
				public void actionPerformed (ActionEvent e)
				{
					Patient currentPatient = GECAMedModule.getCurrentPatient();
					ESanteTab tab;
					
					
					if (!currentPatient.isPersistent())
						return;
					
					tab = ESanteTab.getESanteTab(currentPatient.getId());
					
					if (tab != null)
						tab.unlinkCurrentPatient();
				}
			});
			
			openDocItem	= new JMenuItem(new AbstractAction(
					Translatrix.getTranslationString("esante.eSanteTab.menu.open"),
					GECAMedModule.getSmallIcon(GECAMedIconNames.OPEN))
			{
				private static final long	serialVersionUID	= 1L;
	
				public void actionPerformed (ActionEvent e)
				{
					Patient currentPatient = GECAMedModule.getCurrentPatient();
					ESanteTab tab;
					
					
					if (!currentPatient.isPersistent())
						return;
					
					tab = ESanteTab.getESanteTab(currentPatient.getId());
					
					if (tab != null)
						tab.openDocuments(tab.selectedDocuments);
				}
			});
			
			integrateDocItem	= new JMenuItem(new AbstractAction(
					Translatrix.getTranslationString("esante.eSanteTab.menu.integrate"),
					ESanteGuiUtils.getIcon(IconNames.INTEGRATE_DOC, IconFetcher.SMALLPIX))
			{
				private static final long	serialVersionUID	= 1L;
	
				public void actionPerformed (ActionEvent e)
				{
					Patient currentPatient = GECAMedModule.getCurrentPatient();
					ESanteTab tab;
					
					
					if (!currentPatient.isPersistent())
						return;
					
					tab = ESanteTab.getESanteTab(currentPatient.getId());
					
					if (tab != null)
						tab.integrateDocuments(tab.selectedDocuments);
				}
			});
			
			downloadDocItem	= new JMenuItem(new AbstractAction(
					Translatrix.getTranslationString("esante.eSanteTab.menu.download"),
					ESanteGuiUtils.getIcon(IconNames.DOWNLOAD, IconFetcher.SMALLPIX))
			{
				private static final long	serialVersionUID	= 1L;
	
				public void actionPerformed (ActionEvent e)
				{
					Patient currentPatient = GECAMedModule.getCurrentPatient();
					ESanteTab tab;
					
					
					if (!currentPatient.isPersistent())
						return;
					
					tab = ESanteTab.getESanteTab(currentPatient.getId());
					
					if (tab != null)
						tab.downloadDocuments(tab.selectedDocuments);
				}
			});
			
			downloadAllItem	= new JMenuItem(new AbstractAction(
					Translatrix.getTranslationString("esante.eSanteTab.menu.downloadAll"),
					ESanteGuiUtils.getIcon(IconNames.DOWNLOAD_FOLDER, IconFetcher.SMALLPIX))
			{
				private static final long	serialVersionUID	= 1L;
	
				public void actionPerformed (ActionEvent e)
				{
					Patient currentPatient = GECAMedModule.getCurrentPatient();
					ESanteTab tab;
					
					
					if (!currentPatient.isPersistent())
						return;
					
					tab = ESanteTab.getESanteTab(currentPatient.getId());
					
					if (tab != null)
						tab.startPatientDspDownload();
				}
			});
			
			stopActionsItem	= new JMenuItem(new AbstractAction(
					Translatrix.getTranslationString("esante.eSanteTab.menu.stop"),
					ESanteGuiUtils.getIcon(IconNames.STOP_DOWNLOAD, IconFetcher.SMALLPIX))
			{
				private static final long	serialVersionUID	= 1L;
	
				public void actionPerformed (ActionEvent e)
				{
					DocumentWorker.dequeuePatient(GECAMedModule.getCurrentPatient());
				}
			});
			
	
			eSanteMenu	= new JMenu(Translatrix.getTranslationString("esante.eSanteTab.menu.esante"));
			eSanteMenu.addMenuListener(new MenuListener()
			{
				public void menuSelected (MenuEvent e)
				{
					enableMenuItems();
				}
				
				public void menuDeselected (MenuEvent e) {}
				public void menuCanceled (MenuEvent e) {}
			});
			
			eSanteMenu.add(disconnectItem);
			eSanteMenu.add(presencePasswordItem);
			eSanteMenu.add(refreshItem);
			eSanteMenu.add(linkDspItem);
			eSanteMenu.add(unlinkDspItem);
			eSanteMenu.add(openDocItem);
			eSanteMenu.add(integrateDocItem);
			eSanteMenu.add(downloadDocItem);
			eSanteMenu.add(downloadAllItem);
			eSanteMenu.add(stopActionsItem);
			
			enableMenuItems();
		}
		
		return eSanteMenu;
	}
	
	
	
	/* ======================================== */
	// HELP METHODS
	/* ======================================== */
	
	private void initComponents ()
	{
		connectionStatusButton	= new JButton(new AbstractAction("",
				ESanteGuiUtils.getIcon(IconNames.DISCONNECT, 32))
		{
			private static final long	serialVersionUID	= 1L;

			public void actionPerformed (ActionEvent e)
			{
				UserInactivityMonitor.logout("esante.eSanteTab.logout.manualLogoutMessage");
			}
		});
		connectionStatusButton.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
		connectionStatusButton.setMargin(new java.awt.Insets(3, 3, 3, 3));
		connectionStatusButton.setMargin(new java.awt.Insets(3, 3, 3, 3));
		connectionStatusButton.setFocusable(false);
		connectionStatusButton.setContentAreaFilled(false);
		connectionStatusButton.setBorderPainted(true);
		connectionStatusButton.setEnabled(Security.isConnected());
		connectionStatusButton.addMouseListener(new MouseAdapter() 
		{
			@Override
			public void mouseEntered (MouseEvent e) 
			{
				connectionStatusButton.setContentAreaFilled(true);
			}
			
			@Override
			public void mouseExited (MouseEvent e) 
			{
				connectionStatusButton.setContentAreaFilled(false);
			}
		});
		
		// time period chooser
		timePeriodBox			= new JComboBox(TIME_PERIODS);
		timePeriodBox.setToolTipText(Translatrix.getTranslationString("esante.eSanteTab.timePeriod"));
		timePeriodBox.setRenderer(new LineColorListRenderer()
		{
			private static final long	serialVersionUID	= 1L;
			
			@Override
			public Component getListCellRendererComponent (JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
			{
				JLabel cell = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
				
				if (index >= 0 && index < TIME_PERIODS.length)
					cell.setToolTipText(String.valueOf(TIME_PERIODS[index].getValue(1)));
				
				return cell;
			}
		});
		JPanel timePeriodPanel	= new JPanel(new FormLayout("f:p", "c:p:g"));
		timePeriodPanel.add(timePeriodBox, new CellConstraints(1, 1));
		timePeriodPanel.setOpaque(false);
		
		// presence password button
		presencePasswordButton	= new JButton(new AbstractAction("", 
				GECAMedModule.getScaledIcon(GECAMedIconNames.PASSWORD, IconFetcher.NORMALPIX))
		{
			private static final long	serialVersionUID	= 1L;

			public void actionPerformed (ActionEvent e)
			{
				askForPresencePassword();
			}
		});
		presencePasswordButton.setToolTipText(Translatrix.getTranslationString("esante.eSanteTab.askPresencePassword"));
		
		// refresh button
		refreshButton	= new JButton(new AbstractAction(
				"", GECAMedModule.getScaledIcon(GECAMedIconNames.RELOAD, IconFetcher.NORMALPIX))
		{
			private static final long	serialVersionUID	= 1L;
			
			public void actionPerformed (ActionEvent e)
			{
				UpdateWorker.updateList(ESanteTab.this);
			}
		});
		refreshButton.setToolTipText(Translatrix.getTranslationString("esante.eSanteTab.refreshTip"));
		
		// link patient button
		linkPatientButton	= new JButton(new AbstractAction(
				"", ESanteGuiUtils.getIcon(IconNames.LINK_PATIENT, ESanteGuiUtils.NORMALPIX))
		{
			private static final long	serialVersionUID	= 1L;

			public void actionPerformed (ActionEvent e)
			{
				dspChosen(selectedDsp);
			}
		});
		linkPatientButton.setToolTipText(Translatrix.getTranslationString(
				"esante.eSanteTab.linkWithDspTip"));
		
		// unlink patient button
		unlinkPatientButton	= new JButton(new AbstractAction(
				"", ESanteGuiUtils.getIcon(IconNames.UNLINK_PATIENT, ESanteGuiUtils.NORMALPIX))
		{
			private static final long	serialVersionUID	= 1L;

			public void actionPerformed (ActionEvent e)
			{
				unlinkCurrentPatient();
			}
		});
		unlinkPatientButton.setToolTipText(Translatrix.getTranslationString(
				"esante.eSanteTab.unlinkFromDspTip"));
		
		// Attention the eHealth Agency requested to prevent batch download of all documents
		
		// download all shown and not downloaded documents 
//		downloadFolderButton = new JButton(new AbstractAction(
//				"", ESanteGuiUtils.getIcon(IconNames.DOWNLOAD_FOLDER, 32))
//		{
//			private static final long	serialVersionUID	= 1L;
//
//			public synchronized void actionPerformed (ActionEvent e)
//			{
//				startPatientDspDownload();
//			}
//		});
//		downloadFolderButton.setToolTipText(Translatrix.getTranslationString("esante.eSanteTab.downloadDspTip"));
		
		// open document button
		openDocumentButton	= new JButton(new AbstractAction(
				"", GECAMedModule.getScaledIcon(GECAMedIconNames.OPEN, IconFetcher.NORMALPIX))
		{
			private static final long	serialVersionUID	= 1L;
			
			public void actionPerformed (ActionEvent e)
			{
				openDocuments(selectedDocuments);
			}
		});
		openDocumentButton.setToolTipText(Translatrix.getTranslationString(
				"esante.eSanteTab.openDocumentTip"));
		
		// download selection button
		downloadSelectionButton	= new JButton(new AbstractAction("",
				ESanteGuiUtils.getIcon(IconNames.DOWNLOAD, 32))
		{
			private static final long	serialVersionUID	= 1L;
			
			public void actionPerformed (ActionEvent e)
			{
				downloadDocuments(selectedDocuments);
			}
		});
		downloadSelectionButton.setToolTipText(Translatrix.getTranslationString(
				"esante.eSanteTab.downloadDocumentTip"));
		
		// Luxembourgish eHealth Agency requires not to batch download and integrate documents
		// integrate document into GECAMed button
//		integrateDocumentButton	= new JButton(new AbstractAction("",
//				ESanteGuiUtils.getIcon(IconNames.INTEGRATE_DOC, ESanteGuiUtils.NORMALPIX))
//		{
//			private static final long	serialVersionUID	= 1L;
//			
//			public void actionPerformed (ActionEvent e)
//			{
//				integrateDocuments(selectedDocuments);
//			}
//		});
//		integrateDocumentButton.setToolTipText(Translatrix.getTranslationString(
//				"esante.eSanteTab.integrateDocumentTip"));
		
		switchDocumentViewButton = new JButton(new AbstractAction("", null)
		{
			private static final long	serialVersionUID	= 1L;

			public void actionPerformed (ActionEvent e)
			{
				documentListPanel.switchView();
			}
		});
		
		stopDownloadsButton		= new JButton(new AbstractAction("",
				ESanteGuiUtils.getIcon(IconNames.STOP_DOWNLOAD, 32))
		{
			private static final long	serialVersionUID	= 1L;

			public void actionPerformed (ActionEvent e)
			{
				DocumentWorker.dequeuePatient(gecamedPatient);
			}
		});
		stopDownloadsButton.setToolTipText(Translatrix.getTranslationString("esante.eSanteTab.stopProcessTip"));
		
		// create the panels
		patientListPanel	= new DspListPanel(true);
		patientListPanel.setVisible(false);
		patientListPanel.addPatientListListener(this);
		documentListPanel	= new CdaDocumentListPanel(switchDocumentViewButton);
		documentListPanel.setVisible(false);
		documentListPanel.addDocumentListener(this);

		ButtonPanel buttonPanel = new ButtonPanel(Color.PINK);
//		buttonPanel.setTitle("", ESanteUtils.getESanteIcon(64));
		buttonPanel.setTitle(connectionStatusButton);
		
		// add the button order and define their order
		buttonPanel.addButton(presencePasswordButton);
		buttonPanel.addSeparator();
		buttonPanel.addButton(refreshButton);
		buttonPanel.addButton(timePeriodPanel);
		buttonPanel.addSeparator();
		buttonPanel.addButton(linkPatientButton);
		buttonPanel.addButton(unlinkPatientButton);
		buttonPanel.addSeparator();
		buttonPanel.addButton(openDocumentButton);
//		buttonPanel.addButton(integrateDocumentButton);
		buttonPanel.addButton(downloadSelectionButton);
//		buttonPanel.addButton(downloadFolderButton);
		buttonPanel.addButton(stopDownloadsButton);
		buttonPanel.addSeparator();
		buttonPanel.addButton(switchDocumentViewButton);
		
		buttonPanel.validate();
		
		setLayout(new FormLayout(
				// columns 
				"0px, f:p:g, 0px",
				// rows 
				"0px, f:p, 5px, f:p:g, 0px"));
		CellConstraints cc	= new CellConstraints();
		add(buttonPanel,		cc.xy(2, 2));
		
		documentListPanel.switchView(CdaDocumentListPanel.SHOW_TREE);
		
		EntryTypeRegister.registerHandler(IncidentManager.CDA, new CdaHistoryHandler(this));
	}
	

	/**
	 * Use only the UpdateWorker to call this method
	 */
	void refreshList ()
	{
		if (status >= STATUS_PATIENT_MATCHED)
		{
			updateRepository();
		}
		else if (status >= STATUS_PATIENT_NOT_LINKED)
		{
			loadMatchingPatients();
		}
	}
	
	
	private void loadMatchingPatients ()
	{
		setStatus(STATUS_LOADING_PATIENTS);
		patientsLoaded	= false;
		selectedDsp	= null;
		
		if (gecamedPatient == null) // || linkedDsp == null)
			return;
		
		try
		{
			isLoading		= true;
			
			if (!this.isShowing())
				return;
			
			Boolean loaded = patientListPanel.queryPatients();
			
			if (status >= STATUS_PATIENT_MATCHED)
				return;
			
			if (loaded == null)
				setStatus(STATUS_PATIENT_NOT_LINKED);
			else if (Boolean.TRUE.equals(loaded))
				patientsLoaded = true;
			
			setStatus(STATUS_MATCHES_LOADED);
		}
		catch (Exception e)
		{
			logger.log(Level.ERROR, e.getMessage(), e);
			setStatus(STATUS_PATIENT_NOT_LINKED);
		}
		finally
		{
			isLoading	= false;
		}
	}
	
	
	private  void updateRepository ()
	{
		updateRepository(null);
	}
	
	
	private synchronized void updateRepository (String presencePassword)
	{
		ComboBoxElement<?>	selectedElement;
		Integer				years;
		Date				querySince;
		
		documentsLoaded	= false;
		setStatus(STATUS_LOADING_REPOSITORY);
		
		if (!allDocumentsLoaded)
		{
			documentListPanel.clearPanel();
			documentListPanel.setData(linkedDsp);
			allDocumentsLoaded = true;
		}
		
		if (!this.isShowing())
			return;
		
		
		SoapSender sender = new SoapSender(linkedDsp, false);
		sender.setPresencePassword(presencePassword);
		
		// define to query since when
		selectedElement	= (ComboBoxElement<?>) timePeriodBox.getSelectedItem();
		years			= (Integer) selectedElement.getValue();
		
		if (years != null)
		{
			Calendar	cal	= new GregorianCalendar(TimeZone.getTimeZone("UTC"));
			GECAMedUtils.setTime2Zero(cal);
			cal.add(Calendar.YEAR, years.intValue() * (-1));
			querySince		= cal.getTime();
		}
		else
		{
			querySince	= null;
		}
		sender.setQuerySince(querySince);
		
		try
		{
			requestNewDocuments(sender);
		}
		finally
		{
			if (documentsLoaded)
			{
				setStatus(STATUS_REPOSITORY_LOADED);
			}
			else
			{
				setStatus(STATUS_PATIENT_MATCHED);
			}
			isLoading = false;
		}
	}
	
	
	private void requestNewDocuments (SoapSender sender)
	{
		isLoading = true;
		
//		sender.setPresencePassword(patientPresencePassword);
		try
		{
			XDS.loadDocuments(sender, getCdaHandler());
			documentsLoaded	= true;
		}
		catch (SocketException e)
		{
			ESanteGuiUtils.showConnectionError(e);
		}
		catch (HtmlErrorCodeException e)
		{
			ESanteGuiUtils.showHtmlErrorCodeException(e.getMessage());
		}
		catch (SendingStoppedException e)
		{
			// user cancelled the operation, simply log it as warning and return
			setStatus(STATUS_PATIENT_MATCHED);
			logger.info(e.getMessage());
		}
		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());
					break;

				case WebserviceException.TYPE_SERVER:

					ESanteGuiUtils.showConnectionError(e);
					break;
				
				default:
					
					ESanteGuiUtils.showAndLogWebserviceException(e);
					break;
			}
		}
		catch (Exception e)
		{
			StringWriter writer = new StringWriter();
			e.printStackTrace(new PrintWriter(writer));
			
			ErrorDialog.showESanteErrorDialog(MainFrame.getInstance(), 
					"Unexpected exception: "+e.getMessage(), 
					writer.toString(), 
					linkedDsp.getPatientId(), 
					"Unhandled_Exception");
			logger.log(Level.ERROR, e.getMessage(), e);
		}
	}
	
	
	private void openDocument (CdaDocument doc, boolean integrate)
	{
		DocumentWorker.openDocument(doc, getCdaHandler(), integrate);
	}
	
	
	private void setStatus (int status)
	{
		int oldStatus	= this.status;
		this.status		= status;
		
		if (oldStatus != status)
			enableAndShow(true);
	}
	
	
	private void enableAndShow (boolean reloadList)
	{
		boolean[]	options				= STATUS_TABLE[this.status];
		boolean		documentSelected	= selectedDocuments != null && !selectedDocuments.isEmpty();
		boolean		enableDownload		= documentSelected && ESanteUtils.containsDownloadableDocument(selectedDocuments);
		boolean		enableIntegrate		= documentSelected && ESanteUtils.containsIntegratableDocument(selectedDocuments);
		
		
		// show & hide panels
		if (reloadList && options[SHOW_PATIENT_PANEL])
		{
			remove(documentListPanel);
			add(patientListPanel, new CellConstraints(2, 4));
			patientListPanel.setVisible(true);
		}
		else if (reloadList && options[SHOW_DOCUMENT_PANEL])
		{
			remove(patientListPanel);
			add(documentListPanel, new CellConstraints(2, 4));
			documentListPanel.setVisible(true);
		}
		enablePresencePasswordButton();
		
		// enable & disable buttons
		refreshButton.setEnabled(			options[ENABLE_REFRESH_BUTTON]);
		linkPatientButton.setEnabled(		options[ENABLE_LINK_BUTTON] && selectedDsp != null);
		unlinkPatientButton.setEnabled(		options[ENABLE_UNLINK_BUTTON]);
//		downloadFolderButton.setEnabled(	options[ENABLE_DOCUMENT_BUTTONS] );
		openDocumentButton.setEnabled(		options[ENABLE_DOCUMENT_BUTTONS] && documentSelected);
		downloadSelectionButton.setEnabled(	options[ENABLE_DOCUMENT_BUTTONS] && documentSelected && enableDownload);
//		integrateDocumentButton.setEnabled(	options[ENABLE_DOCUMENT_BUTTONS] && documentSelected && enableIntegrate);
		switchDocumentViewButton.setEnabled(options[ENABLE_DOCUMENT_BUTTONS]);
		stopDownloadsButton.setEnabled(		options[ENABLE_DOCUMENT_BUTTONS] && downloadIsRunning);
		
		this.validate();
		this.repaint();
	}
	
	
	private static void enableMenuItems ()
	{
		Patient		patient	= GECAMedModule.getCurrentPatient();
		ESanteTab	tab		= (patient == null || !patient.isPersistent()) 
				? null 
				: ESanteTab.getESanteTab(patient.getId());
		
		
		// this is independent of the current ESanteTab
		disconnectItem.setEnabled(connected);
		
		if (tab == null || tab.status <= STATUS_PATIENT_NOT_SET)
		{
			// no valid patient or no ESanteTab for this patient opened, yet
			presencePasswordItem.setEnabled(false);
			refreshItem.setEnabled(false);
			linkDspItem.setEnabled(false);
			unlinkDspItem.setEnabled(false);
			downloadAllItem.setEnabled(false);
			openDocItem.setEnabled(false);
			downloadDocItem.setEnabled(false);
			integrateDocItem.setEnabled(false);
			stopActionsItem.setEnabled(false);
			refreshItem.setEnabled(false);
		}
		else
		{
			// TODO set the menu items like their according buttons 
			presencePasswordItem.setEnabled(tab.presencePasswordButton.isEnabled());
			refreshItem.setEnabled(tab.refreshButton.isEnabled());
			linkDspItem.setEnabled(tab.linkPatientButton.isEnabled());
			unlinkDspItem.setEnabled(tab.unlinkPatientButton.isEnabled());
	//		downloadAllItem.setEnabled(tab.downloadFolderButton.isEnabled());
			openDocItem.setEnabled(tab.openDocumentButton.isEnabled());
			downloadDocItem.setEnabled(tab.downloadSelectionButton.isEnabled());
//			integrateDocItem.setEnabled(tab.integrateDocumentButton.isEnabled());
			stopActionsItem.setEnabled(tab.stopDownloadsButton.isEnabled());
			refreshItem.setEnabled(true);
		}
	}
	
	
	private void askForPresencePassword()
	{
		String presencePassword	= ESanteDialog.showInputMessageDialog(
				MainFrame.getInstance(), 
				Translatrix.getTranslationString("esante.eSanteTab.presencePassword"), 
				Translatrix.getTranslationString("esante.eSanteTab.enterPresencePassword"), 
				"");
		
		if (presencePassword != null)
		{
			updateRepository(presencePassword);
		}
	}
}
