/*******************************************************************************
 * 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
 *******************************************************************************/
/*
 * Author: Johannes Hermen Tudor/Santec
 * Mail: johannes.hermen@tudor.lu
 * Created: Jan 17, 2005
 *
 */
package lu.tudor.santec.gecamed.core.gui;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import lu.tudor.santec.gecamed.address.ejb.entity.beans.Country;
import lu.tudor.santec.gecamed.address.gui.addressmanagement.AddressImportPanel;
import lu.tudor.santec.gecamed.core.gui.listener.PhysicianListenerRegister;
import lu.tudor.santec.gecamed.core.gui.updates.IGECAMedUpdate;
import lu.tudor.santec.gecamed.core.gui.updates.UpdatePrescription1_0_9;
import lu.tudor.santec.gecamed.core.gui.utils.DemoEmailDialog;
import lu.tudor.santec.gecamed.core.gui.utils.GECAMedTextMessageReciever;
import lu.tudor.santec.gecamed.core.gui.utils.UrlOpener;
import lu.tudor.santec.gecamed.core.gui.utils.WindowToolbox;
import lu.tudor.santec.gecamed.core.gui.widgets.ErrorDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
import lu.tudor.santec.gecamed.core.gui.widgets.MenuBar;
import lu.tudor.santec.gecamed.core.gui.widgets.PasswordAskDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.StatusBar;
import lu.tudor.santec.gecamed.core.gui.widgets.templates.TemplateSettings;
import lu.tudor.santec.gecamed.core.utils.GECAMedUtils;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.esante.gui.tab.ESanteTab;
import lu.tudor.santec.gecamed.esante.gui.utils.ESanteGuiUtils;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Office;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.OfficeAddress;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Site;
import lu.tudor.santec.gecamed.office.ejb.session.beans.OfficeManagerBean;
import lu.tudor.santec.gecamed.office.ejb.session.interfaces.OfficeManagerInterface;
import lu.tudor.santec.gecamed.office.gui.officemanagement.OfficeManagementPanel;
import lu.tudor.santec.gecamed.office.gui.physicianmanagement.PhysicianManagementPanel;
import lu.tudor.santec.gecamed.patient.gui.PatientListModule;
import lu.tudor.santec.gecamed.patient.gui.PatientManagerModule;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedInfo;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.Role;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface;
import lu.tudor.santec.gecamed.usermanagement.gui.AdminModule;
import lu.tudor.santec.gecamed.usermanagement.gui.settings.GECAMedSettingsPanel;
import lu.tudor.santec.gecamed.usermanagement.gui.settings.GlobalSettingsPanel;
import lu.tudor.santec.gecamed.usermanagement.gui.settings.UserSettingsPlugin;
import lu.tudor.santec.gecamed.usermanagement.gui.userlist.UserManagementPanel;
import lu.tudor.santec.i18n.Relocalizable;
import lu.tudor.santec.i18n.Translatrix;

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

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.l2fprod.common.swing.JButtonBar;

/**
 * This Class is the Main Gecam Window.
 * it assembles all the GUI and connects to the Applicationserver.
 * it keeps instances of all SessionBeans needed for the App.
 *
 * @author Johannes Hermen johannes.hermen
 */
public class MainFrame extends JFrame implements WindowListener, Relocalizable {

	private static final long serialVersionUID = 1L;

	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(MainFrame.class.getName());
	
	/**
	 * date format for logging the startup time
	 */
	private static NumberFormat timeFormat = new DecimalFormat("0.00");

	/**
	 * action command for close button
	 */
	public static final String CLOSE = "close";

	/**
	 * action command for close button
	 */
	public static final String LOCK = "lock";
	
//	public static final int SHORTCUT_KEY	= (getOS() == 0 ? InputEvent.META_DOWN_MASK : InputEvent.CTRL_DOWN_MASK);
	public static final int SHORTCUT_KEY	= Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
	
	
	private static Map<Object, Thread> shutdownHooks = new HashMap<Object, Thread>(6);
	
	private static JLabel glassPaneLabel = new JLabel();
	

	private JPanel lockPanel = new JPanel();

	private Component glassPane;
	
	private List<String>	m_ErrorModules;


	public static final Color COLOR_PANEL_NOTACTIVE = new JLabel()
			.getBackground();

	/**
	 * static reference to itself
	 * can be referenced by calling MainFrame.getInstance();
	 */
	public static MainFrame mainFrame;
	
	private static Physician currentPhysician;

	private static Office currentOffice;
	
	private static JFileChooser fileChooser;

	/**
	 * the loginScreen that manages the access to JBoss
	 */
	public static LoginScreen loginScreen;

	/**
	 * menuBar of GECAMed
	 */
	private MenuBar menuBar;

	/**
	 * statusbar of GECAMed
	 */
	public StatusBar statusBar;

	/**
	 * the user that is currently logged in.
	 */
	public GecamedUser currentUser;

	// layout stuff
	private CardLayout cardLayout;

	private JPanel content;

	private JButtonBar moduleButtonBar;

	public LoginInterface login;


	private ButtonGroup group;

//	START Settings ===========================================================
	public GECAMedSettingsPanel settingsPanel;

//	public GeneralSettingsPlugin generalSettings;

	public GlobalSettingsPanel adminSettingsPanel;

//	private ModuleManagerPlugin moduleManagerPlugin;

	public UserSettingsPlugin userSettings;

	private TemplateSettings templateSettings;
//	END Settings ===========================================================

	public boolean locked = false;

	private JPanel messageGlassPane;

	private JLabel messageGlassLabel;

	public GECAMedModule currentModule;

	public GECAMedModule lastModule;

	protected boolean EXIT = false;

	private static Site site;

	private static Vector<GECAMedTab> admintabs = new Vector<GECAMedTab>();

	private static String clientId;

	private static long timeStart;

	private static long timeLastStep;

	private static boolean multiSite;
	
	// static fields to read and write in the core.info table
	public static final String INFO_CURRENT_VERSION 	= "CURRENT_VERSION";
	public static final String INFO_LAST_UPDATE 		= "LAST_UPDATE";
	public static final String INFO_PRESCRIPTION_UPDATE = "PRESCRIPTION_UPDATE";
	
	//~ Global Rights ===========================================================
	public static final String PERMISSIONS_CORE = "Core";
	public static final String PERMISSION_CHANGE_PHYSICIAN = "changePhysician";
	
	// global website URLs 
	public static final String HELP_WEBSITE= "http://www.gecamed.lu/";
	
	public static final String HELP_HANDBOOK = "http://gecamed.lu/fr/userguide";
	
	public static final String HELP_FIRSTSTEPS = "http://gecamed.lu/fr/userguide/firststeps";
	
	public static final String HELP_FIRSTSETTINGS = "http://gecamed.lu/fr/userguide/firstsettings";
	
	public static final String HELP_BUGTRACK = "http://gecamed.lu/trac/gecamed/newticket";

	public static final String ABOUT_ESANTE = "http://www.gecamed.lu/fr/userguide/mydsp?&#prise_de_connaissance_de_documents_legaux";

	//~ Constructors ===========================================================
	/**
	 * creates the Main Frame of GECAMed
	 *
	 * @param loginScreen a reference to the LoginScreen
	 */
	public MainFrame(LoginScreen loginScr) {
		/* ================================================== */
		super(System.getProperty("APP_NAME") + " " + System.getProperty("APP_VERSION"));
		
		timeLastStep = timeStart = System.currentTimeMillis();
		
		loginScreen = loginScr;
		this.login = loginScreen.getLogin();
		
		this.setMinimumSize(new Dimension(640,480));
		
		/* ------------------------------------------------------- */
		// set static field for MainFrame.getInstance();
		/* ------------------------------------------------------- */
		mainFrame = this;
		/* ------------------------------------------------------- */
		// generate a client id
		/* ------------------------------------------------------- */
		MainFrame.clientId = generateClientId();
		/* ------------------------------------------------------- */

		/* ------------------------------------------------------- */
		// load global rights and roles
		/* ------------------------------------------------------- */
		GECAMedModule.addModulePermissions(PERMISSIONS_CORE);
		GECAMedModule.addModuleRoles(PERMISSIONS_CORE);
		GECAMedModule.addUserPermissions(PERMISSIONS_CORE);

		/* ------------------------------------------------------- */
		
		/* ------------------------------------------------------- */
		// do some gui tweaks
		/* ------------------------------------------------------- */
		this.setBackground(GECAMedColors.c_GECAMedBackground);
		this.getContentPane().setBackground(GECAMedColors.c_GECAMedBackground);

		// set the icon
		this.setIconImage(GECAMedModule.getIcon(GECAMedIconNames.REDCROSS)
				.getImage());

		this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		this.addWindowListener(this);
		logger.info(createLogSectionString(Translatrix.getTranslationString("core.starting") + "\n" + 
				"GECAMED VERSION: " + System.getProperty("APP_NAME") + " " + System.getProperty("APP_VERSION") + " GIT_REV: " + System.getProperty("APP_GIT_REV") + "\n" + 
				"DATABASE CURRENT_VERSION: " + getCurrentVersion() + " LAST_UPDATE: " + getUpdateVersion()+ "\n"));
		this.getContentPane().setLayout(new BorderLayout());
		
		
		/* ------------------------------------------------------- */
		// initialize the onscreen message panel
		/* ------------------------------------------------------- */
		buildMessageGlassPane();
		/* ------------------------------------------------------- */
		// init the messageReciever
		/* ------------------------------------------------------- */
		new GECAMedTextMessageReciever();
		
		this.lockPanel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				PasswordAskDialog pcd = new PasswordAskDialog();
				if (pcd.showCentered()) {
					MainFrame.this.lockScreen(false);
				}
			}
		});
		
		// ==============================================================================
		// we make the UI a bit nicer
		// adjustments on the look and feel
		//
		// ==============================================================================
		UIManager.put("OptionPane.yesButtonText", Translatrix.getTranslationString("core.yes"));
		UIManager.put("OptionPane.noButtonText", Translatrix.getTranslationString("core.no"));
		UIManager.put("OptionPane.cancelButtonText", Translatrix.getTranslationString("core.cancel"));
		// ===============================================================================

		// ==============================================================================
		// Needed for the JasperReport version 3.7.3, 
		// because a font wasn't found anymore.
		// (another, available font will be taken.
		//
		// ==============================================================================
		// TODO TAKE BACK FONT CHANGE FOR JASPERREPORT
//    	JRProperties.setProperty("net.sf.jasperreports.awt.ignore.missing.font", true);
		// ===============================================================================
    	
		ErrorDialog.setBugURL("http://www.gecamed.lu/trac/gecamed/newticket");
		ErrorDialog.setVersion(System.getProperty("APP_VERSION"));

		// retrieve the current user
		try {
			this.currentUser = login.getCurrentUser();
			getCurrentOffice();
			site = loginScr.site;
			multiSite = loginScr.multisite;
		} catch (Exception e) {
			logger.error("Could not obtain GecamedUser");
			MainFrame.exit(0);
		}
		
		/* ------------------------------------------------------- */
		// start posting keepalives to the server
		/* ------------------------------------------------------- */
		new Thread()
		{
			public void run()
			{
				boolean	connected	= true;
				
				currentUser.setSiteID(getCurrentSiteId());
				while (!EXIT)
				{
					try
					{
						Thread.sleep(40000);
						login.iAmOnline(currentUser);
						
						if (!connected)
							logger.info("Connection to the server REASTABLISHED");
						connected	= true;
					}
					catch (InterruptedException e)
					{
						logger.log(Level.WARN, e.getMessage());
					}
					catch (Exception e)
					{
						if (connected)
						{
							logger.warn("Connection to the server LOST");
							connected	= false;
						}
					}
				}
			}
		}.start();
		
		// ===========================================================================
		// init all needed sessionbean-interfaces
		// ===========================================================================
		this.initialize();
		
		/* ------------------------------------------------------- */
		logger.info(Translatrix.getTranslationString("core.loggedInAsUser")
												+ this.currentUser.getLogin());
		this.setTitle(System.getProperty("APP_NAME") + " " + System.getProperty("APP_VERSION") + " - " +
				this.currentUser.getName() + "@" +
				LoginScreen.JBOSS_URL + " " + GECAMedUtils.getInstallationName());
		
		logger.info(MainFrame.createLogSectionString(Translatrix.getTranslationString("core.assemblingGui")));
		/* ------------------------------------------------------- */
		// build the main Container
		/* ------------------------------------------------------- */
		JComponent mainContainer = buildPanel(JButtonBar.VERTICAL);
		/* ------------------------------------------------------- */
		// add parts to the MainFrame
		/* ------------------------------------------------------- */
		loginScreen.setStatus(Translatrix
			.getTranslationString("core.assemblingGui"), 5);
		
		logger.log(Level.INFO, "adding menu bar to MainFrame");
		this.setJMenuBar(this.menuBar);
		logger.log(Level.INFO, "adding main panel to MainFrame");
		this.getContentPane().add(mainContainer, BorderLayout.CENTER);
		logger.log(Level.INFO, "adding status bar to MainFrame");
		this.getContentPane().add(this.statusBar, BorderLayout.SOUTH);
		/* ------------------------------------------------------- */
		// select the first entry
		/* ------------------------------------------------------- */
		logger.log(Level.INFO, "Selecting first Module");
		try {
			((JToggleButton) this.moduleButtonBar.getComponent(0)).doClick();
		} catch (Exception e) {
		}
		/* ------------------------------------------------------- */
		// show the window
		/* ------------------------------------------------------- */
		logger.log(Level.INFO, createLogSubSectionString("Setting GUI to visible"));

		/* ------------------------------------------------------- */
		// try to restore the window pos/size
		/* ------------------------------------------------------- */
		try {
			Integer x;
			Integer y;
			Integer width;
			Integer height;
			
	    	logger.log(Level.INFO, "Try Restoring Screen location and size ...");
		    
	    	try
	    	{
	    		x	= Integer.parseInt(System.getProperty(LoginScreen.MAIN_LOCATION_X));
	    	}
	    	catch (NumberFormatException e)
	    	{
	    		x	= null;
	    	}

	    	try
	    	{
	    		y	= Integer.parseInt(System.getProperty(LoginScreen.MAIN_LOCATION_Y));
	    	}
	    	catch (NumberFormatException e)
	    	{
	    		y	= null;
	    	}

	    	try
	    	{
	    		width	= Integer.parseInt(System.getProperty(LoginScreen.MAIN_WIDTH));
	    	}
	    	catch (NumberFormatException e)
	    	{
	    		width	= null;
	    	}

	    	try
	    	{
	    		height	= Integer.parseInt(System.getProperty(LoginScreen.MAIN_HEIGHT));
	    	}
	    	catch (NumberFormatException e)
	    	{
	    		height	= null;
	    	}
	    	
			adjustWindow(this, x, y, width, height);
			
			// set the extended state
//			try {
//				int extendedState = Integer.valueOf(System.getProperty(LoginScreen.MAIN_EXTENDED_STATE)).intValue();
//				setExtendedState(JFrame.MAXIMIZED_BOTH);
//			} catch (Exception e) {
//				logger.info("couldn't restore extended state.");
//			}
			
		} catch (Exception e) {
		    e.printStackTrace();
			logger.info("unable to restore window size/pos");
			this.setLocation(0,0);
			this.setSize(640,480);
			this.setExtendedState(JFrame.NORMAL);
		}
//		finally
//		{
//			this.setVisible(true);
//		}
		
		setVisible(true);
		
		logger.info(MainFrame.createLogSectionString(Translatrix.getTranslationString("core.finished")));
		loginScreen.setStatus(Translatrix.getTranslationString("core.finished"), 100);
		/* ------------------------------------------------------- */
		// hide Login Screen
		/* ------------------------------------------------------- */
		logger.log(Level.INFO, "hiding Splashscreen");
		loginScreen.setVisible(false);
		
		/* ------------------------------------------------------- */
		// special demo-version options:
		// show a welcome dialog
		/* ------------------------------------------------------- */
		if (GECAMedUtils.isDemo()) {
			/* ------------------------------------------------------- */
			DemoEmailDialog dm = new DemoEmailDialog();
			dm.showDialog();
			/* ------------------------------------------------------- */
		}
		
		/* ------------------------------------------------------- */
		// Check for update actions
		/* ------------------------------------------------------- */
		updateActions();
		/* ================================================== */
		logger.log(Level.INFO, createLogSectionString("GECAMED STARTUP FINISHED"));
		
		// set the startup to false because startup of GECAMed is finish so
		// the GECAMedLauncher can go ahead and send the parameters
		if(LoginScreen.gecamedLauncher) LoginScreen.gecamedLauncherServer.setGECAMedStartup(false);
		
		if (m_ErrorModules != null && !m_ErrorModules.isEmpty()) showErrorModulesDialog();
	}


	//~ Methods ================================================================
	/**
	 * returns the login-object
	 * @return the login object
	 */
	public LoginInterface getLogin() {
		return login;
	}


	public static String getClientId() {
		/* ================================================== */
		return clientId;
		/* ================================================== */
	}

	/**
	 * generate a client id
	 *
	 * The id is made of the current hashcode of the object,
	 * the current date and the current user name.
	 * Should be unique enough for our purpose here.
	 * @return
	 */
	private String generateClientId() {
		/* ================================================== */
		try {
			StringBuffer idBuff = new StringBuffer();
			idBuff.append(this.hashCode());
			idBuff.append(new Date());
			idBuff.append(loginScreen.getLogin().getCurrentUser().getName());
			
			return idBuff.toString();			
		} catch (Exception e) {
			logger.error("Error generating Client ID", e);
		}
		return null;
		/* ================================================== */
	}
	/**
	 * sets the Mousecursor of the MainFrame to a WaitCursor and Back
	 *
	 * @param on true=waitcursor false=normalcursor
	 */
	public void setWaitCursor(boolean on) {
		if (on) {
			this.setGlassPane(glassPaneLabel);
			this.getGlassPane().setVisible(true);
			this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		} else {
			this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			this.getGlassPane().setVisible(false);
		}
	}


	/**
	 * Show OSD message
	 *
	 * @param text
	 * @param time
	 */
	public void showMessage(String text) {
		this.showMessage(null, text, (Integer)MainFrame.getInstance().userSettings.getValue(UserSettingsPlugin.OSD_TIME));
	}

	public void showMessage(String text, int time) {
		this.showMessage(null, text, time);
	}

	public void showMessage(JDialog owner, String text) {
		this.showMessage(owner, text, (Integer)MainFrame.getInstance().userSettings.getValue(UserSettingsPlugin.OSD_TIME));
	}

	public void showMessage(JDialog owner, String text, final int time)
	{
		if (!(Boolean)MainFrame.getInstance().userSettings.getValue(UserSettingsPlugin.OSD_ENABLED))
    		return;
		
		messageGlassLabel.setText(text);
		
		if (owner != null)
			owner.setGlassPane(messageGlassPane);
		else
			this.setGlassPane(messageGlassPane);
		
		new Thread() {
			public void run() 
			{
				try 
				{
					getGlassPane().setVisible(true);
					Thread.sleep(time);
				}
				catch (InterruptedException e) 
				{
					logger.log(Level.WARN, e.getMessage());
				}
				finally
				{
					getGlassPane().setVisible(false);
				}
			}
		}.start();
	}
	
	
	/**
	 * Locks the screen and shows the text until its unlocked
	 * @param text
	 */
	public void showLockMessage(String text) {
		/* ================================================== */
		lockScreen(true);
		
		if (! (Boolean)MainFrame.getInstance().userSettings.getValue(UserSettingsPlugin.OSD_ENABLED))
    		return ;
		
		this.setGlassPane(messageGlassPane);
		
		messageGlassLabel.setText(text);
		messageGlassPane.setVisible(true);
		/* ================================================== */
	}
	

	/**
	 * creates an Action to show the tabs of the MainPanel
	 * @param text Text to be shown on the Button
	 * @param icon Icon to be shown on the Button
	 * @param action the name of the Tab to be shown
	 * @return the Action
	 */
	public AbstractAction createTabAction(String text, Icon icon, String action) {
		class TabAction extends AbstractAction {
			private static final long serialVersionUID = 1L;

			public TabAction(String text, Icon icon, String action) {
				super(text, icon);
				putValue(ACTION_COMMAND_KEY, action);
			}

			public void actionPerformed(ActionEvent e) {
				if (e.getActionCommand().equals(MainFrame.CLOSE)) {
					reallyClose();
				} else if (e.getActionCommand().equals(MainFrame.LOCK)) {
					lockScreen(true);
				} else {
					cardLayout.show(content, e.getActionCommand());
				}
			}
		}
		return new TabAction(text, icon, action);
	}

	/**
	 * locks the screen
	 * @param on
	 */
	private void lockScreen(final boolean on) {
		/* ================================================== */
		lockScreen(on, 255);
		/* ================================================== */
	}
	
	
	/**
	 * Lock the main screen of GECAMed
	 * @param on
	 */
	private void lockScreen(final boolean on, final int end) {
		/* ================================================== */
		final int start = 0, step = 10;
		new Thread() {
			public void run() {
				if (on) {
					MainFrame.this.setGlassPane(lockPanel);
					MainFrame.this.getGlassPane().setVisible(true);
					lockPanel.setOpaque(true);
					for (int i = start; i <= end; i += step) {
						lockPanel.setBackground(new Color(0, 0, 0, i));
						MainFrame.this.getGlassPane().repaint();
						try {
							Thread.sleep(20);
						} catch (InterruptedException e) {
						}
					}
					locked = true;
				} else {
					locked = false;
					MainFrame.this.setGlassPane(glassPane);
				}
				MainFrame.this.getGlassPane().setVisible(on);
			}
		}.start();
		/* ================================================== */
	}

	/**
	 * shows the Dialog centered on the Screen.
	 */
	public void showCentered() {
		/* ================================================== */
		this.setSize(800, 600);
		Dimension f = this.getSize();
		Point d = GraphicsEnvironment.getLocalGraphicsEnvironment()
				.getCenterPoint();
		this.setLocation(d.x - (f.width / 2), d.y - (f.height / 2));

		this.setVisible(true);
		/* ================================================== */
	}




	/**
	 * Loads all registerd modules
	 */
	private void loadModules() {
		/* ================================================== */

		Dimension l_ButtonSize;
		Dimension l_PreferredSize;
		double l_Width;
		double l_Height;
		
		group = new ButtonGroup();
		
		// create Patient Module
		// this.settingsPanel.loadSettings();
		/* ------------------------------------------------------- */
		// load the core and optional enabled modules
		/* ------------------------------------------------------- */
		m_ErrorModules	= ModuleManager.loadModules();
		


		logger.info(createLogSectionString("ModuleManager.loadModules(); DONE" ));
		
		int modCount = 0;
		// add all modules to GECAMed
		ModuleButtonSelectionListener moduleButtonListener = new ModuleButtonSelectionListener();
		for (GECAMedModule modul : ModuleManager.getModules()) {
			// /* ------------------------------------------------------- */
		    	logger.log(Level.INFO, "Adding Module: " + modul.getName() + " to GECAMed GUI");
			content.add(modul, modul.getName());
			JToggleButton button = modul.getModuleButton();
			button.addActionListener(moduleButtonListener);
			
			/* ------------------------------------------------------- */
			moduleButtonBar.add(button);
			group.add(button);

			// =======================================================================
			// Adjust width of module button bar to accomodate widest mpdule
			// =======================================================================
			l_ButtonSize = button.getPreferredSize();
			l_PreferredSize = moduleButtonBar.getPreferredSize();
			l_Width = l_PreferredSize.getWidth();

			if (l_ButtonSize.getWidth() > l_Width) {
				/* ------------------------------------------------------- */
				l_Width = l_ButtonSize.getWidth();
				l_Height = l_PreferredSize.getHeight();

				l_PreferredSize.setSize(l_Width, l_Height);
				moduleButtonBar.setPreferredSize(l_PreferredSize);
				/* ------------------------------------------------------- */
			}

			if (modul.getModuleMenu() != null) {
				this.menuBar.addModuleMenu(modul.getModuleMenu());
//				menuBar.getMenuCount()
				if (modul instanceof PatientManagerModule && ESanteGuiUtils.isESanteModuleActivated()) {
					this.menuBar.addModuleMenu(ESanteTab.getMenu());
				}
			}
			this.menuBar.addWindowEntry(modul.getWindowMenuEntry());
			if (modCount % 3 == 0)
				this.menuBar.addWindowEntry(new JSeparator());
			modCount++;
		}
		/* ------------------------------------------------------- */
		// load the hotkeys of the modules
		/* ------------------------------------------------------- */
		this.settingsPanel.addPlugin(ModuleManager.loadHotkeys());

                        this.settingsPanel.loadSettings();
                //        this.adminSettingsPanel.loadSettings();
		/* ================================================== */
		logger.info(createLogSubSectionString("All Modules ADDED to GECAMed GUI"));
				
	}


	/**
	 * initializes all components and retrieves the interfaces of all SessionBeans
	 */
	private void initialize() {

		Translatrix.addBundle("lu.tudor.santec.settings.resources.WidgetResources");
		this.relocalize();
		
		// we create the settings for the current user
		this.settingsPanel = new GECAMedSettingsPanel(this);
		this.settingsPanel.loadSettings();
		
		// we create the GLOBAL settings
		this.adminSettingsPanel = new GlobalSettingsPanel(this);
		// add plugins
		this.adminSettingsPanel.addPlugin(ModuleManager.moduleManagerPlugin);
		
		// add plugins
//		this.historyElementsPlugin = new HistoryElementsPlugin();
//		this.globalSettingsPanel.addPlugin(this.historyElementsPlugin);

//		this.generalSettings = new GeneralSettingsPlugin();
//		this.adminSettingsPanel.addPlugin(generalSettings);

		this.templateSettings = new TemplateSettings();
		this.adminSettingsPanel.addPlugin(templateSettings);
		this.adminSettingsPanel.loadSettings();


		GECAMedAction editGlobalSettings = new GECAMedAction(null,
				Translatrix.getTranslationString("core.globalSettings"),
				GECAMedModule.getMiniIcon(GECAMedIconNames.SETTINGS), 0,
				true, true, false) {
					private static final long serialVersionUID = 1L;
					public void actionPerformed(ActionEvent p_Event) {
						    MainFrame.this.adminSettingsPanel.setSize(720, MainFrame.this.getHeight()-60);
						    MainFrame.this.adminSettingsPanel.setLocationRelativeTo(MainFrame.this);
						    MainFrame.this.adminSettingsPanel.setVisible(true);
					}
		};
		AdminModule.addAdminAction(editGlobalSettings);

		/* ------------------------------------------------------- */
		// create Status and Menubar
		logger.info(MainFrame.createLogSectionString(Translatrix.getTranslationString("core.creatingMenuBar")));
		loginScreen.setStatus(Translatrix
				.getTranslationString("core.creatingMenuBar"), 5);
		this.menuBar = new MenuBar(this);
		this.statusBar = StatusBar.getInstance();

	}

	// methods to catch window closing action
	public void windowOpened(WindowEvent e) {
	}

	public void windowClosing(WindowEvent e) {
		if (! locked)
			reallyClose();
	}
	public void windowClosed(WindowEvent e) {}
	public void windowIconified(WindowEvent e) {}
	public void windowDeiconified(WindowEvent e) {}
	public void windowActivated(WindowEvent e) {}
	public void windowDeactivated(WindowEvent e) {}

	/**
	 * Opens a dialog to acknowledge program exit
	 */
	private void reallyClose() {
		/* ================================================== */
		final int max = 40;
		final int step = 3;
		String[] args;
		int buttonOption;
		 
		
		Collection<GECAMedModule> gecamedModule = ModuleManager.getModules();
		if (gecamedModule != null)
		{				
			for (GECAMedModule module : gecamedModule)
			{
				if(module.isModified())
				{
					args = new String[] { module.getNameForPrinting() };
					
					buttonOption = GECAMedBaseDialogImpl.showMessageDialog (
							MainFrame.this,
							Translatrix.getTranslationString("core.exitSaveData"),
							Translatrix.getTranslationString("core.exitSaveDataMsg", args),
							GECAMedBaseDialogImpl.YES_NO_BUTTON_MODE,
							GECAMedModule.getBigIcon(GECAMedIconNames.WARNING));
					
					if (buttonOption == GECAMedBaseDialogImpl.NO_OPTION 
							|| buttonOption == GECAMedBaseDialogImpl.CLOSED_OPTION)
						return;
				}
			}
		}
		
		new Thread() {
		    int i = 0;
		    JPanel panel = new JPanel();
			public void run() {
			    	try {
				    SwingUtilities.invokeAndWait(new Runnable() {
				        public void run() {
				            MainFrame.this.setGlassPane(panel);
				    		MainFrame.this.getGlassPane().setVisible(true);
				        }
				    });
				} catch (Exception e1) {
				} 
				panel.setOpaque(true);
				for (i=0; i <= max; i += step) {
				    	try {
					    SwingUtilities.invokeAndWait(new Runnable() {
					        public void run() {
					    	panel.setBackground(new Color(0, 0, 0, i));
					        }
					    });
					} catch (Exception e1) {
					} 
					MainFrame.this.getGlassPane().repaint();
					try {
						Thread.sleep(20);
					} catch (InterruptedException e) {
					}
				}

				if (JOptionPane.showConfirmDialog(MainFrame.this, 
						Translatrix.getTranslationString("core.reallyQuit"), 
						Translatrix.getTranslationString("core.exit"),
						JOptionPane.YES_NO_OPTION,
						JOptionPane.QUESTION_MESSAGE, GECAMedModule
								.getIcon(GECAMedIconNames.HELP)) == JOptionPane.YES_OPTION) {
					try
					{
						try {
							loginScreen.getProperties().setProperty(LoginScreen.MAIN_EXTENDED_STATE, String.valueOf(getExtendedState()));
						} catch (Exception e) {
							logger.info("couldn't save extended state");
						}
						
						logger.info("\r\n" +
								"##############################################\r\n" +
								"#  Exiting GECAMed " + new Date() + "\r\n" +
								"##############################################\r\n");
						logger.info("Program Exit with Status 0 (Successfull)");

						EXIT = true;
						login.iAmOffline(currentUser);
						
						GECAMedLog.system(LoginScreen.LOG_NAME, "LOGOUT", "Session closed for user: " + currentUser.getLogin(), null);
						// wait for log to be written
						for (int i = 0; i < 20; i++) {
							if (GECAMedLog.areAllLogsWritten()) {
								break;
							}
							Thread.sleep(100);							
						}
						
					}
					catch (Throwable e)
					{
						logger.log(Level.ERROR, "Error before closing!", e);
					}
					finally
					{
						exit(0);
					}
				}
				
				for (i = max - 10; i >= 0; i -= step) {
				    try {
					    SwingUtilities.invokeAndWait(new Runnable() {
					        public void run() {
					            panel.setBackground(new Color(0, 0, 0, i));
					            MainFrame.this.getGlassPane().repaint();
					        }
					    });
				    } catch (Exception e1) {
				    } 
					
					try {
						Thread.sleep(20);
					} catch (InterruptedException e) {
					}
				}
				    try {
					    SwingUtilities.invokeAndWait(new Runnable() {
					        public void run() {
					            MainFrame.this.getGlassPane().setVisible(false);
					            MainFrame.this.setGlassPane(glassPane);
					        }
					    });
				    } catch (Exception e1) {
				    } 
			}
		}.start();
		/* ================================================== */	
	}

	/**
	 * static accessor to the MainFrame instance
	 *
	 * @return the current Instance of MainFrame
	 */
	public static MainFrame getInstance() {
		return mainFrame;
	}

	/**
	 * listener that fires preparetoShowup(); on the sleected GECAMedModule
	 * @author Johannes Hermen johannes.hermen(at)tudor.lu
	 */
	public class ModuleButtonSelectionListener implements ActionListener {

		public void actionPerformed(ActionEvent e) {
			/* ------------------------------------------------------- */
			selectModule(e.getActionCommand());
			/* ------------------------------------------------------- */
		}
	}

	/**
	 * Return the current Staff
	 *
	 * @return
	 */
	public static GecamedUser getCurrentUser() {
		return mainFrame.currentUser;
	}

	/**
	 * Return the current StaffID
	 *
	 * @return
	 */
	public static Integer getCurrentUserId() {
		return mainFrame.currentUser.getId();
	}

	//--------------------------------------------------------------------------
	/**
	 * returns the current physician if the current user is a physician.
	 * Otherwise a dialog is shown to select the appropriate physician.
	 *
	 * @return
	 */
	//--------------------------------------------------------------------------
	public static Physician getCurrentPhysician() {
	    return currentPhysician;
	}
	//--------------------------------------------------------------------------
	
	/**
	 * returns the physician object for the id
	 * 
	 * @param id of the pyhsician
	 * @return
	 */
	public static Physician getPhysicianById (Integer id)
	{
		List<Physician> physicians = GECAMedLists.getListReference(Physician.class);
		
		// if there are no physicians, return null
		if (physicians == null || physicians.size() < 1)
			return null;
		for (Physician p : physicians)
		{
			if (p.getId().equals(id))
				return p;
		}
		return null;
	}
	
	

	/**
	 * Sets the current physician.
	 * Should only be called by the combobox of the StatusBar
	 *
	 * @param physician
	 */
	public static void setCurrentPhysician(Physician physician) {
		/* ================================================= */
	        if (! GECAMedModule.userHasPermission(MainFrame.PERMISSIONS_CORE, MainFrame.PERMISSION_CHANGE_PHYSICIAN)) {
	        	if (getCurrentUser().getPhysicians() == null || !getCurrentUser().getPhysicians().contains(physician)) {
	        		logger.warn("User: " + getCurrentUser() + " has no right to change the current physician to " + physician + " -> Not Changing Physician");
	        		return;
	        	}
	        }
		// save the physician
		currentPhysician = physician;
		logger.info("Setting Physician to: " + currentPhysician);
		/* ------------------------------------------------- */
		// notify the listener
		/* --------------------------------------------- */
		for (PhysicianListener l : PhysicianListenerRegister.getAllListeners())
			l.physicianChanged(currentPhysician);
		/* ------------------------------------------------- */
		/* ================================================= */
	}

	/**
	 * Returns the current Office
	 *
	 * @return
	 */
	public static Office getCurrentOffice() {
		/* ================================================== */
		if (currentOffice == null) {
			try {
				OfficeManagerInterface officeManager =
					(OfficeManagerInterface) ManagerFactory.getRemote(OfficeManagerBean.class);
				currentOffice = officeManager.getOffice(Integer.valueOf(1));
				/* ------------------------------------------------------- */
				// set status bar message, that there is no office address
				if (currentOffice == null && MainFrame.getInstance().statusBar != null) {
					/* ------------------------------------------------------- */
					MainFrame.getInstance().statusBar.setWarningText(
							Translatrix.getTranslationString("message.nooffice"), 
							StatusBar.SHOW_TEXT_TIME_INFINITY);
					/* ------------------------------------------------------- */
				}
				/* ------------------------------------------------------- */
			}catch (Exception e) {
				reportServerError(e);
			}
		}
		return currentOffice;
		/* ================================================== */
	}
	
	
	/**
	 * Returns the country of the current office. If the office 
	 * does not have an address et, the default LUXEMBOURG is returned.
	 * 
	 * @return
	 */
	public static String getCurrentOfficeCountry() {
		/* ================================================== */
		String officeCountry = Country.LUXEMBOURG;
		
		Office office = MainFrame.getCurrentOffice();
		if (office != null) {
			/* ------------------------------------------------------- */
			OfficeAddress officeAddress = office.getLatestOfficeAddress();
			if (officeAddress != null)
				officeCountry = officeAddress.getCountry();
			/* ------------------------------------------------------- */
		}
		return officeCountry;
		/* ================================================== */
	}
	
	
	
	/**
	 * Returns the current version of gecamed
	 * 
	 * @return
	 */
	public String getCurrentVersion() {
		/* ================================================== */
		return getInfo(INFO_CURRENT_VERSION);
		/* ================================================== */
	}
	
	/**
	 * Returns the current version of gecamed
	 * 
	 * @return
	 */
	public String getUpdateVersion() {
		/* ================================================== */
		return getInfo(INFO_LAST_UPDATE);
		/* ================================================== */
	}
	
	/**
	 * Reads from core.info
	 * 
	 * @param key
	 * @return
	 */
	public String getInfo(String key) {
		/* ================================================== */
		GecamedInfo conInfo = null;
		try {
			conInfo = login.getInfo(key);
			return conInfo.getValue();
		} catch (Exception e1) {
		}
		return null;
		/* ================================================== */
	}
		
	/**
	 * Adds a new info to the core.info table.
	 * Use updateInfo to update an existing entry
	 * 
	 * @param key
	 * @param value
	 */
	public void setInfo(String key, String value) {
		/* ================================================== */
		GecamedInfo	conInfo = new GecamedInfo();
		conInfo.setDate(new Date());
		conInfo.setKey(key);
		conInfo.setValue(value);
		
		// save
		try {
			/* --------------------------------------------- */
			login.setInfo(conInfo);
			/* --------------------------------------------- */
		} catch (Exception e) {
			/* --------------------------------------------- */
			e.printStackTrace();
			/* --------------------------------------------- */
		}
		/* ================================================== */
	}
	
	/**
	 * Updates an existing info from core.info with new value and date.
	 * Will create a new info entry, if the key is not available in the database
	 * Use  setInfo to create a new info entry in the table
	 * @param key
	 * @param value
	 * 
	 * @see setInfo(String key, String value)
	 */
	public void updateInfo(String key, String value) {
		/* ================================================== */
		GecamedInfo conInfo = null;
		try {
			conInfo = login.getInfo(key);
		} catch (Exception e1) {
		}
		if (conInfo == null)
			conInfo = new GecamedInfo();
		conInfo.setDate(new Date());
		conInfo.setKey(key);
		conInfo.setValue(value);
		
		// save
		try {
			/* --------------------------------------------- */
			login.setInfo(conInfo);
			/* --------------------------------------------- */
		} catch (Exception e) {
			/* --------------------------------------------- */
			e.printStackTrace();
			/* --------------------------------------------- */
		}
		/* ================================================== */
	}
	
	

	/**
	 * Checks if the current user has admin rights
	 *
	 * @return
	 */
	public static boolean isAdmin() {
		/* ================================================== */
		try {
//			return mainFrame.login.userHasRole ("PatientModule.admin");
			return mainFrame.login.userHasRole (Role.ADMIN);
		} catch (Exception e) {
			return false;
		}
		/* ================================================== */
	}


	/**
	 * Method to inform the application in case there are communication
	 * problems with the server
	 *
	 * @param e
	 */
	public static void reportServerError(Exception e) {
		/* ================================================== */
		try
			{
				StatusBar.getInstance().setWarningText(e.getMessage());
				logger.log(Level.WARN, "Server error", e);
				GECAMedLog.error("MainFrame", "", e.getMessage(), e);
				ErrorDialog.showErrorDialog(getInstance(), e.getMessage(), "Problem while talking to the server...", e );				
			} catch (Exception ee)
			{
				e.printStackTrace();
			}
		/* ================================================== */
	}

	public static void showDialogCentered(JDialog dialog) {
		/* ================================================== */
		WindowToolbox.showCentered(mainFrame, dialog);
		/* ================================================== */
	}


	/**
	 * Opens the given module
	 *
	 * @param moduleName
	 */
	public void selectModule(String moduleName) {
		/* ================================================== */
		try {
			if (MainFrame.this.currentModule != null) {
				try {
					MainFrame.this.currentModule.preparetoHide();
				} catch (Exception er) {
					System.out.println(er.getLocalizedMessage());
					er.printStackTrace();
					logger.log(Level.WARN, er.getLocalizedMessage(), er);
				}
			}
			
			GECAMedModule gmModul = ModuleManager.getModule(moduleName);
			MainFrame.this.currentModule = gmModul;
			gmModul.preparetoShowup();
			cardLayout.show(content, gmModul.getName());
			gmModul.afterShowup();
			gmModul.getModuleButton().setSelected(true);
			
			if (! MainFrame.this.currentModule.getClass().equals(PatientListModule.class)) {
				lastModule = MainFrame.this.currentModule;
			}
		
		} catch (Exception e) {
			try {
				PatientManagerModule.getInstance().getModuleButton().doClick();
			} catch (Exception ee) {
			}
			logger.log(Level.WARN, "Failed to activate module " + moduleName, e);
		}
		/* ================================================== */
	}

	/**
	 * returns the current selected module
	 *
	 * @return the current selected module
	 */
	public String getSelectedModule() {
		/* ================================================== */
		return GECAMedModule.getCurrentModuleName();
		/* ================================================== */
	}

	/**
	 * Returns all registered modules
	 *
	 * @return
	 */
	public Collection<GECAMedModule> getModules() {
		/* ================================================== */
		return ModuleManager.getModules();
		/* ================================================== */
	}

	/**
	 *  fires a GECAMedMessage to all registeredGECAMedMessageListener
	 * @param message a GECAMedMessage
	 */
	public static void fireGECAMedMessage(GECAMedMessage message) {
		/* ================================================== */
		logger.info("fireGECAMedMessage: " + message);
		/* --------------------------------------------- */
		for (GECAMedMessageListener l : RegistrationDesk.getAllMessageListener())
			l.handleGECAMedMessage(message);
		/* ================================================== */
	}

	
	
	/**
	 * Actions that must take place durnig first run of gecamed
	 */
	public void firstRunActions() {
		/* ================================================== */
		GecamedInfo conInfo = null;
		try {
			conInfo = login.getInfo(GecamedInfo.FIRST_RUN);
		} catch (Exception e1) {
		}
		if (conInfo == null || "false".equals(conInfo.getValue())) {
			/* ------------------------------------------------------- */
			// block all modules and select admin and enable only
			// user, office and physician tabs
			/* ------------------------------------------------------- */
			ModuleManager.enableAllButThis(AdminModule.MODULE_NAME, true);
			/* ------------------------------------------------------- */
			// disable unwanted tabs in admin module
			/* ------------------------------------------------------- */
			GECAMedModule aModule = ModuleManager.getModule(AdminModule.MODULE_NAME);
			if (aModule != null) {
				/* ------------------------------------------------------- */
				selectModule(AdminModule.MODULE_NAME);
				AdminModule adminModule = AdminModule.getInstance();
				
				adminModule.setAllTabsEnabled(false);
				/* ------------------------------------------------------- */
				adminModule.setTabEnabled(AddressImportPanel.class, 	  true);
				adminModule.setTabEnabled(UserManagementPanel.class, 	  true);
				adminModule.setTabEnabled(OfficeManagementPanel.class, 	  true);
				adminModule.setTabEnabled(PhysicianManagementPanel.class, true);
				/* ------------------------------------------------------- */
			}
			
			/* ------------------------------------------------------- */
			// disable the menu
			/* ------------------------------------------------------- */
			this.menuBar.disabledAllButFile();
			/* ------------------------------------------------------- */
			// save the admin settings once
			/* ------------------------------------------------------- */
			this.adminSettingsPanel.saveSettings();
			/* ------------------------------------------------------- */
			// open firstsettings page
			UrlOpener.openURL(MainFrame.HELP_FIRSTSETTINGS);
		} else {
			/* ------------------------------------------------------- */
			// enable all modules
			/* ------------------------------------------------------- */
			ModuleManager.enableAll(true);
			/* ------------------------------------------------------- */
			GECAMedModule aModule = ModuleManager.getModule(AdminModule.MODULE_NAME);
			if (aModule != null) {
				/* ------------------------------------------------------- */
				AdminModule adminModule = AdminModule.getInstance();
				adminModule.setAllTabsEnabled(true);
				/* ------------------------------------------------------- */
			}
			this.menuBar.setAllEnabled(true);
			/* ------------------------------------------------------- */
		}
		/* ================================================== */
	}
	
	
	
	/**
	 * Actions that must be triggerd after a system update.
	 */
	private void updateActions() {
	    logger.log(Level.INFO, createLogSubSectionString("run update actions"));
		/* ================================================== */
		// check for consultation update
//		checkConsultationUpdate();
	    
//		checkIncidentEntryUpdate();
		// TODO put this in a loop sometimes, when there are more 
		// updates.
		IGECAMedUpdate prescUpdate = new UpdatePrescription1_0_9();
		if (prescUpdate.check()) {
			lockScreen(true);
			showMessage("Updating prescriptions, please wait ....");
			prescUpdate.doUpdate();
			
		}
//		lockScreen(true);
		
		firstRunActions();
		lockScreen(false);
		/* ================================================== */
	}
	
	
	/**
	 * Checks if a special update for the consultation tables must be applied.
	 * it must only be called after the update from the old consultation table to 
	 * the incident_entry table.
	 */
//	@SuppressWarnings("unused")
//	private void checkConsultationUpdate() {
//		/* ================================================== */
//		GecamedInfo conInfo = null;
//		String ConsultationInfoString = "CONSULTATION_UPDATE_1";
//		try {
//			conInfo = login.getInfo(ConsultationInfoString);
//		} catch (Exception e1) {
//		}
//		if (conInfo == null || "false".equals(conInfo.getValue())) {
//			/* ------------------------------------------------------- */
//			// lock the screen and show
//			// the consultation update dialog
//			/* ------------------------------------------------------- */
//			lockScreen(true, 100);
//			ConsultationUpdateDialog cd = new ConsultationUpdateDialog();
//			cd.showDialog();
//			/* ------------------------------------------------------- */
//			// check if all is done
//			if (ConsultationUpdateDialog.STATE_FINISHED == cd.getState()) {
//				lockScreen(false, 100);
//				// write info
//				if (conInfo == null)
//					conInfo = new GecamedInfo();
//				conInfo.setDate(new Date());
//				conInfo.setKey(ConsultationInfoString);
//				conInfo.setValue("true");
//				
//				// save
//				login.setInfo(conInfo);
//			} else {
//				/* ------------------------------------------------------- */
//				// abort the application, because can not assure consistency
//				// up from now
//				logger.error("Canceled consultation update. Aborting ......");
//				MainFrame.exit(1);
//				/* ------------------------------------------------------- */
//			}
//			/* ------------------------------------------------------- */
//		}
//		/* ================================================== */
//	}
	
//	/**
//	 * Checks if a special update for the consultation tables must be applied.
//	 * it must only be called after the update from the old consultation table to 
//	 * the incident_entry table.
//	 */
//	private void checkIncidentEntryUpdate() {
//		/* ================================================== */
//		GecamedInfo conInfo = null;
//		String ConsultationInfoString = "INCIDENT_ENTRY_UPDATE_1";
//		try {
//			conInfo = login.getInfo(ConsultationInfoString);
//		} catch (Exception e1) {
//		}
//		if (conInfo == null || "false".equals(conInfo.getValue())) {
//			/* ------------------------------------------------------- */
//			// lock the screen and show
//			// the consultation update dialog
//			/* ------------------------------------------------------- */
//			lockScreen(true, 100);
//			IncidentEntryUpdateDialog cd = new IncidentEntryUpdateDialog();
//			cd.showDialog();
//			/* ------------------------------------------------------- */
//			// check if all is done
//			if (ConsultationUpdateDialog.STATE_FINISHED == cd.getState()) {
//				lockScreen(false, 100);
//				// write info
//				if (conInfo == null)
//					conInfo = new GecamedInfo();
//				conInfo.setDate(new Date());
//				conInfo.setKey(ConsultationInfoString);
//				conInfo.setValue("true");
//				
//				// save
//				login.setInfo(conInfo);
//			} else {
//				/* ------------------------------------------------------- */
//				// abort the application, because can not assure consistency
//				// up from now
//				logger.error("Canceled incidentEntryUpdate update. Aborting ......");
//				MainFrame.exit(1);
//				/* ------------------------------------------------------- */
//			}
//			/* ------------------------------------------------------- */
//		}
//		/* ================================================== */
//	}
	
	
	
	
	/* ******************************************************************************
	 *  Graphic Section
	 *  
	 * 	all ui component stuff
	 */
	
	/**
	 * creates a Outlook-like ButtonBar to select the main tabs of GeCam
	 *
	 * @param orientation vertical or horizontal
	 * @return a buttonbar
	 */
	private JComponent buildPanel(int orientation) {

		// the glasspane for locking the screen
		this.glassPane = this.getGlassPane();

		// user specific settings
		this.userSettings = new UserSettingsPlugin("user");
		this.settingsPanel.addPlugin(userSettings);

		// create the main TabPane
		JPanel modulesPanel = new JPanel(new BorderLayout());
		modulesPanel.setOpaque(false);
		JPanel buttonBarPanel = new JPanel(new BorderLayout());
		buttonBarPanel.setOpaque(false);
		
		/* ------------------------------------------------------- */
		// testing
		cardLayout = new CardLayout();
		
//		cardLayout = new AnimatingCardLayout(new DashboardAnimation());
		
		content = new JPanel(cardLayout);
		content.setOpaque(false);

		// create the left ButtonBar

		int iconSize = (Integer) userSettings.getValue(UserSettingsPlugin.TOOLBAR_SIZE);

		moduleButtonBar = new JButtonBar(orientation);
		moduleButtonBar.setPreferredSize(new Dimension(iconSize, iconSize * 3));
		moduleButtonBar.setBorder(null);
		
		moduleButtonBar.setBackground(GECAMedUtils.getInstallationColor());
		
		
		buttonBarPanel.add(moduleButtonBar, BorderLayout.CENTER);

		JButtonBar systemButtonBar = new JButtonBar(orientation);
		systemButtonBar.setBorder(null);

		JButton lockButton = new JButton(createTabAction("",GECAMedModule
				.getScaledIcon(GECAMedIconNames.LOCK, iconSize), MainFrame.LOCK));
		if (iconSize >= 32)
			lockButton.setText(Translatrix.getTranslationString("core.lockscreen"));
		lockButton.setToolTipText(Translatrix.getTranslationString("core.lockscreen"));
		systemButtonBar.add(lockButton);

		JButton exitButton = new JButton(createTabAction("",GECAMedModule
				.getScaledIcon(GECAMedIconNames.EXIT, iconSize), MainFrame.CLOSE));
		if (iconSize >= 32)
			exitButton.setText(Translatrix.getTranslationString("core.exit"));
		exitButton.setToolTipText(Translatrix.getTranslationString("core.exit"));
		systemButtonBar.add(exitButton);

		systemButtonBar.setPreferredSize(new Dimension(iconSize, iconSize * 3));
		systemButtonBar.setBackground(GECAMedUtils.getInstallationColor());
		
		buttonBarPanel.add(systemButtonBar, BorderLayout.SOUTH);

		// add the buttonBar
		modulesPanel.add(buttonBarPanel, BorderLayout.WEST);

		// create and add all the Modules
		loadModules();
		
//		new GECAMedHelp(menuBar);
		
		logger.info(createLogSubSectionString("MainFrame.loadModules(); DONE."));
		// --------------------------------------------------------------------------------------------------------------------------

		logger.info("adding module cardpanel to modulepanel");
		modulesPanel.add(content, BorderLayout.CENTER);
		return modulesPanel;
	}
	
	

	/**
	 * Build the nice rounded-corner panel on the glass pane.
	 * It is used for messages to the user
	 */
	private void buildMessageGlassPane() 
	{
		messageGlassPane	= new JPanel(new FormLayout("0px:g,p,0px:g","0px:g,p,0px:g"));
		messageGlassPane.setOpaque(false);
		
		messageGlassLabel	= new JLabel() 
		{
			private static final long serialVersionUID = 1L;
			@Override
			public void paint(Graphics g)
			{
				g.setColor(new Color(0,0,0,100));
				g.fillRoundRect(0,0,this.getSize().width ,this.getSize().height , 30, 30);
				super.paint(g);
			}
		};
		messageGlassLabel.setBorder(BorderFactory.createEmptyBorder(30,30,30,30));
		messageGlassLabel.setForeground(Color.WHITE);
		messageGlassLabel.setMinimumSize(new Dimension(300,300));
		messageGlassLabel.setFont(new Font("arial", Font.BOLD, 30));
		messageGlassLabel.setOpaque(false);
		messageGlassLabel.setHorizontalAlignment(JLabel.CENTER);
		messageGlassLabel.setVerticalAlignment(JLabel.CENTER);
		
		messageGlassPane.add(messageGlassLabel, new CellConstraints(2, 2));
	}
	
	
	

	/* ************************************************************************
	 * 
	 */
	


	
	
	
	
	
	// ********************************************************************
	// Unused methods
	// 
	// ********************************************************************
	
	
//	/**
//	 * @param name
//	 * @return
//	 */
//	public static URL getResource(String name) {
//		try {
//			if (LoginScreen.WEBSTART_CODEBASE != null) {
//				return new URL(LoginScreen.WEBSTART_CODEBASE.toString() + "/" + name);
//			} else {
//				return new File(name).toURL();
//			}
//		} catch (MalformedURLException e) {
//			logger.warn("unable to open resource " + name);
//		}
//		return null;
//	}
	
	
//	public static InputStream getResourceAsStream(String name) {
//	try {
//		return getResource(name).openStream();
//	} catch (IOException e) {
//		logger.warn("unable to open resource as stream " + name);
//		return null;
//	}
//}

//public static File copyResourceToLocal(URL resource) {
//	/* ================================================== */
//	try {
//		URLConnection conn = resource.openConnection();
//		InputStream in = conn.getInputStream();
//		File f = File.createTempFile("gecamed", "");
//		FileOutputStream fout = new FileOutputStream(f);
//		byte[] buf = new byte[1024];
//	    int i = 0;
//	    while((i=in.read(buf))!=-1) {
//	      fout.write(buf, 0, i);
//	    }
//	    in.close();
//	    fout.close();
//	    return f;
//	} catch (IOException e) {
//		logger.warn(e.getLocalizedMessage() + " " + resource);
//	}
//	return null;
//	/* ================================================== */
//}
	
//---------------------------------------------------------------------------

/**
 * Attention, you have to reconfigure this chooser
 * to your needs. It can be modified by another class.
 * 
 * @return
 */
public static JFileChooser getFileChooser ()
	{
	if (fileChooser == null)
		fileChooser = new JFileChooser();
	
	return fileChooser;
	}
	
//---------------------------------------------------------------------------

private void localizeFileSelector ()
    {
    //---Labels ----------------------------------------------------------------
       
    UIManager.put ("FileChooser.lookInLabelText",           
                    Translatrix.getTranslationString ("FileSelector.LookIn"));
    UIManager.put ("FileChooser.saveInLabelText",           
                    Translatrix.getTranslationString ("FileSelector.SaveIn"));
    UIManager.put ("FileChooser.fileNameLabelText",           
                    Translatrix.getTranslationString ("FileSelector.FileName"));
    UIManager.put ("FileChooser.filesOfTypeLabelText",
                    Translatrix.getTranslationString ("FileSelector.FilesOfType"));
     
    //--- Detail Headers -------------------------------------------------------
    
    UIManager.put ("FileChooser.fileNameHeaderText",
                    Translatrix.getTranslationString ("FileSelector.FileNameHeader"));
    UIManager.put ("FileChooser.fileSizeHeaderText",
                    Translatrix.getTranslationString ("FileSelector.FileSizeHeader"));
    UIManager.put ("FileChooser.fileTypeHeaderText",
                    Translatrix.getTranslationString ("FileSelector.FileTypeHeader"));
    UIManager.put ("FileChooser.fileDateHeaderText",
                    Translatrix.getTranslationString ("FileSelector.FileDateHeader"));
    UIManager.put ("FileChooser.fileAttrHeaderText",
                    Translatrix.getTranslationString ("FileSelector.FileAttributesHeader"));

    //--- Buttons --------------------------------------------------------------
    
    UIManager.put ("FileChooser.saveButtonText",
                    Translatrix.getTranslationString ("FileSelector.SaveButton"));
    UIManager.put ("FileChooser.openButtonText",
                    Translatrix.getTranslationString ("FileSelector.OpenButton"));
    UIManager.put ("FileChooser.directoryOpenButtonText",
                    Translatrix.getTranslationString ("FileSelector.DirectoryOpenButton"));
    UIManager.put ("FileChooser.cancelButtonText",
                    Translatrix.getTranslationString ("FileSelector.CancelButton"));
    UIManager.put ("FileChooser.updateButtonText",
                    Translatrix.getTranslationString ("FileSelector.UpdateButton"));
    UIManager.put ("FileChooser.helpButtonText",
                    Translatrix.getTranslationString ("FileSelector.HelpButton"));
    
    //--- Tooltips ------------------------------------------------------------
   
    UIManager.put ("FileChooser.upFolderToolTipText",
                    Translatrix.getTranslationString ("FileSelector.UpFolderTip"));
    UIManager.put ("FileChooser.homeFolderToolTipText",
                    Translatrix.getTranslationString ("FileSelector.HomeFolderTip"));   
    UIManager.put ("FileChooser.newFolderToolTipText",
                    Translatrix.getTranslationString ("FileSelector.NewFolderTip"));
    UIManager.put ("FileChooser.listViewButtonToolTipText",
                    Translatrix.getTranslationString ("FileSelector.ListViewTip"));
    UIManager.put ("FileChooser.detailsViewButtonToolTipText",
                    Translatrix.getTranslationString ("FileSelector.DetailViewTip"));
    UIManager.put ("FileChooser.saveButtonToolTipText",
                    Translatrix.getTranslationString ("FileSelector.SaveButtonTip"));
    UIManager.put ("FileChooser.openButtonToolTipText",
                    Translatrix.getTranslationString ("FileSelector.OpenButtonTip"));
    UIManager.put ("FileChooser.cancelButtonToolTipText",
                    Translatrix.getTranslationString ("FileSelector.CancelButtonTip"));
    UIManager.put ("FileChooser.updateButtonToolTipText",
                    Translatrix.getTranslationString ("FileSelector.UpdateButtonTip"));
    UIManager.put ("FileChooser.helpButtonToolTipText",
                    Translatrix.getTranslationString ("FileSelector.HelpButtonTip"));
    }

//---------------------------------------------------------------------------
		
public void relocalize() 
	{
	UIManager.put("OptionPane.yesButtonText", Translatrix.getTranslationString("core.yes"));
	UIManager.put("OptionPane.noButtonText", Translatrix.getTranslationString("core.no"));
		
	this.localizeFileSelector();	
	}
//---------------------------------------------------------------------------	
	
	/**
	 * registeres a admin tab to be shown in the Admin module.
	 * @param Tab Admin Tab to be shown in the Admin module.
	 */
	public static void addAdminTab(GECAMedTab adminTab) {
	    admintabs.add(adminTab);
	}
	
	/**
	 * returns a Vector of all registered admin tabs to be shown in the 
	 * Admin module.
	 * @return Vector of all registered admin tabs
	 */
	public static Vector<GECAMedTab> getAdminTabs() {
	    return admintabs;
	}
	
	
	/**
	 * retrieves a machine specific setting
	 * this settings are stored in the GECAMed.properties file localy on the machine
	 * @param key
	 * @return
	 */
	public static String getMachineSetting(String key) {
	    return loginScreen.properties.getProperty(key);
	}
	
	/**
	 * stores a machine specific setting
	 * this settings are stored in the GECAMed.properties file localy on the machine
	 * @param key
	 * @param value
	 */
	public static void setMachineSetting(String key, String value) {
	    loginScreen.properties.setProperty(key, value);
	}


	public static String createLogSectionString(String string) {
	    long now = System.currentTimeMillis();
	    double secs = (now - timeLastStep)/1000.0;
	    double total = (now - timeStart)/1000.0;
	    timeLastStep = now;
	    return "\n====================================================================\n" +
		 string + "    last action took: " + timeFormat.format(secs) +  "s total: " + timeFormat.format(total) + "s " +
		 "\n====================================================================";
	}
	
	public static String createLogSubSectionString(String string) {
	    long now = System.currentTimeMillis();
	    double secs = (now - timeLastStep)/1000.0;
	    double total = (now - timeStart)/1000.0;
	    timeLastStep = now;
	    return  "\n-----------------------------------------------------------------------\n" +
	    		 string + "    last action took: " + timeFormat.format(secs) +  "s total: " + timeFormat.format(total) + "s " +
	    		"\n-----------------------------------------------------------------------";
	}
	
	/**
	 * return all users that are currently online on the specified site
	 * @param siteID id of the current site, null for all sites
	 * @return all users that are currently online on the specified site
	 */
	public static Collection<GecamedUser> getOnlineUsers(Integer siteID) {
	    return getInstance().login.getOnlineUsers(siteID);
	}
	
	/**
	 * return all physicians that are currently online on the specified site
	 * @param siteID id of the current site, null for all sites
	 * @return all physicians that are currently online on the specified site
	 */
	public static Collection<Physician> getOnlinePhysicians(Integer siteID) {
	    Collection<GecamedUser> users = getOnlineUsers(siteID);
	    Collection<Physician> physicians = new ArrayList<Physician>();
	    for (GecamedUser gu : users) {
		physicians.addAll(gu.getPhysicians());
	    }
	    return physicians;
	}
	
	public static Site getCurrentSite() {
	    return site;
	}
	
	public static Integer getCurrentSiteId() {
	    if (site != null)
		return site.getId();
	    else 
		return null;
	}
	
	public static boolean isMultiSite() {
	    return multiSite;
	}
	
	/**
	 * Saves the GECAmed settings
	 */
	public void saveSettings() {
		/* ================================================== */
		this.settingsPanel.updateSettings();
		this.settingsPanel.saveSettings();
		/* ================================================== */
	}
	
	/**
	 * Set the mainframe to front in screen.
	 */
	public void setToFront()
	{
		this.toFront();
		this.requestFocus();
	}
	
	
	public static void exit (int exitCode)
	{
		Thread t;
		
		
		try
		{
			for (Object key : shutdownHooks.keySet())
			{
				logger.info("Starting shutdown hook \""+key+"\" ... ");
				try
				{
					t = shutdownHooks.get(key);
					t.start();
					t.join(3000);
				}
				catch (Throwable e)
				{
					logger.log(Level.WARN, "Error while executing shutdown hook \""+key+"\"", e);
				}
				logger.info("... shutdown hook \""+key+"\" completed");
			}
		}
		catch (Throwable e1)
		{
			logger.log(Level.ERROR, e1.getMessage(), e1);
		}
		
		System.exit(exitCode);
	}
	
	
	public static void addShutdownHook (Object key, Thread hook)
	{
//		Runtime.getRuntime().addShutdownHook(hook);
		shutdownHooks.put(key, hook);
	}
	
	
	private void showErrorModulesDialog()
	{
		JLabel			description	= new JLabel();
		StringBuilder	modules		= new StringBuilder();
		JPanel			mainPanel	= new JPanel(new FormLayout(
				"10px, f:p:g, 10px", "20px, f:p:g, 25px"));
		
		
		for (String module : m_ErrorModules)
		{
			modules.append("<li>")
					.append(module.replaceAll(".*\\.", ""))
					.append("</li>\n");
		}
		
		description.setText(Translatrix.getTranslationString("ModuleErrors.warningMessage", 
				new String[] { modules.toString() }));
		
		mainPanel.setOpaque(false);
		mainPanel.add(description, new CellConstraints(2, 2));
		
		GECAMedBaseDialogImpl dialog = GECAMedBaseDialogImpl.getNewInstance(this, 
				Translatrix.getTranslationString("ModuleErrors.warningTitle"), 
				GECAMedBaseDialogImpl.OK_BUTTON_MODE, 
				mainPanel);
		dialog.setModalityType(ModalityType.MODELESS);
		dialog.pack();
		dialog.showCenteredDialog();
	}
	
	
	/**
	 * @param window The window to relocalise
	 * @param xCoordinate The x-coordinate to put the window to
	 * @param yCoordinate
	 * @param width
	 * @param height
	 */
	public static void adjustWindow (Window window, Integer xCoordinate, Integer yCoordinate, Integer width, Integer height)
	{
		if (window == null)
		{
			logger.warn("Cannot adjust window, as the window is null");
			return;
		}
		
		if (xCoordinate == null || yCoordinate == null)
			return;
		
		window.setLocation(xCoordinate, yCoordinate);
		window.setSize(width, height);
		
		window.addWindowListener(new WindowRelocalizer(window));
	}
	
	
	/**
	 * Provides the label of the transparent on screen message. This function is needed for the inactivity monitoring to display automated logout warning
	 * 
	 * @return A reference to the label of the transparent on screen message
	 */
	public JLabel getGlassLabel() {
		return this.messageGlassLabel;
	}
	
	
	/**
	 * Provides the panel of the transparent on screen message. This function is needed for the inactivity monitoring to display automated logout warning
	 * @return A reference to the panel of the transparent on screen message
	 */
	public JPanel getMessageGlassPane(){
		return this.messageGlassPane;
	}
	
	
	
	/* ======================================== */
	// CLASS: WindowRelocalizer
	/* ======================================== */
	
	private static class WindowRelocalizer extends WindowAdapter
	{
		/* ======================================== */
		// MEMBERS
		/* ======================================== */
		
		private Window		window;
		
		
		
		/* ======================================== */
		// CONSTRUCTORS
		/* ======================================== */
		
		public WindowRelocalizer (Window window)
		{
			this.window	= window;
		}
		
		
		
		/* ======================================== */
		// CLASS BODY
		/* ======================================== */
		
		@Override
		public void windowOpened (WindowEvent e)
		{
			int						width			= window.getWidth();
			int						height			= window.getHeight();
			int						x				= window.getX();
			int						y				= window.getY();
			GraphicsConfiguration	pConfig			= window.getGraphicsConfiguration();
			Rectangle				deviceBounds	= pConfig.getBounds();
			
			
			if (width > deviceBounds.width)
				width = deviceBounds.width;
			
			if (height > deviceBounds.height)
				height = deviceBounds.height;
			
			if (x < deviceBounds.x)
				x = deviceBounds.x;
			else if (x + width > deviceBounds.x + deviceBounds.width)
				x = deviceBounds.x + deviceBounds.width - width;
			
			if (y < deviceBounds.y)
				y = deviceBounds.y;
			else if (y + height > deviceBounds.y + deviceBounds.height)
				y = deviceBounds.y + deviceBounds.height - height;
			
			window.setLocation(x, y);
			window.setSize(width, height);
		}
	}
}
