/*****************************************************************************
 *                                                                           *
 *  Copyright (c) 2010 by SANTEC/TUDOR www.santec.tudor.lu                   *
 *                                                                           *
 *                                                                           *
 *  This library is free software; you can redistribute it and/or modify it  *
 *  under the terms of the GNU Lesser General Public License as published    *
 *  by the Free Software Foundation; either version 2 of the License, or     *
 *  (at your option) any later version.                                      *
 *                                                                           *
 *  This software 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 along with this library; if not, write to the Free Software      *
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA  *
 *                                                                           *
 *****************************************************************************/
package lu.tudor.santec.gecamed.patient.gui;

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import javax.naming.InitialContext;
import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.TransferHandler;
import javax.swing.text.html.HTMLEditorKit;

import lu.tudor.santec.gecamed.agenda.ejb.entity.beans.Appointment;
import lu.tudor.santec.gecamed.agenda.gui.AgendaModule;
import lu.tudor.santec.gecamed.billing.gui.BillingModule;
import lu.tudor.santec.gecamed.billing.gui.templates.InvoiceTemplateDialog;
import lu.tudor.santec.gecamed.billing.gui.templates.TemplateManager;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.Gender;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.Language;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.Nationality;
import lu.tudor.santec.gecamed.core.gui.GECAMedAction;
import lu.tudor.santec.gecamed.core.gui.GECAMedFonts;
import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.GECAMedLog;
import lu.tudor.santec.gecamed.core.gui.GECAMedMessage;
import lu.tudor.santec.gecamed.core.gui.GECAMedMessageListener;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.GECAMedOptionPane;
import lu.tudor.santec.gecamed.core.gui.IconFetcher;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.ModuleManager;
import lu.tudor.santec.gecamed.core.gui.PatientListener;
import lu.tudor.santec.gecamed.core.gui.RegistrationDesk;
import lu.tudor.santec.gecamed.core.gui.listener.EntryTypeRegister;
import lu.tudor.santec.gecamed.core.gui.listener.GlobalHotkeyRegister;
import lu.tudor.santec.gecamed.core.gui.widgets.StatusBar;
import lu.tudor.santec.gecamed.core.gui.widgets.hotkeys.HotkeySettingsPlugin;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.core.utils.SSNChecker;
import lu.tudor.santec.gecamed.esante.gui.tab.ESanteTab;
import lu.tudor.santec.gecamed.esante.gui.utils.ESanteGuiUtils;
import lu.tudor.santec.gecamed.importexport.gui.export.ExportDialog;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Incident;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.PatientAddress;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.PatientMemo;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.PatientPhone;
import lu.tudor.santec.gecamed.patient.ejb.session.beans.IncidentManagerBean;
import lu.tudor.santec.gecamed.patient.ejb.session.beans.PatientAdminBean;
import lu.tudor.santec.gecamed.patient.ejb.session.beans.PatientMemoManagerBean;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.IPatientPermissions;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.IncidentManager;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.PatientAdminInterface;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.PatientMemoInterface;
import lu.tudor.santec.gecamed.patient.gui.administrative.AdministrativeElementsPlugin;
import lu.tudor.santec.gecamed.patient.gui.administrative.RelationSelector;
import lu.tudor.santec.gecamed.patient.gui.fileimport.FileImportDialog;
import lu.tudor.santec.gecamed.patient.gui.history.AccidentHandler;
import lu.tudor.santec.gecamed.patient.gui.history.FileHandler;
import lu.tudor.santec.gecamed.patient.gui.history.MeasurementHandler;
import lu.tudor.santec.gecamed.patient.gui.history.PrescriptionHandler;
import lu.tudor.santec.gecamed.patient.gui.history.SickLeaveHandler;
import lu.tudor.santec.gecamed.patient.gui.history.SoapHandler;
import lu.tudor.santec.gecamed.patient.gui.patientexport.PatientExportPanel;
import lu.tudor.santec.gecamed.patient.gui.patientlist.PatientSearchDialog;
import lu.tudor.santec.gecamed.patient.gui.settings.PatientModuleSettings;
import lu.tudor.santec.gecamed.patient.gui.simpleview.SimpleViewSettingsPlugin;
import lu.tudor.santec.gecamed.patient.utils.PatientUpdateObject;
import lu.tudor.santec.gecamed.patient.utils.SettingConstants;
import lu.tudor.santec.gecamed.prescription.ejb.session.interfaces.PrescriptionManager;
import lu.tudor.santec.gecamed.prescription.gui.PrescriptionIcons;
import lu.tudor.santec.gecamed.prescription.gui.drug.ImportDrugsDialog;
import lu.tudor.santec.gecamed.prescription.gui.drug.lists.cefip.CefipDrugListModule;
import lu.tudor.santec.gecamed.prescription.gui.util.NewDrugWorker;
import lu.tudor.santec.gecamed.prescription.gui.widgets.drugbrowser.DrugBrowser;
import lu.tudor.santec.gecamed.usermanagement.gui.AdminModule;
import lu.tudor.santec.gecamed.usermanagement.gui.settings.UserSettingsPlugin;
import lu.tudor.santec.gecamed.waitingroom.gui.WaitingroomModule;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.RowSpec;
import com.jgoodies.forms.layout.Sizes;

/**
 * The PatientManagerModule is the base module for viewing and manipulation
 * patient files. It is a default module of the GECAMed system. The
 * ModuleManager creates exactly one instance of this class.
 * 
 * 
 * 
 * @author martin.heinemann@tudor.lu
 * @author Johannes Hermen johannes.hermen 21.01.2008 12:59:29
 * 
 * 
 * @version <br>
 *          $Log: PatientManagerModule.java,v $
 *          Revision 1.191  2014-02-04 10:08:37  ferring
 *          eSante ID management completed
 *          Only those documents will be shown, that are retrieved by the RSQ
 *
 *          Revision 1.190  2013-11-29 09:10:52  ferring
 *          first changes for eSanté test platform
 *
 *          Revision 1.189  2013-10-28 16:54:45  ferring
 *          show and hide eSante icon
 *
 *          Revision 1.188  2013-10-21 08:22:03  ferring
 *          linking and unlinking patient changed
 *          dequeuing downloads
 *
 *          Revision 1.187  2013-10-10 13:15:27  ferring
 *          new picture fitted
 *
 *          Revision 1.186  2013-09-04 15:33:26  troth
 *          The new consultation view with more entries and the sickleave version 2 history view work now.
 *
 *          Revision 1.185  2013-07-15 06:18:35  ferring
 *          logging changed
 *
 *          Revision 1.184  2013-06-10 08:22:14  ferring
 *          eSante POC
 *
 *          Revision 1.183  2013-01-10 12:54:46  ferring
 *          system exit method changed
 *
 *          Revision 1.182  2013-01-10 09:43:11  ferring
 *          error catching and logging before closing improved
 *
 *          Revision 1.181  2013-01-02 13:19:15  ferring
 *          Unsaved-Data-Dialog changed
 *
 *          Revision 1.180  2012-12-18 15:47:08  troth
 *          Fix Ticket #1120.
 *
 *          Revision 1.179  2012-11-16 10:34:55  ferring
 *          Drag and Drop of files into the patient module will call the FileImportDialog with this files included
 *
 *          Revision 1.178  2012-10-04 12:21:30  troth
 *          Ticket #1000 and parts of ticket #530.
 *
 *          Revision 1.177  2012-10-03 12:24:33  troth
 *          Implement ticket #1000.
 *
 *          Revision 1.176  2012-07-09 13:41:12  troth
 *          DR.G
 *
 *          Revision 1.175  2012-03-05 16:44:25  troth
 *          First version of the MedLogin Button.
 *
 *          Revision 1.174  2012-03-05 10:26:13  troth
 *          *** empty log message ***
 *
 *          Revision 1.173  2012-03-05 10:09:14  troth
 *          Add new MedLogin Button in patient panel on the functionbar.
 *
 *          Revision 1.172  2012-02-24 07:25:36  ferring
 *          Temporarily fix to let the nightly build run correctly.
 *
 *          Revision 1.171  2012-01-25 14:21:41  troth
 *          1. Add scrollbar to the PatientNaviBar.
 *          2. Add tooltips to the buttons.
 *
 *          Revision 1.170  2011-08-24 11:38:56  ferring
 *          Took class body out of method
 *
 *          Revision 1.169  2011-03-10 06:53:33  ferring
 *          bug fixed, where all global GECAMedAction had been shown in the patient module top bar, independent of they were specified to be a top button action or not.
 *          Now they are only shown, if they ought to be a top button action.
 *
 *          Revision 1.168  2011-02-28 15:41:45  troth
 *          To provide smaller resolutions for the user interface add the navigation bar icons and function bar icons to the user setting "use small icons"
 *
 *          Revision 1.167  2010-09-28 16:12:28  troth
 *          Complete - # 663: Accident entry can not be individually deleted from the history view.
 *          http://santec.tudor.lu/trac/gecamed/ticket/663
 *
 *          Revision 1.166  2010-09-02 11:20:03  troth
 *          fix wrong call of function GECAMedOptionPane.showOptionDialog
 *
 *          Revision 1.165  2010-08-31 13:35:56  troth
 *          Incomplete - # 495: Mehrere Unstimmigkeiten mit Unfallnummer (auch #529)
 *          http://santec.tudor.lu/trac/gecamed/ticket/495
 *          and Tickets 529, 613
 *          and new/redesign of AccidentPanel
 *
 *          Revision 1.164  2010-07-05 12:17:10  hermen
 *          *** empty log message ***
 *
 *          Revision 1.163  2010-06-09 07:45:30  hermen
 *          fixed "close patienttab on cancel action" bug
 *
 *          Revision 1.162  2010-06-09 06:41:39  hermen
 *          *** empty log message ***
 *
 *          Revision 1.161  2010-05-05 11:24:45  ferring
 *          *** empty log message ***
 *
 *          Revision 1.160  2010-04-27 14:36:37  troth
 *          GECAMedOptionPane create now only a simple JOptionPane. May be later we build our own optionpane.
 *
 *          Revision 1.159  2010-04-23 07:08:01  gbosch
 *          added constant
 *
 *          Revision 1.158  2010-03-30 10:53:23  troth
 *          Redesign of the prescription view - change icon manager class
 *
 *          Revision 1.157  2010-03-23 15:08:25  troth
 *          Redesign of the patient view history
 *
 *          Revision 1.156  2010-03-19 12:01:06  hermen
 *          improved and unified iconfetching
 *
 *          Revision 1.155  2009-12-14 15:34:31  hermen
 *          fixed NULL entries in history
 *
 *          Revision 1.154  2009-12-14 09:54:58  hermen
 *          *** empty log message ***
 *
 *          Revision 1.153  2009-12-09 11:59:15  hermen
 *          fixed java6 issue
 *
 *          Revision 1.152  2009-12-02 13:38:41  hermen
 *          *** empty log message ***
 *
 *          Revision 1.151  2009-10-30 09:58:55  hermen
 *          added departed status to patient
 *
 *          Revision 1.150  2009-10-06 14:16:13  hermen
 *          added isVisit to waitingroom entry
 *
 *          Revision 1.149  2009-09-07 09:23:29  hermen
 *          fixed ismodified and hang after "to many patients open" issues
 *
 *          Revision 1.148  2009-06-30 12:24:56  hermen
 *          *** empty log message ***
 * <br>
 *          Revision 1.147 2009-05-29 13:51:21 hermen <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.146 2009-03-16 14:17:27 hermen <br>
 *          added patient incident statistics <br>
 * <br>
 *          Revision 1.145 2009-02-27 09:03:20 heinemann <br>
 *          huups. Import cefip action was .... absent <br>
 * <br>
 *          Revision 1.144 2009-01-22 10:32:30 hermen <br>
 *          added and implemented right PERMISSION_CHANGE_PHYSICIAN which
 *          allows/disallows a user to change the current physician <br>
 * <br>
 *          Revision 1.143 2009-01-22 09:36:12 hermen <br>
 *          added right PERMISSION_CHANGE_PHYSICIAN which allows/disallows a
 *          user to change the current physician <br>
 * <br>
 *          Revision 1.142 2008-12-17 15:23:06 heinemann <br>
 *          initial commit after merging of branch new prescription <br>
 * <br>
 *          Revision 1.141.2.1 2008-12-15 14:08:21 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.141 2008-10-21 09:53:34 hermen <br>
 *          fixed patient slot bug <br>
 *          enhanced logging <br>
 *          code cleanup <br>
 * <br>
 *          Revision 1.140 2008-09-25 09:43:06 heinemann <br>
 *          fixed copyrights <br>
 * <br>
 *          Revision 1.139 2008-09-11 07:54:18 hermen <br>
 *          fixed cancelling of close patient <br>
 * <br>
 *          Revision 1.138 2008-09-02 09:10:21 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.137 2008-08-29 10:27:58 heinemann <br>
 *          Ticket #167 (closed task: fixed) <br>
 *          Close patient file of deleted patient <br>
 * <br>
 *          Revision 1.136 2008-05-27 14:41:32 weitz <br>
 *          *New Letter Button removed... <br>
 *          *Handlers for Letters removed <br>
 * <br>
 *          Revision 1.135 2008-05-26 13:22:07 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.134 2008-04-15 12:40:51 heinemann <br>
 *          select accident number when the date is choosen in consultation view <br>
 * <br>
 *          Revision 1.133 2008-04-14 14:37:07 heinemann <br>
 *          fixed problem with patient accident that was not transfered to the
 *          billing module when the current consultation, including the
 *          accident, was not saved before the creation of the invoice. <br>
 * <br>
 *          Revision 1.132 2008-04-11 12:24:40 weitz <br>
 *          *templatemodule finished, renamed commented /few little design bugs <br>
 *          *patientmodule, create new letter dialog created <br>
 * <br>
 *          Revision 1.131 2008-04-09 08:53:42 hermen <br>
 *          fixed small possible bugs <br>
 * <br>
 *          Revision 1.130 2008-03-28 14:56:36 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.129 2008-03-27 12:34:53 weitz <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.128 2008-03-25 08:21:09 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.127 2008-03-14 08:00:14 hermen <br>
 *          fixed yellow header on edited patient <br>
 * <br>
 *          Revision 1.126 2008-03-12 12:33:26 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.125 2008-03-11 17:17:11 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.124 2008-03-10 12:37:52 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.123 2008-03-06 15:34:26 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.122 2008-02-28 15:36:09 heinemann <br>
 *          added load patient method to load a patient by its id <br>
 * <br>
 *          Revision 1.121 2008-02-27 08:25:06 heinemann <br>
 *          added initModule call <br>
 * <br>
 *          Revision 1.120 2008-02-05 15:07:45 hermen <br>
 *          removed copy patient buttons, they still remain in the menu. <br>
 * <br>
 *          Revision 1.119 2008-01-22 13:05:24 heinemann <br>
 *          agenda appointment preview button is now hidden when the module is
 *          disabled. <br>
 * <br>
 *          Revision 1.118 2008-01-21 14:58:42 heinemann <br>
 *          code cleanup and java doc <br>
 * 
 */
public class PatientManagerModule extends GECAMedModule implements PatientListener, GECAMedMessageListener, ActionListener, PropertyChangeListener, DropTargetListener, PatientManagerIconNames
{
	// ~ Static fields/initializers
	// =============================================
	
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(PatientManagerModule.class.getName());
	
	private static final long									serialVersionUID				= 1L;
	
	/* ***********************************************************
	 * Constants for the permission subsystem
	 */
	
	public static final String									PATIENT_UPDATED					= "PATIENT_UPDATED";
	
	/**
	 * The name of the module
	 */
	public static final String									MODULE_NAME						= "Patient";
	
	/**
	 * PatientList submodule
	 */
	public static final String									PATIENT_LIST_MODULE_NAME		= "PatientListModul";
	
	// the rights for that module
	public static final String									VIEW_MEDICAL_DATA				= "viewMedicalData";
	
	public static final String									EDIT_MEDICAL_DATA				= "editMedicalData";
	
	public static final String									EDIT_LIST						= "editList";
	
	public static final int										MAX_OPEN_PATIENTS				= 5;
	
	private static final int									MAX_LENGTH_PATIENT_NAME			= 26;
	
	private static final RowSpec								GAP_ROW_SPEC					= new RowSpec(Sizes.pixel(2));
	
	private static final RowSpec								BUTTON_ROW_SPEC					= new RowSpec(RowSpec.FILL, Sizes.PREFERRED, RowSpec.NO_GROW);
	
	/**
	 * This is the maximum file size for uploading files to the database. <br/>
	 * Currently limited to 25MB
	 */
	public static final long									MAX_FILE_UPLOAD_SIZE			= 25000000;
	
	/**
	 * the name of the Topic to describe to. this MessageTopic has to exist in
	 * the JBoss configuration
	 */
	private static final String									TOPIC_NAME						= "topic/GeCam/patientmanagementTopic";																										//$NON-NLS-1$
																																																												
	// ~ Instance fields
	// ========================================================
	
	private static Map<Integer, List<Incident>>					patientAccidents				= Collections.synchronizedMap(new HashMap<Integer, List<Incident>>());
	
	private static HashMap<Patient, HashMap<String, Object>>	patientDataCache				= new HashMap<Patient, HashMap<String, Object>>();
	
	/**
	 * Appointment
	 */
	public static final String									CACHE_PATIENT_NEXT_APPOINTMENT	= "cache_patient_next_appointment";
	
	/**
	 * util.Date
	 */
	public static final String									CACHE_PATIENT_LAST_VISIT		= "cache_patient_last_visit";
	
	/**
	 * Collection of PatientMemo
	 */
	public static final String									CACHE_PATIENT_WARNING_MEMOS		= "cache_patient_warning_memos";
	
	/**
	 * Long
	 */
	public static final String									CACHE_PATIENT_MEMO_COUNT		= "cache_patient_memo_count";
	
	private static PatientManagerModule							patientManagerModule;

	/* ------------------------------------------------------ */
	// constants for logging
	protected static final String								OPEN_PATIENT					= "OPEN Patient";
	
	protected static final String								CLOSE_PATIENT					= "CLOSE Patient";
	
	protected static final String								UPDATE_PATIENT					= "UPDATE Patient";
	
	protected static final String								CREATE_PATIENT					= "CREATE Patient";
	
	public static final String									SEARCH_PATIENT					= "SEARCH_PATIENT";
	
	/*
	 * ##########################################################################
	 * ############## Class Members
	 */
	
	private Topic												topic							= null;
	
	private TopicConnection										conn							= null;
	
	private TopicSession										session							= null;
	
	private boolean												listenerActivated				= true;
	
	private boolean												initButtons;
	
	private JPanel												cardPanel;
	
	private CardLayout											cardLayout;
	
	private JMenu												patientMenu;
	
	private JPanel												content							= new JPanel();
	
	private PatientNaviBar										naviPanel;
	
	private JPanel												viewSwitcherPanel;
	
	private JPanel												functionsPanel;
	
	private PatientButtonPanel									patientSlotsButtonPanel;
	
	private PatientButtonPanel									invoiceTemplates;
	
	private PatientPanel[]										patientPanels					= new PatientPanel[MAX_OPEN_PATIENTS];
	
	private JToggleButton[]										buttons							= new JToggleButton[MAX_OPEN_PATIENTS];
	
	private int													currentSlot						= 0;
	
	private int[]												mnemonic						= { KeyEvent.VK_1, KeyEvent.VK_2, KeyEvent.VK_3, KeyEvent.VK_4, KeyEvent.VK_5, KeyEvent.VK_6, KeyEvent.VK_7, KeyEvent.VK_8, KeyEvent.VK_9 };
	
	public AdministrativeElementsPlugin							administrativeElementsPlugin;
	
	public PatientModuleSettings								patientSettings;
	
	public PatientModulesPlugin									subModulesPlugin;
	
	public SimpleViewSettingsPlugin								simpleViewSettings;
	
	private JPanel												agendaPanel;
	
	private JPanel												agendaSubPanel;
	
	private AppointmentProposalPreviewArea						appointmentProposalArea;
	
	private JButton												appointmentPreviewButton;
	
	private Thread												patientLoadThread;
	
	private JLabel												titleLabel;
	
	private JPanel												waitingroomSubPanel;
	
	private JButton												waitingroomButton;
	
	private PatientButtonPanel									waitingroomPanel;
	
	protected GECAMedAction										savePatientAction;
	
	protected GECAMedAction										showPatientVisits;
	
	private OverviewPatientVisitsDialog							overviewPatientVisitsDialog;

	private TopicSubscriber recv;
	
	private GECAMedAction exportPatient;
	
	
	// ~ Constructors
	// ===========================================================
	
	/**
	 * 
	 */
	public PatientManagerModule()
	{
		/* ================================================== */
		super(MODULE_NAME, getIcon(PATIENT), Color.WHITE);
		
		patientManagerModule = this;
		String moduleNameTranslated = Translatrix.getTranslationString(getName());
		this.titlePanel.setTopic(moduleNameTranslated + ": ");
		this.titleLabel = new JLabel();
		this.titleLabel.setOpaque(false);
		this.titleLabel.setFont(new Font("Helvetica", Font.BOLD, 20));
		this.titleLabel.setHorizontalTextPosition(SwingConstants.LEADING);
		this.titleLabel.setHorizontalAlignment(SwingConstants.LEADING);
		this.titleLabel.setIconTextGap(25);
		this.titlePanel.setHeaderComponent(this.titleLabel);
		
		this.administrativeElementsPlugin = new AdministrativeElementsPlugin();
		this.addAdminSettingsPlugin(administrativeElementsPlugin);
		
		this.subModulesPlugin = new PatientModulesPlugin();
		this.addAdminSettingsPlugin(subModulesPlugin);
		
		this.patientSettings = new PatientModuleSettings();
		this.addAdminSettingsPlugin(patientSettings);
		
		/* ------------------------------------------------------- */
		// user settings
		// this.simpleViewSettings = new SimpleViewSettingsPlugin();
		// addSettingsPlugin(simpleViewSettings);
		
		/* ------------------------------------------------------- */
		// add the ResourceBundle for: lu.tudor.santec.gecam.client.gui.pm
		/* ------------------------------------------------------- */
		Translatrix.addBundle("lu.tudor.santec.gecamed.patient.gui.resources.Translatrix");
		Translatrix.addBundle("lu.tudor.santec.gecamed.prescription.gui.resources.Translatrix");
		/* ------------------------------------------------------- */
		// set as patient opener
		/* ------------------------------------------------------- */
		this.setCanDisplayPatient(true);
		overviewPatientVisitsDialog = new OverviewPatientVisitsDialog();
		/* ================================================== */
	}
	
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see lu.tudor.santec.gecamed.core.gui.GECAMedModule#initModule()
	 */
	@Override
	protected void initModule()
	{
		/* ====================================================== */
		this.setOpaque(false);
		
		/* ------------------------------------------------------- */
		GECAMedModule.addPatientListener(this);
		RegistrationDesk.addGECAMedMessageListener(this);
		/*
		 * ######################################################### Add the
		 * drug list modules
		 */
		NewDrugWorker.registerDrugList(new CefipDrugListModule());
		
		DrugBrowser.getInstance();
		/* ######################################################## */
		// add the cefip imprt action for admins
		/* ------------------------------------------------------- */
		GECAMedAction importCefipAction = new GECAMedAction(null, Translatrix.getTranslationString("cefip.drugeditor.importNewList"), PrescriptionIcons.getSmallIcon(PrescriptionIcons.PRSC_DRUG), null, true, false, false)
		{
			
			private static final long	serialVersionUID	= 1L;
			
			
			/*
			 * (non-Javadoc)
			 * 
			 * @see
			 * lu.tudor.santec.gecamed.core.gui.GECAMedAction#actionPerformed
			 * (java.awt.event.ActionEvent)
			 */
			@Override
			public void actionPerformed(ActionEvent p_Event)
			{
				/* ============================================= */
				// DrugImportDialog d = new DrugImportDialog();
				// d.showDialog();
				
				ImportDrugsDialog id = new ImportDrugsDialog(MainFrame.getInstance());
				id.pack();
				
				MainFrame.showDialogCentered(id);
				
				/* ============================================= */
			}
		};
		AdminModule.addAdminAction(importCefipAction);
		/* ------------------------------------------------------- */
		// start listener for JMS
		this.recieveJMS();
		/* ------------------------------------------------------- */
		// Drag&Drop
		/* ------------------------------------------------------- */
		this.setTransferHandler(new TransferHandler()
		{
			
			private static final long	serialVersionUID	= 1L;
			
			
			/*
			 * (non-Javadoc)
			 * 
			 * @see
			 * javax.swing.TransferHandler#canImport(javax.swing.JComponent,
			 * java.awt.datatransfer.DataFlavor[])
			 */
			@Override
			public boolean canImport(JComponent comp, DataFlavor[] transferFlavors)
			{
				/* ====================================================== */
				// TODO Auto-generated method stub
				return super.canImport(comp, transferFlavors);
				/* ====================================================== */
			}
		});
		
		Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener()
		{
			
			public void eventDispatched(AWTEvent e)
			{
				/* ================================================== */
				Component currComp = (Component) e.getSource();
				
				while (currComp != null)
				{
					if (currComp instanceof PatientManagerModule)
					{
						break;
					}
					currComp = currComp.getParent();
				}
			}
			/* ================================================== */
		}, AWTEvent.MOUSE_EVENT_MASK);
		
		this.setDropTarget(new DropTarget(this, this));
		/* ------------------------------------------------------- */
		// build the Panel
		/* ------------------------------------------------------- */
		this.buildPanel();
		this.addPropertyChangeListener(this);
		
		/* ------------------------------------------------------- */
		// add IncidentEntry handlers
		/* ------------------------------------------------------- */
		SoapHandler soapHandler = new SoapHandler();
		EntryTypeRegister.registerHandler(IncidentManager.SOAP_S, soapHandler);
		EntryTypeRegister.registerHandler(IncidentManager.SOAP_O, soapHandler);
		EntryTypeRegister.registerHandler(IncidentManager.SOAP_A, soapHandler);
		EntryTypeRegister.registerHandler(IncidentManager.SOAP_P, soapHandler);
		EntryTypeRegister.registerHandler(IncidentManager.CONS_1, soapHandler);
		EntryTypeRegister.registerHandler(IncidentManager.CONS_2, soapHandler);
		EntryTypeRegister.registerHandler(IncidentManager.CONS_3, soapHandler);
		
		
		FileHandler fileHandler = new FileHandler();
		EntryTypeRegister.registerHandler(IncidentManager.FILE, fileHandler);
		
		MeasurementHandler measurementHandler = new MeasurementHandler();
		EntryTypeRegister.registerHandler(IncidentManager.MEASUREMENT, measurementHandler);
		
		PrescriptionHandler prescriptionHandler = new PrescriptionHandler();
		EntryTypeRegister.registerHandler(PrescriptionManager.ENTRY_TYPE, prescriptionHandler);
		
		AccidentHandler accidentHandler = new AccidentHandler();
		EntryTypeRegister.registerHandler(AccidentHandler.ACCIDENT, accidentHandler);
		
		SickLeaveHandler sickLeaveHandler = new SickLeaveHandler();
		EntryTypeRegister.registerHandler(IncidentManager.SICK_LEAVE, sickLeaveHandler);
		
		/* ====================================================== */
	}
	
	
	// ~ Methods
	// ================================================================
	/**
	 * creates a new Action for Closing a patient file
	 * 
	 * @return the Action
	 */
	private GECAMedAction getActionClosePatient()
	{
		GECAMedAction a = new GECAMedAction(this, "pm.closePatient", GECAMedModule.getIcon(GECAMedIconNames.CLOSE), null, true, true, false)
		{
			private static final long	serialVersionUID	= 1L;
			
			
			public void actionPerformed(ActionEvent e)
			{
				
				//		new Thread() {
				//		    public void run() {
				
				// close current Patient
				logger.info(MainFrame.createLogSubSectionString("Closing Patient " + getCurrentPatient().toString() + " in Slot [" + currentSlot + "] of " + getOpenPatients().size()));
				try
				{
					//getPatientPanel().stopEditing();
					// remove the next appointment
					switchNextAppointment(null);
					// if only one patient open we set an empty one to the panel
					if (getOpenPatients().size() == 1)
					{
						logger.info("Only 1 Patient Open, NOT CLOSING SLOT");
						// // log
						// GECAMedLog.user(PatientManagerModule.MODULE_NAME,
						// CLOSE_PATIENT, "Patient: ID " +
						// patientPanel.getPatient().getId()
						// + "; " + patientPanel.getPatient().getSurName()+", "
						// +patientPanel.getPatient().getFirstName()+"; "
						// +
						// patientPanel.getPatient().getSocialSecurityNumber());
						
						Patient tempPatient = new Patient();
						tempPatient.setLanguage(Language.LUXEMBOURGISH);
						tempPatient.setNationality(Nationality.LUXEMBOURGISH);
						getPatientPanel().setPatient(tempPatient);
						if (tempPatient.equals(getPatientPanel().getPatient()))
						{
							GECAMedModule.setCurrentPatient(tempPatient);
						}
					}
					// if more than 1 patients open
					else
					{
						logger.info(getOpenPatients().size() + " Patients Open, CLOSING SLOT");
						// set an empty patient to see if the last one was saved
						Patient tempPatient = new Patient();
						tempPatient.setLanguage(Language.LUXEMBOURGISH);
						tempPatient.setNationality(Nationality.LUXEMBOURGISH);
						getPatientPanel().setPatient(tempPatient);
						
						// only close if setpatient was not canceled
						if (tempPatient.equals(getPatientPanel().getPatient()))
						{
							closeCurrentSlot();
						}
						
					}
				}
				catch (Exception e1)
				{
					logger.log(Level.WARN, "error closing patient", e1);
					mainFrame.statusBar.setWarningText(Translatrix.getTranslationString("pm.noPatientSelected"));
				}
				//		    }
				//		}.start();
				
			}
		};
		return a;
	}
	
	
	/**
	 * creates a new Action for Creating a new Patient File
	 * 
	 * @return the Action
	 */
	private GECAMedAction getActionNewPatient()
	{
		GECAMedAction a = new GECAMedAction(this, "pm.newPatient", getIcon(PATIENT_NEW), null, true, true, false)
		{
			
			private static final long	serialVersionUID	= 1L;
			
			
			public void actionPerformed(ActionEvent e)
			{
				Patient newPatient = new Patient();
				newPatient.setLanguage(Language.LUXEMBOURGISH);
				newPatient.setNationality(Nationality.LUXEMBOURGISH);
				addPatient(newPatient, true);
				GECAMedLog.user(PatientManagerModule.MODULE_NAME, CREATE_PATIENT, "New Patient created.");
			}
		};
		return a;
	}
	
	
	/**
	 * creates a new Action for Saving the active Patient File
	 * 
	 * @return the Action
	 */
	private GECAMedAction getActionSavePatient()
	{
		GECAMedAction a = new GECAMedAction(this, Translatrix.getTranslationString("pm.savePatient"), GECAMedModule.getIcon(GECAMedIconNames.SAVE), null, true, true, false)
		{
			
			private static final long	serialVersionUID	= 1L;
			
			
			public void actionPerformed(ActionEvent e)
			{
				/* ================================================== */
				// save current patient
				/* ------------------------------------------------------- */
				savePatientAction();
			}
		};
		return a;
	}
	
	public void savePatientAction()
	{
		try
		{
			
			long start = System.currentTimeMillis();
			boolean updatePatient = getPatientPanel().getPatient().isPersistent();
			
			
			mainFrame.setWaitCursor(true);
			mainFrame.statusBar.setProgress(Translatrix.getTranslationString("pm.savingPatient"), StatusBar.PROGRESS_INDETERMINATE);
			getPatientPanel().savePatient();
			/* ------------------------------------------------------- */
			// log
			long took = (System.currentTimeMillis() - start);
			if (updatePatient)
			{
				GECAMedLog.user(PatientManagerModule.MODULE_NAME, UPDATE_PATIENT, "Patient: ID " + getPatient().toLogString(), took);
			}
			else
			{
				GECAMedLog.user(PatientManagerModule.MODULE_NAME, CREATE_PATIENT, "Patient: ID " + getPatient().toLogString(), took);
			}
			/* ------------------------------------------------------- */
			MainFrame.getInstance().showMessage(Translatrix.getTranslationString("pm.patientSaved"));
			
			// currentPatientPanel.initializeTabs();
			/* ------------------------------------------------------- */
		}
		catch (ArrayIndexOutOfBoundsException e1)
		{
			mainFrame.statusBar.setWarningText(Translatrix.getTranslationString("pm.noPatientSelected"));
		}
		catch (Exception e1)
		{
			/* ------------------------------------------------------- */
			// ============================================================
			// Attention!
			// This error must be transmitted directly in the brain of
			// the user. We need a dialog that demands user interaction
			// to
			// inform him, that information may have been lost!
			// ============================================================
			logger.log(Level.WARN, "error saving patient", e1);
			GECAMedOptionPane.showOptionDialog(MainFrame.getInstance(), Translatrix.getTranslationString("pm.savingPatient"), Translatrix.getTranslationString("pm.errorSavingPatient"), JOptionPane.DEFAULT_OPTION);
			//GECAMedOptionPane.ICON_WARNING);
			
			// mainFrame.statusBar.setWarningText(
			// Translatrix.getTranslationString("pm.errorSavingPatient"));
			/* ------------------------------------------------------- */
		}
		// ==================================================================
		// the following operations are executed even if something went
		// wrong while saving the patient.
		// ==================================================================
		// reset the cursor
		mainFrame.setWaitCursor(false);
		// set the current patient
		GECAMedModule.setCurrentPatient(getPatient(), true);
		// preload the patient's accidents
		loadAccidents(getCurrentPatient());
		/* ================================================== */
	}
	
	
	/**
	 * returns the currently shown patient panel
	 * 
	 * @return
	 */
	public PatientPanel getPatientPanel()
	{
		return patientPanels[currentSlot];
	}
	
	
	/**
	 * returns the currently shown patient
	 * 
	 * @return
	 */
	protected Patient getPatient()
	{
		return patientPanels[currentSlot].getPatient();
	}
	
	
	/**
	 * @return
	 */
	protected PatientNaviBar getNaviBar()
	{
		/* ================================================== */
		return this.naviPanel;
		/* ================================================== */
	}
	
	
	/**
	 * Copies the adminstrativ data from the current patient into a new one.
	 * 
	 * @return
	 */
	private GECAMedAction getActionCopyPatient()
	{
		/* ====================================================== */
		// create the action
		GECAMedAction a = new GECAMedAction(this, "pm.copypatient", getIcon(COPY_PATIENT), null, true, false, false)
		{
			/* ------------------------------------------------------ */
			private static final long	serialVersionUID	= 1L;
			
			
			public void actionPerformed(ActionEvent e)
			{
				/* ====================================================== */
				/*
				 * create a new Patient with the adminstrativ data of the
				 * current patient
				 */
				Patient currP = PatientManagerModule.getCurrentPatient();
				Patient newP = new Patient();
				/* ------------------------------------------------------ */
				newP.setSurName(currP.getSurName());
				newP.setFirstName("");
				newP.setLanguage(currP.getLanguage());
				newP.setNationality(currP.getNationality());
				newP.setGender(currP.getGender());
				if (currP.getAddress() != null)
				{
					/* ------------------------------------------------------ */
					// clone the addresses
					Set<PatientAddress> newAddr = new HashSet<PatientAddress>();
					for (PatientAddress ad : currP.getAddress())
					{
						newAddr.add(ad.copy());
					}
					newP.setAddress(newAddr);
					/* ------------------------------------------------------ */
				}
				/* ------------------------------------------------------ */
				// copy the phones
				if (currP.getPhones() != null)
				{
					/* ------------------------------------------------------ */
					// clone the addresses
					Set<PatientPhone> newPhon = new HashSet<PatientPhone>();
					for (PatientPhone ad : currP.getPhones())
					{
						newPhon.add(ad.copy());
					}
					newP.setPhones(newPhon);
					/* ------------------------------------------------------ */
				}
				// copy the health insurance
				newP.setInsuranceID(currP.getInsuranceID());
				newP.setInsurance(currP.getInsurance());
				newP.setComplementaryID(currP.getComplementaryID());
				newP.setComplementary(currP.getComplementary());
				// open in new Tab
				addPatient(newP, true);
				/* ====================================================== */
			}
			/* ------------------------------------------------------ */
		};
		return a;
		
		/* ====================================================== */
	}
	
	
	/**
	 * Opens the PatientSearchList to search for a patient whose adminstrative
	 * data should be copied.
	 * 
	 * @return
	 */
	private GECAMedAction getActionCopyFromPatient()
	{
		GECAMedAction a = new GECAMedAction(this, "pm.copyfrompatient", getIcon(COPY_FROM_PATIENT), null, true, false, false)
		{
			
			private static final long	serialVersionUID	= 1L;
			
			
			public void actionPerformed(ActionEvent e)
			{
				// show patient list
				Patient currP = PatientSearchDialog.searchPatient("");
				
				if (currP != null)
				{
					/* ------------------------------------------------------ */
					Patient newP = new Patient();
					/* ------------------------------------------------------ */
					newP.setSurName(currP.getSurName());
					newP.setFirstName("");
					newP.setLanguage(currP.getLanguage());
					newP.setNationality(currP.getNationality());
					newP.setGender(currP.getGender());
					if (currP.getAddress() != null)
					{
						/*
						 * ------------------------------------------------------
						 */
						// clone the addresses
						Set<PatientAddress> newAddr = new HashSet<PatientAddress>();
						for (PatientAddress ad : currP.getAddress())
						{
							newAddr.add(ad.copy());
						}
						newP.setAddress(newAddr);
						/*
						 * ------------------------------------------------------
						 */
					}
					/* ------------------------------------------------------ */
					// copy the phones
					if (currP.getPhones() != null)
					{
						/*
						 * ------------------------------------------------------
						 */
						// clone the addresses
						Set<PatientPhone> newPhon = new HashSet<PatientPhone>();
						for (PatientPhone ad : currP.getPhones())
						{
							newPhon.add(ad.copy());
						}
						newP.setPhones(newPhon);
						/*
						 * ------------------------------------------------------
						 */
					}
					// copy the health insurance
					newP.setInsuranceID(currP.getInsuranceID());
					newP.setInsurance(currP.getInsurance());
					newP.setComplementaryID(currP.getComplementaryID());
					newP.setComplementary(currP.getComplementary());
					
					/* ------------------------------------------------------ */
					// relation
					
					RelationSelector.getInstance().showSelector(true);
					switch (RelationSelector.getInstance().getResult())
					{
						case RelationSelector.RELATION_UNDEFINED:
							break;
						case RelationSelector.RELATION_PARENT:
						{
							/*
							 * ------------------------------------------------------
							 */
							Set<Patient> parentSet = new HashSet<Patient>();
							parentSet.add(currP);
							newP.setParents(parentSet);
							
							break;
							/*
							 * ------------------------------------------------------
							 */
						}
						case RelationSelector.RELATION_CHILD:
						{
							/*
							 * ------------------------------------------------------
							 */
							Set<Patient> childSet = new HashSet<Patient>();
							childSet.add(currP);
							newP.setChildren(childSet);
							
							break;
							/*
							 * ------------------------------------------------------
							 */
						}
						case RelationSelector.RELATION_SPOUSE:
						{
							/*
							 * ------------------------------------------------------
							 */
							newP.setSpouseId(currP.getId());
							/*
							 * ------------------------------------------------------
							 */
							break;
						}
						default:
							break;
					}
					
					// open in new Tab
					addPatient(newP, true);
					/* ------------------------------------------------------ */
				}
				
			}
		};
		return a;
	}
	
	
	/**
	 * @param patient
	 *            the Patient to be added
	 */
	public void addPatient (Patient patient, boolean asNewTab)
	{
		addPatient(patient, asNewTab, null);
	}
	
	
	public void addPatient (Patient patient, boolean asNewTab, String[] disabledTabs)
	{
		/* ================================================== */
		// create a new Thread because fetching may take some time...
		// this.patientLoadThread = new Thread() {
		
		if (patientLoadThread != null)
		{
			int waitTimeout = 0;
			while (patientLoadThread.isAlive() && waitTimeout < 50)
			{
				try
				{
					Thread.sleep(100);
					waitTimeout++;
					System.out.println("waiting for patientLoadThread " + patientLoadThread.getId() + " to finish.....");
				}
				catch (InterruptedException e)
				{
					logger.log(Level.ERROR, e.getMessage(), e);
				}
			}
			try
			{
				patientLoadThread.interrupt();
				patientLoadThread.stop();
			}
			catch (Throwable e)
			{
				logger.log(Level.ERROR, e.getMessage(), e);
			}
		}
		
		patientLoadThread = new LoadingThread (patient, asNewTab, disabledTabs);
		
		// start the thread
		//		EventQueue.invokeLater(patientLoadThread);
		patientLoadThread.start();
		/* ================================================== */
	}
	
	
	/**
	 * Closes an open patient file. Does not check for changes!!! <b>Used only
	 * to close the Patient File before deleting the Patient</b>
	 * 
	 * @param patientId
	 */
	public void closePatient(Integer patientId)
	{
		/* ================================================== */
		if (patientId == null)
			return;
		/* ------------------------------------------------------- */
		// first, try to get the patientpanel for this patientid
		/* ------------------------------------------------------- */
		Patient patient2Close = null;
		PatientPanel panel2Close = null;
		int slot = -1;
		for (int i = 0; i < patientPanels.length; i++)
		{
			/* ------------------------------------------------------- */
			if (patientPanels[i] != null)
			{
				/* ------------------------------------------------------- */
				Patient p = patientPanels[i].getPatient();
				if (p != null && p.getId() != null && p.getId().equals(patientId))
				{
					patient2Close = p;
					panel2Close = patientPanels[i];
					slot = i;
					break;
				}
				/* ------------------------------------------------------- */
			}
			/* ------------------------------------------------------- */
		}
		/* ------------------------------------------------------- */
		// exit if we can not find the patient
		/* ------------------------------------------------------- */
		if (patient2Close == null)
			return;
		/* ------------------------------------------------------- */
		// if only one patient open we set an empty one to the panel
		if (getOpenPatients().size() == 1)
		{
			/* ------------------------------------------------------- */
			Patient tempPatient = new Patient();
			tempPatient.setLanguage(Language.LUXEMBOURGISH);
			tempPatient.setNationality(Nationality.LUXEMBOURGISH);
			
			panel2Close.setPatient(tempPatient, true);
			
			// if setPatient was not cancelled
			if (tempPatient.equals(panel2Close.getPatient()))
			{
				GECAMedModule.setCurrentPatient(tempPatient);
			}
			/* ------------------------------------------------------- */
		}
		else
		{
			/* ------------------------------------------------------- */
			// start closing now
			/* ------------------------------------------------------- */
			closeSlot(panel2Close, slot);
			/* ------------------------------------------------------- */
		}
		/* ================================================== */
	}
	
	
	/**
	 * Removes a patient from the view
	 * 
	 * @param panel2Remove
	 * @param slot
	 */
	private void closeSlot(PatientPanel panel2Remove, int slot)
	{
		/* ================================================== */
		logger.info("Closing Patient Slot: [" + slot + "] from " + getOpenPatients().size() + " open slots");
		// remove from panel array
		/* ------------------------------------------------------- */
		patientPanels[slot] = null;
		/* ------------------------------------------------------- */
		// shift the patientpanels in the slots
		/* ------------------------------------------------------- */
		for (int i = slot; i < patientPanels.length - 1; i++)
		{
			System.out.println("Shift Slot: [" + i + "] = [" + (i + 1) + "]");
			patientPanels[i] = patientPanels[i + 1];
		}
		// set lastSlot to null
		patientPanels[patientPanels.length - 1] = null;
		
		/* ------------------------------------------------------- */
		// shift the currenSlot if the deleted slot is smaller than the current.
		/* ------------------------------------------------------- */
		if (slot <= currentSlot)
		{
			currentSlot--;
			if (currentSlot < 0)
				currentSlot = 0;
		}
		/* ------------------------------------------------------- */
		// adjust the buttons that are working on the current patient
		// e.g. close, copy etc
		/* ------------------------------------------------------- */
		for (int i = 0; i < buttons.length; i++)
		{
			/* ------------------------------------------------------- */
			if (patientPanels[i] != null)
			{
				/* ------------------------------------------------------- */
				String mneText = "";
				if (getUseMnemonics()) {
					mneText = " [ALT+"+i+"]";
				}
				
				if (patientPanels[i].isModified())
				{
					buttons[i].setText((i + 1) + ": " + patientPanels[i].getPatient().toShortString() + " *" + mneText);
				}
				else
				{
					buttons[i].setText((i + 1) + ": " + patientPanels[i].getPatient().toShortString() + mneText);
				}
				buttons[i].setActionCommand(patientPanels[i].getIdentifier());
				buttons[i].setEnabled(true);
				/* ------------------------------------------------------- */
			}
			else
			{
				buttons[i].setText((i + 1) + ": ");
				buttons[i].setEnabled(false);
			}
			/* ------------------------------------------------------- */
		}
		/* ------------------------------------------------------- */
		// remove from layout
		/* ------------------------------------------------------- */
		cardPanel.remove(panel2Remove);
		/* ------------------------------------------------------- */
		// activate a patient
		/* ------------------------------------------------------- */
		if (currentSlot < 0)
			buttons[currentSlot - 1].doClick();
		else
			buttons[0].doClick();
		/* ------------------------------------------------------- */
		Set<Integer> ids	= new HashSet<Integer>();
		for (int index = 0; index < patientPanels.length; index++)
			try
			{
				if (patientPanels[index] != null)
					ids.add(patientPanels[index].getPatient().getId());
			} catch (NullPointerException e) {
				logger.warn("Error while checking patient panels.", e);
			}
		
		ESanteTab.checkExistence(ids);
		/* ================================================== */
	}
	
	
	/**
	 * Removes the current patient from the view
	 */
	private void closeCurrentSlot()
	{
		/* ================================================== */
		closeSlot(getPatientPanel(), currentSlot);
		/* ================================================== */
	}
	
	
	/**
	 * Add a new patient. Create a new PatientPanel instance Returns false if
	 * all slots are in use
	 * 
	 * @param p
	 * @return
	 */
	private boolean addPatientPanel(Patient p)
	{
		/* ================================================== */
		// we create a new patient panel and add it to the cardLayout
		PatientPanel patientPanel = new PatientPanel(PatientManagerModule.this);
		patientPanel.setPatient(p);
		
		int newSlot = -1;
		for (int i = 0; i < patientPanels.length; i++)
		{
			if (patientPanels[i] == null)
			{
				newSlot = i;
				patientPanels[newSlot] = patientPanel;
				cardPanel.add(patientPanels[newSlot], patientPanels[newSlot].getIdentifier());
				break;
			}
		}
		
		if (newSlot != -1)
		{
			currentSlot = newSlot;
			buttons[newSlot].setEnabled(true);
			buttons[newSlot].doClick();
		}
		else
		{
			MainFrame.getInstance().showMessage(Translatrix.getTranslationString("patient.noSlotLeft"), 5000);
			logger.info("NO EMPTY PATIENT SLOT");
			return false;
		}
		patientPanel.setModified(false);
		return true;
		/* ================================================== */
	}
	
	
	/**
	 * starts the recieving of new Messages
	 */
	public void recieveJMS()
	{
		/* ================================================== */
		try
		{
			// Setup the PubSub connection, session
			InitialContext iniCtx = new InitialContext();
			Object factory = iniCtx.lookup("ConnectionFactory");
			TopicConnectionFactory tcf = (TopicConnectionFactory) factory;
			
			conn = tcf.createTopicConnection();
			topic = (Topic) iniCtx.lookup(TOPIC_NAME);
			session = conn.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
			
			conn.start();
			conn.setExceptionListener(new ExceptionListener() {
				public void onException(JMSException e) {
					try {
						logger.warn("JMS Topic Connection lost, closing Connection.", e);
						if (recv != null) 		recv.close();
						if (session != null) 	session.close();
						if (conn != null) 		conn.close();
					} catch (Throwable ee) {
						logger.error("Error Closing JMS Topic Connection", ee);
					}
					
				}
			});
			
			iniCtx.close();
			MainFrame.addShutdownHook("Closing JMS connection to " + TOPIC_NAME, new Thread()
			{
				public void run()
				{
					try
					{
						logger.info("Closing JMS connection to " + TOPIC_NAME);
						// conn.stop();
						session.close();
						conn.close();
					}
					catch (JMSException e)
					{
						logger.log(Level.WARN, "closing JMS failed", e);
					}
					catch (Throwable e)
					{
						logger.log(Level.WARN, "closing JMS failed", e);
					}
				}
			});
			
			// Set the async listener
			recv = session.createSubscriber(topic);
			recv.setMessageListener(new PatientManagerMessageListener());
		}
		catch (Exception e)
		{
			logger.log(Level.WARN, "JMS listener failed", e);
		}
		/* ================================================== */
	}
	
	
	/**
	 * adds the components to the panel
	 */
	private void buildPanel()
	{
		initComponents();
		// add the menu
		this.patientMenu = new JMenu(Translatrix.getTranslationString("Patient"));
		this.setModuleMenu(patientMenu);
		
		getActionClosePatient().add();
		
		if (GECAMedModule.userHasPermission(IPatientPermissions.CREATE_PATIENT))
		{
			getActionNewPatient().add();
			getActionCopyPatient().add();
			getActionCopyFromPatient().add();
		}
		
		// overview of patient visits
		this.showPatientVisits = getActionPatientVisits();
		this.showPatientVisits.setEnabled(false);
		this.showPatientVisits.add();
		
		this.exportPatient = getActionExportPatient();
		this.exportPatient.setEnabled(false);
		this.exportPatient.add();
		
		/* *****************************************************
		 * If the current user gains at least one edit right we must provide the
		 * save button
		 */
		if (GECAMedModule.userHasPermission(IPatientPermissions.EDIT_ADMINISTRATIVE) || GECAMedModule.userHasPermission(IPatientPermissions.EDIT_ALL_MEMOS) || GECAMedModule.userHasPermission(IPatientPermissions.EDIT_OWN_MEMOS) || GECAMedModule.userHasPermission(IPatientPermissions.EDIT_ANAMNESIS)
				|| GECAMedModule.userHasPermission(IPatientPermissions.EDIT_CONSULTATION) || GECAMedModule.userHasPermission(IPatientPermissions.EDIT_HISTORY))
		{
			this.savePatientAction = getActionSavePatient();
			this.savePatientAction.setEnabled(false);
			this.savePatientAction.add();
		}
		
		//	getActionPatientStatistics().add();
		this.content.add(cardPanel, BorderLayout.CENTER);
		
		// ===================================================================
		// add naviPanel
		// ===================================================================
		JScrollPane scrollPane = new JScrollPane(naviPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		scrollPane.setOpaque(false);
		scrollPane.getViewport().setOpaque(false);
		scrollPane.setBorder(null);
		scrollPane.setViewportBorder(null);
		this.content.add(scrollPane, BorderLayout.EAST);
		
		this.setContentPanel(content);
		
	}
	
	private GECAMedAction getActionExportPatient()
	{
		GECAMedAction action = new GECAMedAction(this, "pm.exportPatient", GECAMedModule.getIcon(EXPORT), null, true, false, false)
		{
			private static final long	serialVersionUID	= 1L;
			
			public void actionPerformed(ActionEvent e)
			{
				try {
					ArrayList<Integer> exportPatient = new ArrayList<Integer>();
					exportPatient.add(getCurrentPatient().getId());
					ExportDialog exportdialog = new ExportDialog(null, exportPatient);
					exportdialog.setOptions(PatientExportPanel.exportDialogOptions);
					exportdialog.setStartDirectory(PatientExportPanel.startDirectory);
					exportdialog.showCenteredDialog();
					PatientExportPanel.exportDialogOptions = exportdialog.getOptions();
					PatientExportPanel.startDirectory = exportdialog.getStartDirectory();					
				} catch (Exception e2) {
					logger.warn("Error Exporting Patient!", e2);
				}
			}
		};
		return action;
	}
	
	/**
	 * creates a new Action for open the overview of patient visits
	 * 
	 * @return the Action
	 */
	private GECAMedAction getActionPatientVisits()
	{
		GECAMedAction action = new GECAMedAction(this, "pm.patientVisits", getIcon(PATIENT_VISITED), null, true, true, false)
		{
			private static final long	serialVersionUID	= 1L;
			
			
			public void actionPerformed(ActionEvent e)
			{
				overviewPatientVisitsDialog.showDialog();
			}
		};
		return action;
	}
		
	/**
	 * initialises the Components
	 */
	private void initComponents()
	{
		/* ================================================== */
		this.content.setLayout(new BorderLayout());
		this.content.setOpaque(false);
		
		// create the main patient Panel
		this.cardLayout = new CardLayout();
		this.cardPanel = new JPanel(cardLayout);
		this.cardPanel.setOpaque(false);
		
		// create the navi Panel
		naviPanel = new PatientNaviBar();
		
		// create the patient buttons
		FormLayout layout = new FormLayout("2px,f:min(100dlu;p):g,2px");
		JPanel patientButtonPanel	= new JPanel(layout);
		patientSlotsButtonPanel = new PatientButtonPanel(
				Translatrix.getTranslationString("patient.patients"), 
				Color.YELLOW, patientButtonPanel);
		CellConstraints	cc	= new CellConstraints();
		ButtonGroup	bg = new ButtonGroup();
		for (int i = 0; i < buttons.length; i++)
		{
			buttons[i] = new JToggleButton((i + 1) + ": ");
			try
			{
				if (getUseMnemonics()) {
					buttons[i].setMnemonic(mnemonic[i]);
					buttons[i].setToolTipText("[ALT+"+i+"]");
				}
			}
			catch (Exception e)
			{
			}
			buttons[i].setFont(GECAMedFonts.BUTTON_FONT);
			buttons[i].setMargin(new java.awt.Insets(0, 0, 0, 0));
			buttons[i].setEnabled(false);
			buttons[i].setHorizontalAlignment(SwingConstants.LEFT);
			buttons[i].addActionListener(this);
			bg.add(buttons[i]);
//			patientSlotsButtonPanel.addToggleButton(buttons[i]);
			layout.appendRow(GAP_ROW_SPEC);
			layout.appendRow(BUTTON_ROW_SPEC);
			patientButtonPanel.add(buttons[i], cc.xy(2, (i+1)*2));
		}
//		layout.appendRow(GAP_ROW_SPEC);
		
		/* ------------------------------------------------------ */
		// ===================================================================
		// view switcher button panel
		// ===================================================================
		this.viewSwitcherPanel = new JPanel(new BorderLayout());
		this.viewSwitcherPanel.setOpaque(false);
		naviPanel.addButtonPanel(viewSwitcherPanel, PatientNaviBar.TOP);
		
		// ===================================================================
		// functions button section
		// ===================================================================
		this.functionsPanel = new JPanel(new BorderLayout());
		this.functionsPanel.setOpaque(false);
		naviPanel.addButtonPanel(functionsPanel, PatientNaviBar.TOP);
		
		// ===================================================================
		// load waitingroom button
		// ===================================================================
		loadWaitingroomButton();
		
		// ===================================================================
		// load agenda preview button, if module is enabled
		// ===================================================================
		loadAgendaPreviewButton();
		
		// ===================================================================
		// load billing template buttons
		// ===================================================================
		loadBillingTemplateButtons();
		
		// ===================================================================
		// open patient slots
		// ===================================================================
		naviPanel.addButtonPanel(this.patientSlotsButtonPanel, PatientNaviBar.BOTTOM, true);
		// ===================================================================
		
		Patient newPatient = new Patient();
		newPatient.setLanguage(Language.LUXEMBOURGISH);
		newPatient.setNationality(Nationality.LUXEMBOURGISH);
		addPatientPanel(newPatient);
		
	}
	
	
	/**
	 * Loads the waitingroom button, if the module is enabled.
	 */
	private void loadWaitingroomButton()
	{
		/* ================================================== */
		if (ModuleManager.getModule(WaitingroomModule.MODULE_NAME) == null)
			return;
		/* ------------------------------------------------------- */
		boolean smallIcons = false;
		try
		{
			smallIcons = (Boolean) MainFrame.getInstance().userSettings.getValue(UserSettingsPlugin.SMALL_ICONS);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
		/* ------------------------------------------------------- */
		
		this.waitingroomSubPanel = new JPanel(new BorderLayout());
		this.waitingroomSubPanel.setOpaque(false);
		/* ------------------------------------------------------- */
		this.waitingroomButton = new JButton((smallIcons ? IconFetcher.getIcon(PatientManagerModule.class, WAITINGROOM_SMALL) : IconFetcher.getIcon(PatientManagerModule.class, WAITINGROOM)));
		waitingroomButton.setMargin(new java.awt.Insets(1, 1, 1, 1));
		waitingroomButton.setToolTipText(Translatrix.getTranslationString("patient.waitingroom.tooltip"));
		/* ------------------------------------------------------- */
		waitingroomSubPanel.add(waitingroomButton);
		this.waitingroomPanel = new PatientButtonPanel(Translatrix.getTranslationString("patient.waitingroom"), new Color(28, 225, 2), waitingroomSubPanel);
		/* ------------------------------------------------------- */
		
		/* ------------------------------------------------------- */
		waitingroomButton.addActionListener(new ActionListener()
		{
			
			public void actionPerformed(ActionEvent e)
			{
				/* ====================================================== */
				WaitingroomModule.getInstance().move2Waitingroom(getPatient());
				/* ====================================================== */
			}
			
		});
		
		naviPanel.addButtonPanel(this.waitingroomPanel, PatientNaviBar.BOTTOM);
		
		/* ------------------------------------------------------- */
		
		/* ================================================== */
	}
	
	
	/**
	 * Loads the agenda appointment preview button, if the module is enabled.
	 */
	private void loadAgendaPreviewButton()
	{
		/* ================================================== */
		if (ModuleManager.getModule(AgendaModule.MODULE_NAME) == null)
			return;
		/* ------------------------------------------------------- */
		
		//		boolean smallIcons = false;
		//		try {
		//			smallIcons = (Boolean) MainFrame.getInstance().userSettings.getValue(UserSettingsPlugin.SMALL_ICONS);
		//		} catch (Exception e) {
		//			e.printStackTrace();
		//		}
		
		this.agendaSubPanel = new JPanel(new BorderLayout());
		this.agendaSubPanel.setOpaque(false);
		/* ------------------------------------------------------- */
		this.appointmentPreviewButton = new JButton();
		appointmentPreviewButton.setMargin(new java.awt.Insets(1, 1, 1, 1));
		/* ------------------------------------------------------- */
		agendaSubPanel.setPreferredSize(new Dimension(150, 70));
		
		this.agendaPanel = new PatientButtonPanel(Translatrix.getTranslationString("patient.agenda"), new Color(28, 225, 2), agendaSubPanel);
		/* ------------------------------------------------------- */
		this.appointmentProposalArea = new AppointmentProposalPreviewArea();
		appointmentProposalArea.showHeader(false);
		/* ------------------------------------------------------- */
		Appointment a = new Appointment();
		a.setStartDate(new Date());
		a.setEndDate(new Date(a.getStartDate().getTime() + 3000));
		/* ------------------------------------------------------- */
		appointmentProposalArea.setAppointment(null, new Color(229, 242, 215));
		/* ------------------------------------------------------- */
		try
		{
			/* ------------------------------------------------------- */
			AgendaModule.getInstance();
			agendaSubPanel.add(appointmentPreviewButton, BorderLayout.CENTER);
			/* ------------------------------------------------------- */
			appointmentPreviewButton.setBorder(null);
			appointmentPreviewButton.add(appointmentProposalArea);
			/* ------------------------------------------------------- */
			
			appointmentPreviewButton.addActionListener(new ActionListener()
			{
				
				public void actionPerformed(ActionEvent e)
				{
					/* ====================================================== */
					Appointment nextApp = AgendaModule.getInstance().getNextAppointmentOfPatient(getPatient().getId());
					if (nextApp != null)
						AgendaModule.getInstance().setDate(nextApp.getStartDate());
					else
					{
						AgendaModule.getInstance().setDate(new Date());
						MainFrame.getInstance().selectModule(AgendaModule.MODULE_NAME);
						// show the new appointment dialog if there is no next
						AgendaModule.getInstance().showFreeAppointmentFinderDialog();
						return;
					}
					
					/* ------------------------------------------------------- */
					MainFrame.getInstance().selectModule(AgendaModule.MODULE_NAME);
					/* ====================================================== */
				}
				
			});
			
			naviPanel.addButtonPanel(this.agendaPanel, PatientNaviBar.BOTTOM);
			
			/* ------------------------------------------------------- */
		}
		catch (Exception e)
		{
			// TODO: handle exception
		}
		/* ================================================== */
	}
	
	
	/**
	 * Loads the billing template buttons, if the module is enabled.
	 */
	public void loadBillingTemplateButtons()
	{
		if (ModuleManager.getModule(BillingModule.MODULE_NAME) == null)
			return;
		
		Vector<AbstractButton> v2 = TemplateManager.getInstance().getTemplateButtons(false);
		
		invoiceTemplates = new PatientButtonPanel(Translatrix.getTranslationString("patient.facturation"), Color.RED, 2, v2);
		
		naviPanel.addButtonPanel(invoiceTemplates, PatientNaviBar.BOTTOM);
	}
	
	
	/**
	 * switches the view to the specified patient slot
	 * 
	 * @param slotNr
	 *            the number of the slot
	 */
	private void showSlot(int slotNr)
	{
		/* ================================================== */
//		if (currentSlot == slotNr)
//			 return;
		// remove the listener from the old Panel
		logger.info(MainFrame.createLogSubSectionString("show Patient Slot: " + slotNr));
		try
		{
			getPatientPanel().removePropertyChangeListener(this);
		}
		catch (Exception e2)
		{
		}
		
		this.currentSlot = slotNr;
		
		// show the patient panel
		cardLayout.show(cardPanel, getPatientPanel().getIdentifier());
		
		// update upper buttons
		try
		{
			viewSwitcherPanel.removeAll();
		}
		catch (Exception e1)
		{
		}
		viewSwitcherPanel.add(getPatientPanel().getButtonGroup());
		viewSwitcherPanel.validate();
		viewSwitcherPanel.updateUI();
		
		getPatientPanel().addPropertyChangeListener(this);
		
		// fire a change event to set title etc....
		propertyChange(new PropertyChangeEvent(this, "shown patient changed", null, null));
		getPatientPanel().setTabsEnabled();
		// set the new patient to all modules
		GECAMedModule.setCurrentPatient(getPatient());
		switchNextAppointment(getPatient());
		/* ================================================== */
	}
	
	// ~ Inner Classes
	// ==========================================================
	/**
	 * a listener Class with a onMessage-Method which is called when a new
	 * message arrives
	 * 
	 * @author Johannes Hermen johannes.hermen@tudor.lu Tudor/Santec
	 * 
	 */
	public class PatientManagerMessageListener implements MessageListener
	{
		// ~ Constructors
		// =======================================================
		
		public PatientManagerMessageListener()
		{
		}
		
		
		// ~ Methods
		// ============================================================
		
		/*
		 * (non-Javadoc)
		 * 
		 * @see javax.jms.MessageListener#onMessage(javax.jms.Message)
		 */
		public void onMessage(Message msg)
		{
			// show updated patient
			try
			{
				if (msg instanceof ObjectMessage) {
					Object payload = ((ObjectMessage) msg).getObject();
					if (payload instanceof Patient) {
						Patient pv = (Patient) ((ObjectMessage) msg).getObject();
						
						if (GECAMedModule.getCurrentUser().getId().equals(pv.getModifiedBy()))
						{
							// nothing to do, as yourself just changed this patient....
						}
						else
						{
							// patient was changed by another user, and we have this
							// patient openend
							if (isOpenPatient(pv))
							{
								mainFrame.statusBar.setMessageText(Translatrix.getTranslationString("pm.patient") + " " + pv.getFirstName() + " " + pv.getSurName() + " " + Translatrix.getTranslationString("pm.changed"));
								MainFrame.fireGECAMedMessage(new GECAMedMessage(PatientManagerModule.getInstance(), PATIENT_UPDATED, null, pv));
							}
						}						
					} else if (payload instanceof PatientUpdateObject) {
//						System.out.println("Received PatientUpdateObject Message on "+TOPIC_NAME);
//						System.out.println(payload);
					}
				}
			}
			catch (Exception e)
			{
			}
		}
	}

	/**
	 * called by GECAMedModule.setCurrentPatient()
	 * 
	 */
	public void patientChanged(Patient patient)
	{
		if (!patient.equals(getPatient()))
		{
			addPatient(patient, false);
		}
		
		if (patient != null && patient.getIdLuxembourg() != null && ESanteGuiUtils.isESanteModuleActivated())
		{
			titleLabel.setIcon(ESanteGuiUtils.getESanteIcon(64));
		}
		else
		{
			titleLabel.setIcon(null);
		}
	}
	
	
	/**
	 * @param p_IconName
	 * @return
	 */
	public static ImageIcon getIcon(String p_IconName)
	{
		return IconFetcher.getIcon(PatientManagerModule.class, p_IconName);
	}
	
	
	@Override
	public void afterShowup()
	{
		if (!initButtons)
		{
			/* Add all global gecamed actions that ought to be top bar actions
			 * to the patient panel top bar.
			 */
			Set<String> keys = GlobalHotkeyRegister.getHotKeyKeys();
			
			int i = 0;
			for (String key : keys)
			{
				if (key == null || "".equals(key.trim()))
					continue;
				
				GECAMedAction element = (GECAMedAction) GlobalHotkeyRegister.getHotKey(key);
				if (element.isTopBarAction())
				{
					// create a new button with the GECAMedAction as action
					JButton jb = new JButton(element);
					jb.setText(null);
					this.addTopButton(jb, i++);
				}
			}
			this.addTopButton(new JLabel(), i);
			initButtons = true;
		}
	}
	
	
	public static ImageIcon getMiniIcon(String p_IconName)
	{
		return IconFetcher.getScaledIcon(PatientManagerModule.class, p_IconName, MINIPIX);
	}
	
	
	public static ImageIcon getMediumIcon(String p_IconName)
	{
		return IconFetcher.getScaledIcon(PatientManagerModule.class, p_IconName, MEDIPIX);
	}
	
	
	public static ImageIcon getScaledIcon(String p_IconName, int width, int height)
	{
		return IconFetcher.getScaledIcon(PatientManagerModule.class, p_IconName, width, height);
	}
	
	
	/**
	 * returns the current open patients
	 * 
	 * @return
	 */
	public ArrayList<Patient> getOpenPatients()
	{
		ArrayList<Patient> patients = new ArrayList<Patient>();
		for (int i = 0; i < patientPanels.length; i++)
		{
			if (patientPanels[i] != null)
			{
				patients.add(patientPanels[i].getPatient());
			}
		}
		return patients;
	}
	
	
	public List<PatientPanel> getPatientPanels ()
	{
		List<PatientPanel> panels = new LinkedList<PatientPanel>();
		for (PatientPanel panel : patientPanels)
		{
			if (panel != null)
				panels.add(panel);
		}
		
		return panels;
	}
	
	
	/**
	 * returns the id of the patient panel if the specified patient is currently
	 * open
	 * 
	 * @param p
	 * @return
	 */
	public boolean isOpenPatient(Patient p)
	{
		return getOpenPatients().contains(p);
	}
	
	
	/**
	 * @return
	 */
	public static PatientManagerModule getInstance()
	{
		/* ====================================================== */
		return patientManagerModule;
		/* ====================================================== */
	}
	
	
	/*
	 * called if a patient slot button is pressed
	 */
	public void actionPerformed(ActionEvent e)
	{
		String actioncommand = e.getActionCommand();
		if (listenerActivated)
		{
			try
			{
				cardLayout.show(cardPanel, actioncommand);
				if (e.getSource() instanceof JToggleButton)
				{
					// get the new patient slot:
					for (int i = 0; i < buttons.length; i++)
					{
						if (e.getSource().equals(buttons[i]))
						{
							showSlot(i);
						}
					}
				}
			}
			catch (Exception e2)
			{
				logger.log(Level.WARN, "showing patient failed", e2);
			}
		}
	}
	
	
	/*
	 * sets the buttonpanel and titlebar to the selected patient
	 */
	public void propertyChange(PropertyChangeEvent evt)
	{
		/* ============================================= */
		// if (evt.getPropertyName().equals(New_PatientPanel.VIEW_CHANGED)) {
		this.functionsPanel.removeAll();
		this.functionsPanel.add(getPatientPanel().getFunctionButtonPanel());
		this.functionsPanel.validate();
		this.functionsPanel.updateUI();
		// }
		
		String moduleNameTranslated = Translatrix.getTranslationString(getName());
		String str = getPatient().toShortString();
		String ssn = "";
		try {
			ssn = getPatient().getSocialSecurityNumber();
			ssn=SSNChecker.getFormattedSSN(ssn, true);
			//Here we have to change the str according to the settings (show/hide ID)
			
			if((Boolean)patientSettings.getValue(PatientModuleSettings.SHOW_ID_IN_HEADER))
			{
				ssn = "(" + ssn.trim() + ") - " + getPatient().getId();
			}
			else
			{
				ssn = "(" + ssn.trim() + ") ";
			}
		
		} catch (Exception e) {}
		
		
	
		
		// update the slot button
		// update the Modules title
		
		int textWidth = 0;
		try
		{
			FontMetrics metrics = this.titleLabel.getGraphics().getFontMetrics();
			String s = moduleNameTranslated + ": " + str + " " + ssn + " *";
			textWidth = metrics.stringWidth(s);
		}
		catch (Exception e)
		{
		}
		// Berechne Stringbreite und -höhe
		int labelWidth = this.titleLabel.getWidth();
		
		/* ------------------------------------------------------ */
		// shorten the patient.to string to MAX_LENGTH_PATIENT_NAME chars
		Boolean showIDinHeader;
		
	
		
		if (labelWidth != 0 && textWidth > labelWidth)
			try
			{
				
				str = getPatient().toString().substring(0, MAX_LENGTH_PATIENT_NAME - 2) + "..";
			}
			catch (Exception e)
			{
			}
		
		/* ------------------------------------------------------ */
		if (getPatientPanel().isModified())
		{
			
			buttons[currentSlot].setText((currentSlot + 1) + ": " + getPatient().toShortString() + " *");
			
			this.titleLabel.setText(str + " " + ssn + " *");
			
			this.titlePanel.setColor(Color.YELLOW);
		}
		else
		{
			buttons[currentSlot].setText((currentSlot + 1) + ": " + getPatient().toShortString());
			
			
			this.titleLabel.setText(str + " " + ssn);
			
			this.titlePanel.setColor(Color.WHITE);
		}
		
		// set patient Icon 
		if (getPatient().getStatus() != null && getPatient().getStatus().equals(Patient.STATUS_DEPARTED))
		{
			this.titlePanel.setIcon(IconFetcher.getIcon(PatientManagerModule.class, PatientManagerIconNames.ICON_DEPARTED));
		}
		else
		{
			//	    this.titlePanel.setIcon(getIcon(PATIENT));
			
			if (getPatient().getGender() != null && getPatient().getGender().equals(Gender.FEMALE))
			{
				this.titlePanel.setIcon(IconFetcher.getIcon(PatientManagerModule.class, PatientManagerIconNames.FEMALE));
			}
			else if (getPatient().getGender() != null && getPatient().getGender().equals(Gender.MALE))
			{
				this.titlePanel.setIcon(IconFetcher.getIcon(PatientManagerModule.class, PatientManagerIconNames.MALE));
			}
			else
			{
				this.titlePanel.setIcon(getIcon(PATIENT));
			}
			
		}
		
		try
		{
			if (getPatientPanel().isModified() && getPatientPanel().isFilledOK())
			{
				this.savePatientAction.setEnabled(true);
				this.showPatientVisits.setEnabled(true);
			}
			else
			{
				this.savePatientAction.setEnabled(false);
				this.showPatientVisits.setEnabled(false);
			}
		}
		catch (Exception e)
		{
		}
		
		// show men� item 'Show patient visits' only if a Patient is open
		try
		{
			if (getPatientPanel().isFilledOK())
			{
				this.showPatientVisits.setEnabled(true);
				this.exportPatient.setEnabled(true);
			}
			else
			{
				this.showPatientVisits.setEnabled(false);
				this.exportPatient.setEnabled(true);
			}
		}
		catch (Exception e)
		{
		}
		
		/* ============================================= */
	}
	
	
	/**
	 * Shows a dialog containing all warning messages from warning memos
	 * 
	 * @param memos
	 */
	private void showWarningMemoDialog(List<PatientMemo> memos)
	{
		/* ================================================== */
		if (memos == null || memos.size() < 1)
			return;
		/* ------------------------------------------------------- */
		StringBuffer buff = new StringBuffer();
		for (PatientMemo m : memos)
		{
			String s = m.getNote().replaceAll("<html>|</html>", "");
			buff.append(s.replaceAll("<body>|</body>|<head>|</head>", "") + "<br><hr><br>");
		}
		// remove all <html> and <body> tags
		/* ------------------------------------------------------- */
		final JDialog d = new JDialog(MainFrame.getInstance(), Translatrix.getTranslationString("pm.warning"), true);
		JEditorPane t = new JEditorPane();
		t.setEditorKit(new HTMLEditorKit());
		t.setEditable(false);
		t.setText("<html><body>" + buff.toString() + "</body></html>");
		JScrollPane scroll = new JScrollPane(t);
		
		d.setLayout(new BorderLayout());
		d.add(scroll, BorderLayout.CENTER);
		
		JButton closeButton = new JButton(Translatrix.getTranslationString("pm.ok"), GECAMedModule.getSmallIcon(GECAMedIconNames.OK));
		closeButton.addActionListener(new ActionListener()
		{
			
			public void actionPerformed(ActionEvent e)
			{
				/* ====================================================== */
				d.setVisible(false);
				/* ====================================================== */
			}
		});
		/* ------------------------------------------------------- */
		
		ButtonBarBuilder bb = new ButtonBarBuilder();
		bb.addGlue();
		bb.addGridded(closeButton);
		bb.addGlue();
		d.add(bb.getPanel(), BorderLayout.SOUTH);
		closeButton.requestFocus();
		
		Thread thread = new Thread()
		{
			public void run()
			{
				d.setSize(new Dimension(400, 400));
				MainFrame.showDialogCentered(d);
			}
		};
		thread.start();
		/* ================================================== */
	}
	
	
	/**
	 * Loads all accidents of a patient and stores them in a static hash
	 * 
	 * @param patient
	 */
	private void loadAccidents(Patient patient)
	{
		/* ================================================== */
		if (patient == null)
			return;
		/* ------------------------------------------------------- */
		IncidentManager manager = (IncidentManager) ManagerFactory.getRemote(IncidentManagerBean.class);
		/* ------------------------------------------------------- */
		List<Incident> result = manager.getAccidents(patient.getId());
		if (result != null)
		{
			patientAccidents.put(patient.getId(), result);
		}
		/* ================================================== */
	}
	
	
	public static List<Incident> getPatientAccidents(Integer patientId)
	{
		/* ================================================== */
		return patientAccidents.get(patientId);
		/* ================================================== */
	}
	
	
	/**
	 * Adds an accident to the hashmap that is not saved yet.
	 * 
	 * @param incAccident
	 */
	public static void addPatientAccident(Incident incAccident)
	{
		/* ================================================== */
		if (incAccident == null || incAccident.getPatientId() == null)
			return;
		/* ------------------------------------------------------- */
		List<Incident> temp = patientAccidents.get(incAccident.getPatientId());
		if (temp == null)
		{
			/* ------------------------------------------------------- */
			temp = new ArrayList<Incident>();
			
			patientAccidents.put(incAccident.getPatientId(), temp);
			/* ------------------------------------------------------- */
		}
		/* ------------------------------------------------------- */
		// if already in the list, replace
		/* ------------------------------------------------------- */
		int pos = temp.indexOf(incAccident);
		if (pos > -1)
			temp.set(pos, incAccident);
		else
			temp.add(incAccident);
		/* ================================================== */
	}
	
	
	/**
	 * Removes an accident from the local hash
	 * 
	 * @param incAccident
	 */
	public static void removePatientAccident(Incident incAccident)
	{
		/* ================================================== */
		if (incAccident == null || incAccident.getPatientId() == null)
			return;
		/* ------------------------------------------------------- */
		List<Incident> temp = patientAccidents.get(incAccident.getPatientId());
		if (temp != null)
		{
			/* ------------------------------------------------------- */
			temp.remove(incAccident);
			/* ------------------------------------------------------- */
		}
		/* ================================================== */
	}
	
	
	/**
	 * Checks if the maiden name is used as principal name.
	 * 
	 * @return
	 */
	public static boolean isMaidenConfig()
	{
		/* ================================================== */
		if (PatientManagerModule.getInstance().administrativeElementsPlugin.getValue(SettingConstants.MAIDEN_CONFIG) != null && ((Boolean) PatientManagerModule.getInstance().administrativeElementsPlugin.getValue(SettingConstants.MAIDEN_CONFIG)))
		{
			return true;
		}
		
		return false;
		/* ================================================== */
	}
	
	
	/**
	 * Shows the appointment of a patient in the navibar
	 * 
	 * @param patientId
	 */
	private void switchNextAppointment(Patient patient)
	{
		/* ================================================== */
		try
		{
			// the Agenda Module needn't to be loaded, no module
			// no feature!
			Appointment nextApp = AgendaModule.getInstance().getNextAppointmentOfPatient(patient.getId());
			appointmentProposalArea.setAppointment(nextApp);
			// reset the entry in the cache
			getCache(patient).put(CACHE_PATIENT_NEXT_APPOINTMENT, null);
			
			// set tooltip
			if (nextApp == null)
			{
				/* ------------------------------------------------------- */
				appointmentPreviewButton.setToolTipText(Translatrix.getTranslationString("patient.agendaTooltip") + (getPatient().getSurName() != null ? getPatient().getSurName() : "") + ", " + (getPatient().getFirstName() != null ? getPatient().getFirstName() : ""));
				/* ------------------------------------------------------- */
			}
			else
			{
				/* ------------------------------------------------------- */
				appointmentPreviewButton.setToolTipText(Translatrix.getTranslationString("patient.agendaTooltipNext"));
				/* ------------------------------------------------------- */
			}
			/* ------------------------------------------------------- */
			appointmentPreviewButton.validate();
			appointmentPreviewButton.updateUI();
		}
		catch (Exception e)
		{
			// e.printStackTrace();
		}
		/* ================================================== */
	}
	
	
	public void handleGECAMedMessage(GECAMedMessage message)
	{
		
		if ((message.getModul().equals(BillingModule.getInstance())) && (message.getMessage().equals(InvoiceTemplateDialog.c_TemplateChanged) || message.getMessage().equals(InvoiceTemplateDialog.c_TemplateOrderChanged) || message.getMessage().equals(InvoiceTemplateDialog.c_TemplateListChanged)))
		{
			Vector<AbstractButton> v2 = TemplateManager.getInstance().getTemplateButtons(true);
			
			invoiceTemplates.setButtons(v2);
			invoiceTemplates.repaint();
		}
		
	}
	
	
	/**
	 * Returns the hashmap for the patient in the cache.<br>
	 * If there is no item for that, a new hashmap will be created.<br/>
	 * If the patientId is null, a new HashMap will be created anyway but is not
	 * going to be stored in the map
	 * 
	 * @param patientId
	 * @return
	 */
	public static HashMap<String, Object> getCache(Patient patient)
	{
		/* ================================================== */
		HashMap<String, Object> cache = patientDataCache.get(patient);
		
		if (cache == null)
		{
			cache = new HashMap<String, Object>();
			patientDataCache.put(patient, cache);
		}
		return cache;
		/* ================================================== */
	}
	
	
	public void dragEnter(DropTargetDragEvent dtde)
	{
		/* ====================================================== */
//		System.out.println("Dreck entered " + dtde);
		/* ====================================================== */
	}
	
	
	public void dragExit(DropTargetEvent dte)
	{
	}
	
	
	public void dragOver(DropTargetDragEvent dtde)
	{
	}
	
	
	public void drop(DropTargetDropEvent dtde)
	{
		Transferable		tr;
		DataFlavor[]		flavors;
		String				dropString;
		List<?>				drops;
		Collection<File>	files;
		File				file;
		FileImportDialog	fid;
		PatientPanel		pp;
		//	System.out.println("Drop " + dtde);
		
		try
		{
			tr = dtde.getTransferable();
			flavors = tr.getTransferDataFlavors();
			for (int i = 0; i < flavors.length; i++)
			{
				if (flavors[i].isFlavorJavaFileListType())
				{
					dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
					// TODO: call the append file dialog with this file
					dropString	= ((java.util.List<?>) tr.getTransferData(flavors[i])).get(0).toString();
					try
					{
						drops	= (List<?>) tr.getTransferData(flavors[i]);
						files	= new HashSet<File>(drops.size());
						for (Object o : drops)
						{
							try
							{
								System.out.println(o);
								if (o instanceof File)
									file	= (File) o;
								else 
									file	= new File(String.valueOf(o));
								
								if (file.exists() && file.isFile())
								{
									if (!files.contains(file))
										files.add(file);
								}
								else
									logger.warn(o + " cannot be resolved as an existing file");
							}
							catch (Exception e)
							{
								logger.warn(o + " cannot be resolved as a file");
							}
						}
						
						fid	= new FileImportDialog();
						if (files.size() > 0)
						{
							pp	= getPatientPanel();
							fid.showDialog(pp.getCurrentIncident(false), files);
							pp.reloadHistory();
						}
					}
					catch (Exception e)
					{
						logger.log(Level.WARN, "Couldn't resolve the drop result to a valid file path", e);
					}
					
					System.out.println(dropString);
					dtde.dropComplete(true);
					
					return;
				}
				else if (flavors[i].isRepresentationClassInputStream())
				{
					/* ------------------------------------------------------- */
					// dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
					// dtde.acceptDrop(DnDConstants.ACTION_LINK);
					// BufferedReader r=new
					// BufferedReader(flavors[i].getReaderForText(tr));
					
					// String text=r.readLine();
					// URI link=new URI(text);
					//		    System.out
					//			    .println("TODO: PatientManagerModule::drop  DnD not working yet");
					// File f = new File(link);
					
					// addFile(f);
					
					// System.out.println(link.toString());
					// dtde.getDropTargetContext().dropComplete(true);
					// reload history
					
					return;
					/* ------------------------------------------------------- */
				}
				
			}
			//	    System.out.println("Drop failed: " + dtde);
			dtde.rejectDrop();
		}
		catch (Exception e)
		{
			e.printStackTrace();
			dtde.rejectDrop();
		}
		/* ====================================================== */
	}
	
	
	public void dropActionChanged(DropTargetDragEvent dtde)
	{
		/* ====================================================== */
		/* ====================================================== */
	}
	
	
	// public void addFile(File file) {
	// /* ================================================== */
	// if (file == null)
	// return;
	// /* ------------------------------------------------------- */
	// if (file.isDirectory())
	// return;
	// /* ------------------------------------------------------- */
	// // Read the file
	// if (file.length() > MAX_FILE_UPLOAD_SIZE) {
	// System.out.println("TODO: file size exceeds maximum");
	// return;
	// }
	// /* ------------------------------------------------------- */
	// try {
	// /* ------------------------------------------------------- */
	// IncidentManager iManager = (IncidentManager)
	// ManagerFactory.getRemote(IncidentManagerBean.class);
	// FileInputStream fin = new FileInputStream(file);
	// BufferedInputStream bin = new BufferedInputStream(fin);
	// byte[] b = new byte[(int) file.length()];
	// bin.read(b);
	// /* ------------------------------------------------------- */
	// String mimeType = getMIMEType(file);
	// // create a new incident entry type object
	// IncidentEntryType et = new IncidentEntryType();
	// et.setMimeType(mimeType);
	//			
	// // create a new IncidentEntry object
	// IncidentEntry ie = new IncidentEntry();
	// IncidentEntryBinary ib = new IncidentEntryBinary();
	// ib.setBinaryContent(b);
	//			
	// ie.setBinaryContent(ib);
	// ie.setEntryType(et);
	//			
	//
	// PatientPanel currPanel = patientPanels[currentSlot];
	// Incident i = currPanel.getHistoryTableModel().getLatestIncident();
	// if (i == null ) {
	// Incident newI = iManager.saveIncident(new
	// Incident(this.getPatient().getId(),
	// MainFrame.getCurrentPhysician().getId()));
	// ie.setIncident(newI);
	// } else
	// ie.setIncident(i);
	//			
	// // set file name
	// ie.setFileName(file.getName());
	// ie.setFileSize(file.length());
	// /* ------------------------------------------------------- */
	// // save
	//			
	// ie = iManager.saveEntry(ie, IncidentManager.FILE);
	// System.out.println("Binary Oid: " + ie.getBinaryContent());
	// IncidentEntry ie2 = iManager.loadBinary(ie);
	// System.out.println("Binary : " + ie2.getBinaryContent());
	// // reload history
	// currPanel.getHistoryTableModel().reload();
	// /* ------------------------------------------------------- */
	// } catch (FileNotFoundException e) {
	// e.printStackTrace();
	// }
	// catch (IOException e) {
	// e.printStackTrace();
	// }
	// /* ================================================== */
	// }
	
	/**
	 * Easy but nor very robust solution to get the mime-type of a file
	 * 
	 * @param file
	 * @return
	 */
	public static String getMIMEType(File file)
	{
		/* ================================================== */
		if (!file.exists())
			throw new IllegalArgumentException("File does not exit!");
		if (file.isDirectory())
			return "directory";
		try
		{
			URLConnection uCon = file.toURI().toURL().openConnection();
			String mime = uCon.getContentType();
			uCon.getInputStream().close();
			return mime;
		}
		catch (IOException e)
		{
			throw new IllegalArgumentException(e.getMessage());
		}
		/* ================================================== */
	}
	
	
	/**
	 * Loads a patient by its id.
	 * 
	 * @param patientId
	 */
	public void loadPatient(Integer patientId)
	{
		/* ================================================== */
		try
		{
			/* ------------------------------------------------------- */
			// get the patient from the database
			/* ------------------------------------------------------- */
			PatientAdminInterface pManager = (PatientAdminInterface) ManagerFactory.getRemote(PatientAdminBean.class);
			Patient patient = pManager.getPatient(patientId);
			/* ------------------------------------------------------- */
			// set the patient
			/* ------------------------------------------------------- */
			GECAMedModule.setCurrentPatient(patient);
			MainFrame.getInstance().selectModule(PatientManagerModule.MODULE_NAME);
			/* ------------------------------------------------------- */
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		/* ================================================== */
	}
	
	
	/**
	 * Check if the patient module is modify.
	 * 
	 * @return true if any patient panel is modify else false.
	 */
	public boolean isModified()
	{
		for (int i = 0; i < patientPanels.length; i++)
		{
			if (patientPanels[i] != null)
			{
				if (patientPanels[i].isModified())
				{
					return true;
				}
			}
		}
		return false;
	}
	
	
	private class LoadingThread extends Thread
	{
		private Patient	patient;
		private boolean	asNewTab;
		private String[] disabledTabs;
		
		
		public LoadingThread (Patient patient, boolean asNewTab, String[] disabledTabs)
		{
			this.patient = patient;
			this.asNewTab = asNewTab;
			this.disabledTabs = disabledTabs;
		}
		
		
		public void run()
		{
			try
			{
				logger.info(MainFrame.createLogSectionString("START loading Patient: " + patient.toString() + "     asNewTab=" + asNewTab));
				/* ------------------------------------------------------- */
				// if the patient is allready open, just select him
				if (isOpenPatient(patient))
				{
					for (int i = 0; i < patientPanels.length; i++)
					{
						try
						{
							if (patientPanels[i].getPatient().equals(patient))
							{
								buttons[i].doClick();
								return;
							}
						}
						catch (Exception e)
						{
						}
					}
				}
				
				
				// set waitcursor
				mainFrame.statusBar.setProgress(Translatrix.getTranslationString("pm.loadingPatient"), StatusBar.PROGRESS_INDETERMINATE);
				mainFrame.setWaitCursor(true);
				long start = System.currentTimeMillis();
				
				/* ------------------------------------------------------- */
				// ===================================================================
				// Obtain all accident numbers for that patient
				// store them
				/* ------------------------------------------------------- */
				loadAccidents(patient);
				// ====================================================
				// get the next appointment for the patient
				switchNextAppointment(patient);
				
				// ==================================================================
				// Obtain all warning memos
				// and show them in a dialog
				// ==================================================================
				PatientMemoInterface memoManager = (PatientMemoInterface) ManagerFactory.getRemote(PatientMemoManagerBean.class);
				//			PatientMemoInterface memoManager = (PatientMemoInterface) ManagerFactory
				//					.getRemote(ManagerFactory.MEMOMANAGER);
				List<PatientMemo> memos = memoManager.getWarningMemos(patient.getId());
				getCache(patient).put(CACHE_PATIENT_WARNING_MEMOS, memos);
				
				try
				{
					Long mCount = memoManager.getMemoCountByPatientID(patient.getId());
					getCache(patient).put(CACHE_PATIENT_MEMO_COUNT, mCount);
				}
				catch (Exception e)
				{
					e.printStackTrace();
				}
				// =================================================================
				// open Patient in a new Panel
				//
				// =================================================================
				//			unstopppapal = true;
				if (asNewTab || getPatientPanel().isModified())
				{
					/* ------------------------------------------------------- */
					if (addPatientPanel(patient))
					{
						GECAMedModule.setCurrentPatient(patient);
					}
					else
					{
						//				unstopppapal = false;
						logger.info(MainFrame.createLogSectionString("no patient loaded, slots full. " + " took: " + (System.currentTimeMillis() - start) + "ms"));
						// reset Cursor
						mainFrame.setWaitCursor(false);
						mainFrame.statusBar.setProgress(Translatrix.getTranslationString("patient.noSlotLeft"), 0);
						MainFrame.getInstance().showMessage(Translatrix.getTranslationString("patient.noSlotLeft"), 4000);
						return;
					}
					/* ------------------------------------------------------- */
					// open patient in current Tab
				}
				else
				{
					/* ------------------------------------------------------- */
					getPatientPanel().setPatient(patient);
					GECAMedModule.setCurrentPatient(patient);
					/* ------------------------------------------------------- */
				}
				
				if (disabledTabs != null && disabledTabs.length > 0)
				{
					StringBuilder disabledTabsList = new StringBuilder();
					
					for (String tab : disabledTabs)
					{
//						getPatientPanel().enableTab(tab, false);
						getPatientPanel().permanentlyDisableTab(tab);
						disabledTabsList.append(tab).append(", ");
					}
					PatientAdminBean.getInstance().log(Integer.valueOf(Level.INFO.toInt()), "Patient " 
							+ patient.toString() + " loaded without tab(s) " 
							+ disabledTabsList.substring(0, disabledTabsList.length() - 2));
				}
				
				/* ------------------------------------------------------- */
				//			unstopppapal = false;
				
				logger.info(MainFrame.createLogSectionString("END loading patient " + patient.toString() + " (GECAMed ID: " + patient.getId() + ") took: " + (System.currentTimeMillis() - start) + "ms"));
				
				// reset Cursor
				mainFrame.setWaitCursor(false);
				mainFrame.statusBar.setProgress(Translatrix.getTranslationString("pm.patientLoaded"), 0);
				
				if (memos != null && memos.size() > 0)
				{
					/* ------------------------------------------------------- */
					// show dialog
					showWarningMemoDialog(memos);
					/* ------------------------------------------------------- */
				}
				/* ------------------------------------------------------- */
			}
			catch (Exception e)
			{
				logger.log(Level.WARN, "Patient loading canceled....", e);
				return;
			}
		}
	}


	public void eSanteIdChanged (String eSanteId, Integer patientId)
	{
		if (eSanteId != null)
			titleLabel.setIcon(ESanteGuiUtils.getESanteIcon(64));
		else
			titleLabel.setIcon(null);
		PatientListModule.getInstance().research();
	}
	
	public static boolean getUseMnemonics() {
		try {
			return (Boolean) MainFrame.getInstance().settingsPanel.getValue(HotkeySettingsPlugin.NAME, HotkeySettingsPlugin.PATIENTSIDEBAR_HOTKEYS_ENABLED);			
		} catch (Exception e) {
			return true;
		}
	}
}
