/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.core.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JToggleButton;
import javax.swing.border.EmptyBorder;

import lu.tudor.santec.gecamed.core.gui.widgets.ModuleHeader;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.Permission;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.Role;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.beans.LoginBean;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface;
import lu.tudor.santec.gecamed.usermanagement.gui.settings.UserSettingsPlugin;
import lu.tudor.santec.i18n.Relocalizable;
import lu.tudor.santec.i18n.Translatrix;
import lu.tudor.santec.settings.SettingsPlugin;

import org.apache.log4j.Logger;

import com.jgoodies.forms.builder.ButtonBarBuilder;

//***************************************************************************
//* Class Definition and Members                                            *
//***************************************************************************

/**
 * Abstract class of a GECAMED Module. All modules in GECAMed should extend this
 * class. A GECAMed Module is shown as a JPanel on the main screen and is
 * represented via its icon in the ButtonBar on the left.
 * 
 * @Version <br>
 *          $Log: GECAMedModule.java,v $
 *          Revision 1.85  2013-12-27 18:09:26  donak
 *          Cleanup of imports
 *
 *          Revision 1.84  2013-07-15 06:18:35  ferring
 *          logging changed
 *
 *          Revision 1.83  2013-01-02 13:19:15  ferring
 *          Unsaved-Data-Dialog changed
 *
 *          Revision 1.82  2012-10-31 16:40:47  troth
 *          Version 1.1 of GECAMed launcher.
 *
 *          Revision 1.81  2011-03-04 09:53:11  ferring
 *          Hotkeys for physicians added.
 *          It is now possible to make a hotkey consisting of key + modifiers.
 *
 *          Revision 1.80  2010-06-09 12:58:12  ferring
 *          loaded modules needn't be shown anymore
 *          => override the method isShown in the GECAMedModule (default is true)
 *
 *          Revision 1.79  2010-04-27 15:06:11  mack
 *          Changes required by caching user permissions on client side to avoid db querries
 *
 *          Revision 1.78  2010-03-19 12:01:06  hermen
 *          improved and unified iconfetching
 *
 *          Revision 1.77  2009-01-26 13:32:33  hermen
 *          added and implemented right PERMISSION_CHANGE_PHYSICIAN which allows/disallows a user to change the current physician
 *
 *          Revision 1.76  2009-01-22 10:32:30  hermen
 *          added and implemented right PERMISSION_CHANGE_PHYSICIAN which allows/disallows a user to change the current physician
 *
 *          Revision 1.75  2009-01-22 07:35:51  hermen
 *          improved startup logging and progress dialog
 *
 *          Revision 1.74  2008-10-21 09:53:34  hermen
 *          fixed patient slot bug
 *          enhanced logging
 *          code cleanup
 *
 *          Revision 1.73  2008-10-07 09:34:37  heinemann
 *          translations of roles and rights;
 *          show only  roles and rights of the activated modules in the usermanagement section
 * <br>
 *          Revision 1.72 2008-10-02 12:49:15 hermen <br>
 *          improved logging <br>
 * <br>
 *          Revision 1.71 2008-09-25 09:43:07 heinemann <br>
 *          fixed copyrights <br>
 * <br>
 *          Revision 1.70 2008-08-04 10:06:13 hermen <br>
 *          moved toolbarsize setting to usersettings <br>
 * <br>
 *          Revision 1.69 2008-05-23 07:41:32 hermen <br>
 *          FIXED BUG WHEN ADDING PLUGINS AFTER LOADING THE SETTINGS <br>
 * <br>
 *          Revision 1.68 2008-05-22 07:35:03 hermen <br>
 *          added settings debug <br>
 * <br>
 *          Revision 1.67 2008-05-19 10:06:55 hermen <br>
 *          now settings are only loaded once and the access to the settings is
 *          now synchronized. <br>
 * <br>
 *          Revision 1.66 2008-04-15 15:22:25 mack <br>
 *          Added protected setIcon method <br>
 * <br>
 *          Revision 1.65 2008-02-27 08:22:30 heinemann <br>***
 *          empty log message *** <br>
 * <br>
 *          Revision 1.64 2008-02-26 09:15:46 hermen <br>
 *          added initModule() to GECAMedModule, which is called after all
 *          modules have been instanciated <br>
 * <br>
 *          Revision 1.63 2008-02-13 12:45:46 heinemann <br>
 *          fixed problem with color change of the modul header <br>
 * <br>
 *          Revision 1.62 2008-02-11 16:47:18 heinemann <br>
 *          gradient backgound to the module header <br>
 * <br>
 *          Revision 1.61 2008-01-28 08:28:06 hermen <br>
 *          moved functionality to IconFetcher Class and GECAMedIconNames
 *          Interface <br>
 * <br>
 *          Revision 1.60 2008-01-15 09:29:39 hermen <br>
 *          updated Javadoc and refactured code <br>
 * <br>
 *          Revision 1.59 2008-01-10 09:28:45 hermen <br>
 *          enhanced logging <br>
 * <br>
 *          Revision 1.58 2008-01-10 09:00:25 hermen <br>
 *          enhanced logging <br>
 * <br>
 *          Revision 1.57 2007-12-05 08:35:01 heinemann <br>
 *          removed duplicate code in different constructors <br>
 * <br>
 *          Revision 1.56 2007-12-04 14:02:54 heinemann <br>
 *          comments <br>
 * <br>
 *          Revision 1.55 2007-12-03 10:59:02 hermen <br>
 *          updated Javadoc <br>
 * 
 */
public abstract class GECAMedModule extends JPanel implements Relocalizable,
		GECAMedIconNames {

	private static final long serialVersionUID = 1L;

	/**
	 * a reference to the Main Window of GECAMed
	 */
	public MainFrame mainFrame;

	/**
	 * the builder for the buttonbar on the Module Bottom
	 */
	private ButtonBarBuilder bottomButtonBarBuilder;

	/**
	 * the Menue for this Module (will be shown in the MenueBar)
	 */
	private JMenu moduleMenu;

	/**
	 * the Titlepanel on the Modul top containing the Module icon, the Module
	 * Name etc..
	 */
	protected ModuleHeader titlePanel;

	/**
	 * the untranslated name of the Module
	 */
	private String moduleName;

	/**
	 * the Modules Icon
	 */
	private ImageIcon moduleIcon;

	/**
	 * The Module Color (shown in the TitlePanel)
	 */
	private Color moduleColor;

	/**
	 * The Panel for the ceonter of the Module
	 */
	private JComponent contentPanel;

	/**
	 * The modules button in the left ButtonBar
	 */
	private JToggleButton moduleButton;

	/**
	 * the Modules defined actions
	 */
	private Vector<GECAMedAction> moduleActions;

	/**
	 * reference to the currently selected Patient
	 */
	private static Patient currentPatient;

	/**
	 * reference to the Login Bean to retrieve rights and roles
	 */
	private static LoginInterface loginInterface;

	/**
	 * static list of listeners to retrieve patientchanged events
	 */
	private static Collection<PatientListener> patientListeners = new ArrayList<PatientListener>();

	/**
	 * hash of the permissions for this module and the current user.
	 */
	private static Hashtable<String, Integer> permissionsHash = new Hashtable<String, Integer>();
	
	/**
	 * Vector of the Permission objects of the modules.
	 */
	private static List<Permission> permissions = Collections.synchronizedList(new ArrayList<Permission>());
	
	private static HashSet <String> userPermissions = new HashSet <String> ();
	
	/**
	 * List of all available roles of the modules
	 */
	private static List<Role> roles = Collections.synchronizedList(new ArrayList<Role>());
	

	/**
	 * list of Hotkeys and related Actions for this module
	 */
	private LinkedHashMap<String, GECAMedAction> hotKeys = new LinkedHashMap<String, GECAMedAction>();

	/**
	 * static logger for this class
	 */
	private static Logger logger = Logger.getLogger(GECAMedModule.class
			.getName());

	/**
	 * Flag to specifiy whether this module can be called from the patient
	 * listmodule to display a patient.
	 */
	private boolean canDisplayPatient = false;

	/**
	 * settings plugin for the Module, will be shown in the settings Dialog
	 */
	public Vector<SettingsPlugin> settingsPlugins = new Vector<SettingsPlugin>();

	private Vector<SettingsPlugin> adminSettingsPlugins = new Vector<SettingsPlugin>();

	private Integer iconSize;

	private ActionListener moduleButtonActionListener;

	/**
	 * static reference to the current selected Module
	 */
	protected static GECAMedModule currentModule = null;

	public static final String LAST_SELECTED_MODULE = "Last Module";

	
	
	
	
	
	// ***************************************************************************
	// * Constructor(s) *
	// ***************************************************************************

	// ---------------------------------------------------------------------------
	/**
	 * creates a new GECAMed Module
	 * 
	 * @param mainFrame
	 *            reference to the GECAMed Main window
	 * @param moduleName
	 *            the module name
	 * @param moduleIcon
	 *            the module icon
	 * @param moduleColor
	 *            the color for the module header
	 */
	// ---------------------------------------------------------------------------
	public GECAMedModule(String moduleName, ImageIcon moduleIcon,
			Color moduleColor) {
		/* ================================================== */
		this.mainFrame = MainFrame.getInstance();
		this.moduleName = moduleName;
		this.moduleIcon = moduleIcon;
		this.moduleColor = moduleColor;

		init();
		/* ================================================== */
	}

	// ---------------------------------------------------------------------------
	/**
	 * creates a new GECAMed Module
	 * 
	 * @param mainFrame
	 *            reference to the GECAMed Main window
	 * @param moduleName
	 *            the module name
	 * @param moduleIcon
	 *            the module icon
	 * @param moduleColor
	 *            the color for the module header
	 */
	// ---------------------------------------------------------------------------
	public GECAMedModule(MainFrame mainFrame, String moduleName,
			String moduleIconName, Color moduleColor) {
		/* ================================================== */
		this.mainFrame = mainFrame;
		this.moduleName = moduleName;
		this.moduleIcon = this.getModuleIcon(moduleIconName);
		this.moduleColor = moduleColor;

		init();
		/* ================================================== */
	}

	/**
	 * init the module. Must be called inside a constructor
	 */
	private void init() {
		/* ================================================== */
		logger.info("Instanciating module "
				+ Translatrix.getTranslationString(moduleName));
		iconSize = (Integer) mainFrame.userSettings
				.getValue(UserSettingsPlugin.TOOLBAR_SIZE);

		this.moduleButton = new JToggleButton(new ImageIcon(this.moduleIcon
				.getImage().getScaledInstance(iconSize, iconSize,
						Image.SCALE_SMOOTH)));
		if (iconSize >= 32) {
			this.moduleButton.setText(Translatrix
					.getTranslationString(this.moduleName));
		}
		this.moduleButton.setToolTipText(Translatrix
				.getTranslationString(this.moduleName));
		this.moduleButton.setActionCommand(this.moduleName);
		/* ------------------------------------------------------- */
		// create an ActionListener for the button
		/* ------------------------------------------------------- */
		this.moduleButtonActionListener = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				GECAMedModule.currentModule = GECAMedModule.this;
			}
		};
		this.moduleButton.addActionListener(this.moduleButtonActionListener);

		/* ------------------------------------------------------- */
		logger.info(MainFrame.createLogSectionString(Translatrix
				.getTranslationString("main.creatingModule")
				+ " " + Translatrix.getTranslationString(moduleName)));
		MainFrame.loginScreen.setStatus(Translatrix
				.getTranslationString("main.creatingModule")
				+ " " + Translatrix.getTranslationString(moduleName), 6);

		this.moduleActions = new Vector<GECAMedAction>();

		GECAMedModule.addModulePermissions(moduleName + "Module");
		GECAMedModule.addModuleRoles(moduleName + "Module");
		GECAMedModule.addUserPermissions(moduleName + "Module");

		
		buildPanel();
		/* ================================================== */
	}

	// ---------------------------------------------------------------------------
	// ***************************************************************************
	// * Class Primitives *
	// ***************************************************************************
	// ---------------------------------------------------------------------------

	// ---------------------------------------------------------------------------

	/**
	 * builds the panel for the Module
	 */
	private void buildPanel() {
		this.setLayout(new BorderLayout());
		this.setBorder(new EmptyBorder(5, 5, 5, 5));

		this.titlePanel = new ModuleHeader(Translatrix
				.getTranslationString(this.moduleName), this.moduleIcon,
				this.moduleColor);

		this.bottomButtonBarBuilder = new ButtonBarBuilder();
		this.bottomButtonBarBuilder.addGlue();

		titlePanel.setOpaque(false);

		this.add(this.titlePanel, BorderLayout.NORTH);
		// this.add(GradientFactory.makeGradient(titlePanel, this.moduleColor,
		// true), BorderLayout.NORTH);
		this.add(this.bottomButtonBarBuilder.getPanel(), BorderLayout.SOUTH);
	}

	/**
	 * returns the button for the left main buttonbar
	 * 
	 * @return the button for the left main buttonbar
	 */
	public JToggleButton getModuleButton() {
		return moduleButton;
	}

	/**
	 * returns the Modules name
	 */
	public String getName() {
		return this.moduleName;
	}

	public Color getColor() {
		return this.moduleColor;
	}

	public String getTranslatedName() {
		return Translatrix.getTranslationString(this.moduleName);
	}

	protected void setIcon(ImageIcon p_ModuleIcon) {
		if (p_ModuleIcon != null) {
			this.moduleIcon = p_ModuleIcon;
			if (this.moduleButton != null) {
				this.moduleButton.setIcon(p_ModuleIcon);
				this.moduleButton.validate();
			}

			if (this.titlePanel != null) {
				this.titlePanel.setIcon(p_ModuleIcon);
				this.titlePanel.validate();
			}
		}
	}

	/**
	 * returns the modules JMenuItem entry for the "window" menu in the menubar
	 * 
	 * @return JMenuItem entry for the "window" menu in the menubar
	 */
	public JMenuItem getWindowMenuEntry() {
		return new JMenuItem(new AbstractAction(Translatrix
				.getTranslationString(this.moduleName), new ImageIcon(
				this.moduleIcon.getImage().getScaledInstance(16, 16,
						Image.SCALE_SMOOTH))) {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				moduleButton.doClick();
			}
		});
	}

	/**
	 * adds a button to the buttonbar on the bottom
	 * 
	 * @param jb
	 *            the button
	 */
	public void addBottomButton(JComponent jb) {
		this.bottomButtonBarBuilder.addGridded(jb);
	}

	/**
	 * adds a new button to the buttonbar on the right top
	 * 
	 * @param jb
	 *            the Button
	 */
	public void addTopButton(JComponent jb) {
		this.titlePanel.addButton(jb);
	}

	/**
	 * adds a new button to the buttonbar on the right top on position index
	 * 
	 * @param jb
	 *            the Button
	 * @param index
	 *            the Position
	 */
	public void addTopButton(JComponent jb, int index) {
		this.titlePanel.addButton(jb, index);
	}

	public void addTopButtonSeparator() {
		this.titlePanel.addSeparator();
	}

	public void addTopButtonSeparator(int index) {
		this.titlePanel.addSeparator(index);
	}

	/**
	 * sets the center PAnel for this Module
	 * 
	 * @param jp
	 *            the Panel shown in teh Module Center
	 */
	public void setContentPanel(JComponent jp) {
		contentPanel = jp;
		this.add(contentPanel, BorderLayout.CENTER);
	}

	// ---------------------------------------------------------------------------
	/**
	 * Returns the JMenu object of this Module. JMenu has to be set explicitely
	 * as no object is automatically created at module instanciation.
	 * 
	 * @return JMenu object if previously set by calling setModuleMenu
	 *         <b>null</b> otherwise.
	 */
	// ---------------------------------------------------------------------------
	public JMenu getModuleMenu() {
		return this.moduleMenu;
	}

	// ---------------------------------------------------------------------------
	/**
	 * Sets this modules' JMenu object.
	 * 
	 * @param p_ModuleMenu
	 *            specifies the JMenu object to set this modules' ModuleMenu to.
	 */
	// ---------------------------------------------------------------------------
	public void setModuleMenu(JMenu p_ModuleMenu) {
		this.moduleMenu = p_ModuleMenu;
	}

	// ---------------------------------------------------------------------------
	/**
	 * Adds the specified menu item to this modules menu if existing
	 * 
	 * @param p_MenuItem
	 *            specifies the menu item to add to module menu
	 */
	// ---------------------------------------------------------------------------
	public void addMenuItem(JMenuItem p_MenuItem) {
		if ((this.moduleMenu != null) && (p_MenuItem != null)) {
			this.moduleMenu.add(p_MenuItem);
		}
	}

	public void addMenuSeparator(JSeparator p_Seppl) {
		if ((this.moduleMenu != null) && (p_Seppl != null)) {
			this.moduleMenu.add(p_Seppl);
		}
	}

	// ---------------------------------------------------------------------------
	/**
	 * will be called after the model has been created 
	 * and defines, if the module button is shown
	 */
	// ---------------------------------------------------------------------------
	public boolean isShown () {
		return true;
	}
	
	// ---------------------------------------------------------------------------
	/**
	 * will be fired after all modules have been created
	 */
	// ---------------------------------------------------------------------------
	protected void initModule() {
	}

	// ---------------------------------------------------------------------------
	/**
	 * will be fired before the module tab becomes visible
	 */
	// ---------------------------------------------------------------------------
	protected void preparetoShowup() {
	}

	// ---------------------------------------------------------------------------
	/**
	 * will be fired before the module tab becomes invisible
	 */
	// ---------------------------------------------------------------------------
	protected void preparetoHide() {
	}

	// ---------------------------------------------------------------------------
	/**
	 * will be fired before after the module tab became visible
	 */
	// ---------------------------------------------------------------------------
	protected void afterShowup() {
	}

	// ---------------------------------------------------------------------------
	/**
	 * Adds the specified GECAMedAction to this modules' moduleActions vector.
	 * 
	 * @param p_Action
	 *            specifies the GECAMedAction to be added.
	 */
	// ---------------------------------------------------------------------------
	public void addGECAMedAction(GECAMedAction p_Action) {
		if (p_Action != null) {
			moduleActions.add(p_Action);
		}
	}

	// ---------------------------------------------------------------------------
	// ***************************************************************************
	// * Icon Resource Related Methods *
	// ***************************************************************************
	// ---------------------------------------------------------------------------

	// ---------------------------------------------------------------------------
	/**
	 * returns the ImageIcon Resource specified by p_IconName.
	 * 
	 * @param p_IconName
	 *            specifies the name of the icon to get from application
	 *            resources.
	 * @return the ImageIcon specified by p_IconName, or <CODE>null</CODE> if
	 *         specified does not exist.
	 */
	// ---------------------------------------------------------------------------
	public ImageIcon getModuleIcon(String p_IconName) {
		String l_IconPath;
		URL l_Location;

		l_IconPath = "resources/" + p_IconName;
		l_Location = this.getClass().getResource(l_IconPath);

		if (l_Location != null)
			return new ImageIcon(l_Location);
		else
			return new ImageIcon(l_IconPath);
	}

	// ---------------------------------------------------------------------------

	public static ImageIcon getIcon(String p_IconName) {
	    return IconFetcher.getIcon(GECAMedModule.class, p_IconName);
	}

	// ---------------------------------------------------------------------------

	public static ImageIcon getScaledIcon(String p_IconName, int size) {
	    return IconFetcher.getScaledIcon(GECAMedModule.class, p_IconName, size);
	}

	// ---------------------------------------------------------------------------

	public static ImageIcon getMiniIcon(String p_IconName) {
	    return IconFetcher.getMiniIcon(GECAMedModule.class, p_IconName);
	}

	// ---------------------------------------------------------------------------

	public static ImageIcon getSmallIcon(String p_IconName) {
	    return IconFetcher.getSmallIcon(GECAMedModule.class, p_IconName);
	}

	// ---------------------------------------------------------------------------

	public static ImageIcon getMediumIcon(String p_IconName) {
	    return IconFetcher.getMediumIcon(GECAMedModule.class, p_IconName);
	}

	// ---------------------------------------------------------------------------

	public static ImageIcon getBigIcon(String p_IconName) {
	    return IconFetcher.getBigIcon(GECAMedModule.class, p_IconName);
	}

	// ---------------------------------------------------------------------------
	// ***************************************************************************
	// * Current Patient Related Methods *
	// ***************************************************************************
	// ---------------------------------------------------------------------------
	/**
	 * returns the currently active patient
	 * 
	 * @return currently active patient
	 */
	// ---------------------------------------------------------------------------
	public static Patient getCurrentPatient() {
		return currentPatient;
	}

	/**
	 * @param patient
	 */
	public static synchronized void setCurrentPatient(Patient patient) {
		setCurrentPatient(patient, false);
	}

	/**
	 * @param patient
	 * @param forceReload
	 */
	public static synchronized void setCurrentPatient(Patient patient,
			boolean forceReload) {
		logger.info(MainFrame.createLogSubSectionString("setCurrentPatient " + patient));
		if (!forceReload && currentPatient != null
				&& currentPatient.equals(patient)) {
			logger.info("old Patient == new Patient......");
			logger.info("no change -------------------------------------");
			return;
		}
		MainFrame.getInstance().setWaitCursor(true);
		long start = System.currentTimeMillis();
		currentPatient = patient;
		for (Iterator<PatientListener> iter = patientListeners.iterator(); iter.hasNext();) {
			PatientListener module = (PatientListener) iter.next();
			module.patientChanged(patient);
			logger.info("PatientChanged in "
					+ module.getClass().getSimpleName() + " took: "
					+ (System.currentTimeMillis() - start) + "ms");
		}
		logger.info(Translatrix.getTranslationString("pm.shownPatientChanged")
				+ ": " + patient + " took: "
				+ (System.currentTimeMillis() - start) + "ms");
		MainFrame.getInstance().setWaitCursor(false);
		logger.info(MainFrame.createLogSubSectionString("setCurrentPatient DONE " + patient));
	}

	public static void addPatientListener(PatientListener module) {
		patientListeners.add(module);
	}

	public static void removePatientListener(PatientListener module) {
		patientListeners.remove(module);
	}

	public boolean canDisplayPatient() {
		return canDisplayPatient;
	}

	public void setCanDisplayPatient(boolean canDisplayPatient) {
		this.canDisplayPatient = canDisplayPatient;
	}

	// ---------------------------------------------------------------------------
	// ***************************************************************************
	// * Current Physician Related Methods *
	// ***************************************************************************
	// ---------------------------------------------------------------------------
	/**
	 * returns the currently active physician
	 * 
	 * @return currently active physician
	 */
	// ---------------------------------------------------------------------------
	public static Physician getCurrentPhysician() {
		return MainFrame.getCurrentPhysician();
	}

	// ---------------------------------------------------------------------------
	// ***************************************************************************
	// * Current User Related Methods *
	// ***************************************************************************
	// ---------------------------------------------------------------------------
	/**
	 * returns the currently active physician
	 * 
	 * @return currently active physician
	 */
	// ---------------------------------------------------------------------------
	public static GecamedUser getCurrentUser() {
		return MainFrame.getCurrentUser();
	}

	// ---------------------------------------------------------------------------
	// ***************************************************************************
	// * User Privilege Related Methods *
	// ***************************************************************************
	// ---------------------------------------------------------------------------

	private static LoginInterface getLoginInterface() {
		/* ================================================== */
		if (loginInterface != null)
			return loginInterface;
		loginInterface = (LoginInterface) ManagerFactory.getRemote(LoginBean.class);
		return loginInterface;
		/* ================================================== */
	}

	// ---------------------------------------------------------------------------

	protected static void addModulePermissions(String p_ModuleName) {
		/* ================================================== */
		LoginInterface l_LoginInterface = null;
		List<Permission> l_Permissions;
		Permission l_Permission;
		int l_Index;
		/* ------------------------------------------------------- */
		l_LoginInterface = GECAMedModule.getLoginInterface();
		/* ------------------------------------------------------- */
		logger.info("adding permissions for: " + p_ModuleName);
		/* ------------------------------------------------------- */
		if (l_LoginInterface != null) {
			/* ------------------------------------------------------- */
			try {
				/* ------------------------------------------------------- */
				l_Permissions = l_LoginInterface.getModulePermissions(p_ModuleName);
				if (l_Permissions != null) {
					/* ------------------------------------------------------- */
					// l_NameSplitter = Pattern.compile ("^" + p_ModuleName + "\\.(.*?)");
					/* ------------------------------------------------------- */
					for (l_Index = 0; l_Index < l_Permissions.size(); l_Index++) {
						/* ------------------------------------------------------- */
						l_Permission = l_Permissions.get(l_Index);
						permissionsHash.put(l_Permission.getName(), l_Permission.getId());
						permissions.add(l_Permission);
						/* ------------------------------------------------------- */
					}
					/* ------------------------------------------------------- */
				}
				if (l_Permissions != null)
					logger.info("added " + l_Permissions.size() + " permissings, " + permissionsHash.size() + " total");
				else
					logger.info("no permissions added");
				/* ------------------------------------------------------- */
			} catch (Exception p_Exception) {
				logger.warn(p_Exception.getLocalizedMessage());
			}
		}
		/* ================================================== */
	}

	// ---------------------------------------------------------------------------

	protected static void addUserPermissions (String p_ModuleName) 
		{
		LoginInterface 			l_LoginInterface = null;
		Collection<String> 		l_Permissions = null;
		Integer					l_UserId;
		
		l_LoginInterface = GECAMedModule.getLoginInterface();
		logger.info("adding user permissions for: " + p_ModuleName);
		if (l_LoginInterface != null)
			{
			try	{
				l_UserId = l_LoginInterface.getCurrentUserID();
				l_Permissions = l_LoginInterface.getModulePermissions (p_ModuleName, l_UserId);
				userPermissions.addAll (l_Permissions);
				}
			catch (Exception p_Exception)
				{
				logger.warn(p_Exception.getLocalizedMessage());
				}
			
			if (l_Permissions != null)
				 logger.info("added " + l_Permissions.size() + " user permissions, " + userPermissions.size() + " in total");
			else logger.info("no user permissions added");
			}
		}
		
	
	protected static void addModuleRoles(String moduleName) {
		/* ================================================== */
		try {
			/* --------------------------------------------- */
			LoginInterface loginBean = getLoginInterface();
			/* ------------------------------------------------------- */
			logger.info("adding roles for: " + moduleName);
			/* ------------------------------------------------------- */
			if (loginBean != null) {
				/* ------------------------------------------------------- */
				List<Role> moduleRoles = loginBean.getModuleRoles(moduleName);
				if (moduleRoles == null) {
					logger.info("no roles added for module " + moduleName);
					return;
				}
				/* ------------------------------------------------------- */
				for (Role role : moduleRoles) {
					/* ------------------------------------------------------- */
					logger.info("adding role " + role.getName());
					roles.add(role);
					/* ------------------------------------------------------- */
				}
				/* ------------------------------------------------------- */
			} else {
				logger.warn("Unable to get server connection. No roles were added!");
			}
			/* --------------------------------------------- */
		} catch (Exception e) {
			/* --------------------------------------------- */
			logger.warn("Error while talking to server.");
			e.printStackTrace();
			/* --------------------------------------------- */
		}
		/* ================================================== */
	}
	
	
	// ---------------------------------------------------------------------------

	private static Integer getModulePermissionId(String p_ModuleName, String p_Permission) {
		/* ================================================== */
		String l_PermissionName;
		Integer l_PermissionId;
		/* ------------------------------------------------------- */
		if (p_ModuleName != null)
			l_PermissionName = p_ModuleName + "." + p_Permission;
		else
			l_PermissionName = p_Permission;
		/* ------------------------------------------------------- */
		if (permissionsHash.containsKey(l_PermissionName))
			l_PermissionId = permissionsHash.get(l_PermissionName);
		else
			l_PermissionId = Integer.valueOf(-1);

		return l_PermissionId;
		/* ================================================== */
	}

	/**
	 * @return
	 */
	public static List<Permission> getAllPermissions() {
		/* ================================================== */
		
		Collections.sort(permissions);
		
		return permissions;
		/* ================================================== */
	}
	
	
	/**
	 * Returns all roles that are available thorugh the activated modules.
	 * @return
	 */
	public static List<Role> getAllRoles() {
		/* ================================================== */
		Collections.sort(roles);
		return roles;
		/* ================================================== */
	}
	
	// ---------------------------------------------------------------------------

	public static boolean userHasPermission(GecamedUser p_User,
			String p_ModuleName, String p_Permission) {
		LoginInterface l_LoginInterface;
		Integer l_PermissionId;
		boolean l_PermissionGranted = false;

		l_LoginInterface = GECAMedModule.getLoginInterface();

		if (l_LoginInterface != null) {
			l_PermissionId = getModulePermissionId(p_ModuleName, p_Permission);
			if (l_PermissionId.intValue() >= 0) {
				try {
					l_PermissionGranted = l_LoginInterface.userHasPermission(
							p_User, l_PermissionId);
				} catch (Exception p_Exception) {
					logger.warn(p_Exception.getLocalizedMessage());
				}
			}
		}

		return l_PermissionGranted;
	}
	
	
	
	// ---------------------------------------------------------------------------

	/**
	 * @param p_Permission
	 * @return
	 */
	public static boolean userHasPermission(String p_Permission) 
		{
		/* ====================================================== */
		return userHasPermission(null, p_Permission);
		/* ====================================================== */
		}

//	public static boolean userHasPermission(String p_ModuleName,
//			String p_Permission) {
//		LoginInterface l_LoginInterface;
//		Integer l_PermissionId;
//		boolean l_PermissionGranted = false;
//
//		l_LoginInterface = GECAMedModule.getLoginInterface();
//
//		if (l_LoginInterface != null) {
//			l_PermissionId = getModulePermissionId(p_ModuleName, p_Permission);
//			if (l_PermissionId.intValue() >= 0) {
//				try {
//					l_PermissionGranted = l_LoginInterface
//							.userHasPermission(l_PermissionId);
//				} catch (Exception p_Exception) {
//					logger.warn(p_Exception.getLocalizedMessage());
//				}
//			}
//		}
//
//		return l_PermissionGranted;
//	}

	public static boolean userHasPermission(String p_ModuleName, String p_Permission)
		{
		String  l_PermissionName;
		boolean	l_Granted = false;
		
		if (p_ModuleName != null)
			 l_PermissionName = p_ModuleName + "." + p_Permission;
		else l_PermissionName = p_Permission;
		
		l_Granted = userPermissions.contains (l_PermissionName);
		
		return l_Granted;	
		}
	
	// ---------------------------------------------------------------------------

	public static boolean userHasRole(GecamedUser p_User, String p_ModuleName,
			String p_Role) {
		LoginInterface l_LoginInterface;
		String l_Role;
		boolean l_HasRole = false;

		l_LoginInterface = GECAMedModule.getLoginInterface();

		if (l_LoginInterface != null) {
			try {
				if ((p_ModuleName != null) && (p_ModuleName.length() > 0))
					l_Role = p_ModuleName + "." + p_Role;
				else
					l_Role = p_Role;

				l_HasRole = l_LoginInterface.userHasRole(p_User, l_Role);
			} catch (Exception p_Exception) {
				logger.warn(p_Exception.getLocalizedMessage());
			}
		}

		return l_HasRole;
	}

	// ---------------------------------------------------------------------------

	public static boolean userHasRole(String p_ModuleName, String p_Role) {
		LoginInterface l_LoginInterface;
		String l_Role;
		boolean l_HasRole = false;

		l_LoginInterface = GECAMedModule.getLoginInterface();

		if (l_LoginInterface != null) {
			try {
				if ((p_ModuleName != null) && (p_ModuleName.length() > 0))
					l_Role = p_ModuleName + "." + p_Role;
				else
					l_Role = p_Role;

				l_HasRole = l_LoginInterface.userHasRole(l_Role);
			} catch (Exception p_Exception) {
				logger.warn(p_Exception.getLocalizedMessage());
			}
		}

		return l_HasRole;
	}

	// ---------------------------------------------------------------------------
	/**
	 * Method is part of the Relocalizable interface. The method does everything
	 * required to reflect changes of active Locale
	 */
	// ---------------------------------------------------------------------------
	public void relocalize() {
		Method l_RelocalizeMethod;
		GECAMedAction l_GECAMedAction;
		int l_ActionIndex;

		// Make sure JTable re-creates columns using re-localized headers

		if (titlePanel != null)
			titlePanel.setTopic(Translatrix
					.getTranslationString(this.moduleName));
		if (moduleButton != null) {
			if (iconSize >= 32)
				moduleButton.setText(Translatrix
						.getTranslationString(this.moduleName));
			moduleButton.setToolTipText(Translatrix
					.getTranslationString(this.moduleName));
		}
		// If content panel implements Relocalizable interface, then call
		// call relocalize method now.

		if (contentPanel != null) {
			try {
				l_RelocalizeMethod = contentPanel.getClass().getMethod(
						"relocalize");

				if (l_RelocalizeMethod != null) {
					l_RelocalizeMethod.invoke(contentPanel);
				}
			} catch (NoSuchMethodException p_Exception) {
				// No relocalize method in content panel, do nothing!
			} catch (IllegalArgumentException p_Exception) {
			} catch (IllegalAccessException p_Exception) {
			} catch (InvocationTargetException p_Exception) {
			}
		}

		// Call Relocalize method an all module actions

		for (l_ActionIndex = 0; l_ActionIndex < moduleActions.size(); l_ActionIndex++) {
			l_GECAMedAction = moduleActions.elementAt(l_ActionIndex);
			l_GECAMedAction.relocalize();
		}
	}

	/**
	 * @param settingsPlugin
	 *            the settings plugin for this module (shown in the settings
	 *            dialog)
	 */
	public void addSettingsPlugin(SettingsPlugin settingsPlugin) {
		// System.out.println("ADD Settings Plugin: " +
		// settingsPlugin.getName());
		this.settingsPlugins.add(settingsPlugin);
		mainFrame.settingsPanel.addPlugin(settingsPlugin);
		mainFrame.settingsPanel.reflectSettings();
		// System.out.println("DONE " + settingsPlugin.getName());
		// System.out.flush();
	}

	/**
	 * @param settingsPlugin
	 *            the settings plugin for this module (shown in the settings
	 *            dialog)
	 */
	public void addAdminSettingsPlugin(SettingsPlugin settingsPlugin) {
		// System.out.println("ADD Admin Settings Plugin: " +
		// settingsPlugin.getName());
		this.adminSettingsPlugins.add(settingsPlugin);
		mainFrame.adminSettingsPanel.addPlugin(settingsPlugin);
		mainFrame.adminSettingsPanel.reflectSettings();
		// System.out.println("DONE " + settingsPlugin.getName());
		// System.out.flush();
	}

	/**
	 * @return the current selected Module
	 */
	public static GECAMedModule getCurrentModule() {
		return currentModule;
	}
	
	/**
	 * Set the current GECAMed module
	 * @param gecamedModule
	 */
	public static void setCurrentModule(GECAMedModule gecamedModule)
	{
		currentModule = gecamedModule;
	}

	/**
	 * @return the current selected Module's name
	 */
	public static String getCurrentModuleName() {
		try {
			return currentModule.getName();
		} catch (Exception e) {
		}
		return null;
	}

	/**
	 * registers a HotKey for an action in this Module
	 * 
	 * @param key
	 *            the keycode
	 * @param action
	 *            the action to register for the keycode
	 * @return true if success, false if keycode allready bound
	 */
	public boolean registerHotKey(String key, GECAMedAction action) {
		if (key == null || key.equals("")) 
			return false;
					
		if (this.hotKeys.containsKey(key)) {
			logger.warn("Hotkey '" + key
					+ "' is allready registered for action: "
					+ ((Action) hotKeys.get(key)).getValue(Action.NAME));
			return false;
		}
		this.hotKeys.put(key, action);
		logger.info("Hotkey '" + key
				+ "' registered for action: "
				+ ((Action) hotKeys.get(key)).getValue(Action.NAME));
		return true;
	}

	/**
	 * unregisters an hotkey for this module
	 * 
	 * @param key
	 *            the keycode
	 * @throws Exception
	 */
	public void unregisterHotKey(String key) throws Exception {
		this.hotKeys.remove(key);
	}

	/**
	 * returns the action mapped to the given keycode
	 * 
	 * @param key
	 *            the keycode
	 * @return the Action
	 * @throws Exception
	 */
	public Action getActionForHotKey(String key) throws Exception {
		return this.hotKeys.get(key);
	}

	/**
	 * lists the hotkeys with the mapped actions for this module as HTML text
	 * 
	 * @return
	 */
	public String listHotKeys() {
		StringBuffer sb = new StringBuffer();
		if (moduleActions != null && moduleActions.size() > 0) {
			sb.append("<tr><td><b>"
					+ Translatrix.getTranslationString(this.moduleName)
					+ ":</b></td></tr>");
			for (Iterator<GECAMedAction> iter = moduleActions.iterator(); iter.hasNext();) {
				GECAMedAction element = (GECAMedAction) iter.next();
				sb.append("<tr><td>&nbsp;&nbsp;&nbsp;"
						+ element.getTranslatedName() + "</td>"
						+ "<td  align=\"center\">" + element.getShortcutName()
						+ "</td>" + "<td  align=\"center\">"
						+ element.getHotKeyName() + "</td></tr>");
			}
		}

		return sb.toString();
	}

	/**
	 * @return Returns the moduleActions.
	 */
	public Vector<GECAMedAction> getModuleActions() {
		return moduleActions;
	}
	
	
	/**
	 * Override this method to specify, so that GECAMed can 
	 * check, whether there are Unsaved changes, before closing.
	 */
	public boolean isModified ()
	{
		return false;
	}
	
	
	public String getNameForPrinting ()
	{
		return Translatrix.getTranslationString("modulenames."+getName());
	}

	// ***************************************************************************
	// * End of Class *
	// ***************************************************************************
}
