/*****************************************************************************
 *                                                                           *
 *  Copyright (c) 2010 by SANTEC/TUDOR www.santec.tudor.lu				   *
 *																		   *
 *																		   *
 *  This library is free software; you can redistribute it and/or modify it  *
 *  under the terms of the GNU Lesser General Public License as published	*
 *  by the Free Software Foundation; either version 2 of the License, or	 *
 *  (at your option) any later version.									  *
 *																		   *
 *  This software is distributed in the hope that it will be useful, but	 *
 *  WITHOUT ANY WARRANTY; without even the implied warranty of			   *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU		*
 *  Lesser General Public License for more details.						  *
 *																		   *
 *  You should have received a copy of the GNU Lesser General Public		 *
 *  License along with this library; if not, write to the Free Software	  *
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA  *
 *																		   *
 *****************************************************************************/
package lu.tudor.santec.gecamed.core.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.rmi.ConnectException;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.TimeZone;
import java.util.logging.Handler;

import javax.ejb.EJBAccessException;
import javax.jnlp.BasicService;
import javax.jnlp.ServiceManager;
import javax.naming.CommunicationException;
import javax.naming.InitialContext;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JProgressBar;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;

import lu.tudor.santec.dicom.gui.ErrorDialog;
import lu.tudor.santec.gecamed.core.ejb.session.beans.ListManagerBean;
import lu.tudor.santec.gecamed.core.ejb.session.interfaces.ListManagerInterface;
import lu.tudor.santec.gecamed.core.gui.launcher.GECAMedLauncherServer;
import lu.tudor.santec.gecamed.core.gui.utils.AutoCompletion;
import lu.tudor.santec.gecamed.core.gui.utils.ImagePanel;
import lu.tudor.santec.gecamed.core.gui.utils.LogFileViewer;
import lu.tudor.santec.gecamed.core.gui.utils.PortScanner;
import lu.tudor.santec.gecamed.core.gui.utils.UrlOpener;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl.ButtonOption;
import lu.tudor.santec.gecamed.core.gui.widgets.ServerDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.autocompletion.GECAMedAutoCompletionHandler;
import lu.tudor.santec.gecamed.core.utils.GECAMedUtils;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.core.utils.TimeZoneCheck;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Site;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.beans.LoginBean;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface;
import lu.tudor.santec.i18n.Relocalizable;
import lu.tudor.santec.i18n.SwingLocalizer;
import lu.tudor.santec.i18n.Translatrix;
import lu.tudor.santec.org.fife.ui.autocomplete.AutoCompletionTextComponent;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.RollingFileAppender;
import org.slf4j.bridge.SLF4JBridgeHandler;

import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.l2fprod.gui.plaf.skin.SkinLookAndFeel;

/**
 * 
 * The initial screen to start GECAMed
 * 
 * This class contains the main method which is called to startup gecamed. The
 * screen shows a login Dialog to authenticate the user to the JBoss server.
 * after a successfull authentication an instance of MainFrame is created and
 * the application is started
 * 
 * @author Johannes Hermen johannes.hermen(at)tudor.lu
 *
 * @Version <br>
 *          $Log: LoginScreen.java,v $ <br>
 *          Revision 1.116 2014-01-20 08:42:36 ferring <br>
 *          load default / english translations <br>
 * <br>
 *          Revision 1.115 2014-01-15 09:58:04 ferring <br>
 *          eSante log file added <br>
 * <br>
 *          Revision 1.114 2013-12-10 11:08:13 ferring <br>
 *          time zone conflict handling changed <br>
 * <br>
 *          Revision 1.113 2013-11-07 08:47:09 ferring <br>
 *          Java 5 compatible <br>
 * <br>
 *          Revision 1.112 2013-11-05 14:50:36 ferring <br>
 *          setting the default file encoding doesn't work here. Took it out <br>
 * <br>
 *          Revision 1.111 2013-10-22 08:35:47 donak <br>
 *          Once again a wrong encoding character in LoginScreen.class - should
 *          not reoccur again now <br>
 *          Added libraries that are necessary for LuxTrust certificate handling
 *          and Common Layer access <br>
 * <br>
 *          Revision 1.110 2013-10-03 11:17:21 donak <br>
 *          eSanté integration CDA document upload metadata configuration dialog <br>
 * <br>
 *          Revision 1.109 2013-09-18 11:56:41 ferring <br>
 *          eSante translation bundle removed <br>
 * <br>
 *          Revision 1.108 2013-09-18 11:45:31 ferring <br>
 *          catching error for wrong locale set in locale machine settings <br>
 * <br>
 *          Revision 1.107 2013-09-10 06:15:55 ferring <br>
 *          link to tudor logo added <br>
 * <br>
 *          Revision 1.106 2013-07-23 12:22:55 ferring <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.105 2013-07-15 11:15:44 ferring <br>
 *          logging changed <br>
 * <br>
 *          Revision 1.104 2013-07-15 06:18:35 ferring <br>
 *          logging changed <br>
 * <br>
 *          Revision 1.103 2013-07-10 10:01:21 troth <br>
 *          set system property file.encoding <br>
 * <br>
 *          Revision 1.102 2013-07-10 08:52:33 ferring <br>
 *          logging changed <br>
 * <br>
 *          Revision 1.101 2013-07-09 12:18:50 ferring <br>
 *          logging options changed <br>
 * <br>
 *          Revision 1.100 2013-07-02 09:51:57 ferring <br>
 *          logging level for FOP and JasperReport set to ERROR <br>
 * <br>
 *          Revision 1.99 2013-07-02 09:27:47 ferring <br>
 *          logging level of FOP changed to error <br>
 * <br>
 *          Revision 1.98 2013-06-24 12:54:24 ferring <br>
 *          eSante Translatrix initialized <br>
 * <br>
 *          Revision 1.97 2013-06-10 08:07:49 ferring <br>
 *          version checking changed <br>
 * <br>
 *          Revision 1.96 2013-05-24 10:45:36 ferring <br>
 *          Checking GECAMed version on client and server <br>
 * <br>
 *          Revision 1.95 2013-05-23 14:27:14 ferring <br>
 *          Conflicting time zone detection - changing client time zone to
 *          server time zone <br>
 * <br>
 *          Revision 1.94 2013-03-11 07:48:46 ferring <br>
 *          GECAMedRemoteException will be thrown, if the Manager Factory cannot
 *          return a manager <br>
 * <br>
 *          Revision 1.93 2013-01-16 16:42:50 troth <br>
 *          add new Scanner dialog. <br>
 * <br>
 *          Revision 1.92 2013-01-10 12:54:46 ferring <br>
 *          system exit method changed <br>
 * <br>
 *          Revision 1.91 2013-01-10 09:43:11 ferring <br>
 *          error catching and logging before closing improved <br>
 * <br>
 *          Revision 1.90 2012-11-29 10:54:03 troth <br>
 *          Fix Null-Pointer-Exception when GECAMed starts without
 *          GECAMedLauchnerServer. <br>
 * <br>
 *          Revision 1.89 2012-11-28 16:41:04 troth <br>
 *          Version 1.3 of GECAMedLauncher and GECAMedLauncherServer 1.5. <br>
 *          Some fixings in the LoginScreen. <br>
 * <br>
 *          Revision 1.88 2012-10-31 16:40:47 troth <br>
 *          Version 1.1 of GECAMed launcher. <br>
 * <br>
 *          Revision 1.87 2012-10-19 16:24:42 troth <br>
 *          First version of GECAMed launcher. <br>
 * <br>
 *          Revision 1.86 2012-05-08 07:25:05 ferring <br>
 *          SSN field edit mode can now be switch to fix format, free format or
 *          no format <br>
 * <br>
 *          Revision 1.85 2012-02-29 14:25:19 ferring <br>
 *          port checking improved <br>
 * <br>
 *          Revision 1.84 2012-02-07 10:42:38 ferring <br>
 *          Warn if server has wrong Java version <br>
 * <br>
 *          Revision 1.83 2012-01-26 15:15:19 ferring <br>
 *          Necessary ports are scanned, if the JBoss is not available. <br>
 * <br>
 *          Revision 1.82 2011-04-14 06:20:41 ferring <br>
 *          initializing auto completion fixed <br>
 * <br>
 *          Revision 1.81 2011-02-04 06:47:20 ferring <br>
 *          extended state will be stored in properties and restored at startup <br>
 * <br>
 *          Revision 1.80 2010-10-11 13:57:21 troth <br>
 *          Complete - # 552: Verschreibungs-Vorlagenfenster verdeckt
 *          Verschreibungstext <br>
 *          http://santec.tudor.lu/trac/gecamed/ticket/552 <br>
 * <br>
 *          Revision 1.79 2010-08-26 14:28:04 ferring <br>
 *          additional options for main arguments added <br>
 * <br>
 *          Revision 1.78 2010-08-26 13:33:50 hermen <br>
 *          added commandline arg PATIENTSEARCH: <br>
 * <br>
 *          Revision 1.77 2010-05-05 12:16:10 hermen <br>
 *          fixed logout bug after changing password <br>
 * <br>
 *          Revision 1.76 2010-04-20 07:24:39 hermen <br>
 *          added show server log to tools menu <br>
 * <br>
 *          Revision 1.75 2010-04-08 10:56:40 hermen <br>
 *          enhanced logging <br>
 * <br>
 *          Revision 1.74 2009-10-30 09:58:55 hermen <br>
 *          added departed status to patient <br>
 * <br>
 *          Revision 1.73 2009-09-29 07:53:04 hermen <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.72 2009-09-07 09:24:55 hermen <br>
 *          close login and context <br>
 * <br>
 *          Revision 1.71 2009-05-07 08:26:45 hermen <br>
 *          handle password changing without restarting <br>
 * <br>
 *          Revision 1.70 2009-03-30 13:49:14 mack <br>
 *          Added SwingLocalizer Bundle ot Translatrix init <br>
 * <br>
 *          Revision 1.69 2009-03-16 14:17:27 hermen <br>
 *          added patient incident statistics <br>
 * <br>
 *          Revision 1.68 2009-02-24 08:38:06 hermen <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.67 2009-02-16 09:46:22 hermen <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.66 2009-02-11 14:56:28 hermen <br>
 *          added <br>
 *          isMultiSite() and getSite() <br>
 *          to mainframe <br>
 * <br>
 *          Revision 1.65 2009-02-11 14:05:53 hermen <br>
 *          added management of sites to the office admin tab <br>
 * <br>
 *          Revision 1.64 2009-02-04 16:03:11 hermen <br>
 *          added bean and table for site and site_address <br>
 *          created GECAMedAddressBean which all addresses should extend <br>
 * <br>
 *          Revision 1.63 2008-12-09 09:37:54 hermen <br>
 *          fixed checkJBossconnection() to use correct URL <br>
 * <br>
 *          Revision 1.62 2008-12-09 09:21:54 hermen <br>
 *          fixed checkJBossconnection() to use correct URL <br>
 * <br>
 *          Revision 1.61 2008-10-22 14:34:14 hermen <br>
 *          changed logging <br>
 * <br>
 *          Revision 1.60 2008-10-02 12:49:15 hermen <br>
 *          improved logging <br>
 * <br>
 *          Revision 1.59 2008-10-01 13:28:22 hermen <br>
 *          changed logfiel size <br>
 * <br>
 *          Revision 1.58 2008-09-30 14:25:47 hermen <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.57 2008-09-30 14:18:13 hermen <br>
 *          added server check on startup <br>
 * <br>
 *          Revision 1.56 2008-09-29 13:56:15 hermen <br>
 *          improved debugging <br>
 * <br>
 *          Revision 1.55 2008-09-25 09:43:07 heinemann <br>
 *          fixed copyrights <br>
 * <br>
 *          Revision 1.54 2008-08-19 10:25:08 heinemann <br>
 *          cleanup <br>
 * <br>
 *          Revision 1.53 2008-06-05 09:03:50 hermen <br>
 *          removed tracing <br>
 * <br>
 *          Revision 1.52 2008-06-04 09:39:09 hermen <br>
 *          disabled tracing <br>
 * <br>
 *          Revision 1.51 2008-06-04 09:38:43 hermen <br>
 *          small bugfixes <br>
 * <br>
 *          Revision 1.50 2008-06-03 13:34:16 hermen <br>
 *          added tracing and some invokeLater's <br>
 * <br>
 *          Revision 1.49 2008-05-22 08:29:05 hermen <br>
 *          made setStatus synchronized <br>
 * <br>
 *          Revision 1.48 2008-04-07 14:33:52 hermen <br>
 *          added get/set MachineSetting to store settings localy on the machine <br>
 * <br>
 *          Revision 1.47 2008-03-26 13:46:26 hermen <br>
 *          added backupdb menu entry <br>
 * <br>
 *          Revision 1.46 2008-03-10 14:00:21 hermen <br>
 *          updated UI <br>
 * <br>
 *          Revision 1.45 2008-03-10 13:49:29 hermen <br>
 *          updated splash and about screen <br>
 * <br>
 *          Revision 1.44 2008-03-06 08:30:33 hermen <br>
 *          new SplashScreen <br>
 * <br>
 *          Revision 1.43 2008-01-15 09:29:39 hermen <br>
 *          updated Javadoc and refactured code <br>
 * <br>
 *          Revision 1.42 2008-01-02 09:40:30 heinemann <br>
 *          enhanced logo in loginscreen <br>
 * <br>
 *          Revision 1.41 2007-12-04 14:04:01 hermen <br>
 *          updated Javadoc and refactured code <br>
 *
 */
public class LoginScreen extends JFrame implements ActionListener, Relocalizable {
	// ~ Static fields/initializers
	// =============================================
	private static final long serialVersionUID = 1L;

	public static final int[] NEEDED_PORTS = new int[] { 1098, 1099, 4444, 8080, 8093, 3873 };

	static String user = null;
	static String pass = null;
	static String[] commands = null;

	/**
	 * static logger for this class
	 */
	private static Logger logger;

	/**
	 * directory to store the log and setting files in the client
	 */
	public static final String FOLDER = ".gecamed";

	/**
	 * Webstart URL of the JBoss server from which the client is loaded
	 */
	protected static URL WEBSTART_CODEBASE;

	/**
	 * URL (host:port) of the JBoss server from which the client is loaded
	 */
	public static String JBOSS_URL;

	private int WEB_PORT = 8080;

	/**
	 * home directory of the system user, provided by the os
	 */
	public final static String USER_HOME = System.getProperty("user.home");

	public final static File USER_FOLDER = new File(USER_HOME, FOLDER);

	public static final String SHOW_WARNING_TIME_ZONE = "show.warning.timezone";

	/**
	 * logfile for java.util..logging in the client
	 */
	public final static File LOGFILE = new File(USER_HOME + File.separator + FOLDER + File.separator + "GECAMed.log");

	public final static File ESANTE_LOGFILE = new File(USER_HOME + File.separator + FOLDER + File.separator + "esante_GECAMed.log");

	/**
	 * logfile for java.util..logging in the client
	 */
	public final static File HTML_LOGFILE = new File(USER_HOME + File.separator + FOLDER + File.separator + "GECAMed_log.html");

	// /**
	// * logfile for java.util..logging in the client
	// */
	// public final static File JAVA_LOGFILE = new File(
	// USER_HOME + File.separator + FOLDER + File.separator +
	// "GECAMed_java_util_logging_log");

	/**
	 * properties/settings file on webstart clients (default)
	 */
	public final static File PROPERTIES_USER_HOME = new File(USER_HOME + File.separator + FOLDER + File.separator + "GECAMed.properties");

	/**
	 * properties/settings file on client installations/development
	 */
	public final static File PROPERTIES_DEFAULT = new File("conf/GECAMed.properties");

	/**
	 * key to store the location of the client window in the settings file
	 */
	public static final String MAIN_LOCATION_X = "MAIN_LOCATION_X";

	/**
	 * key to store the location of the client window in the settings file
	 */
	public static final String MAIN_LOCATION_Y = "MAIN_LOCATION_Y";

	/**
	 * key to store the size of the client window in the settings file
	 */
	public static final String MAIN_WIDTH = "MAIN_WIDTH";

	/**
	 * key to store the size of the client window in the settings file
	 */
	public static final String MAIN_HEIGHT = "MAIN_HEIGHT";

	/**
	 * key to store the maximization state of the window in the settings file
	 */
	public static final String MAIN_EXTENDED_STATE = "MAIN_EXTENDED_STATE";

	public static final String LOG_NAME = "Login";
	public static final String LOG_OPERATION_LOGIN = "Login";

	public static final ImageIcon SPLASH_IMAGE = GECAMedModule.getIcon(GECAMedIconNames.SPLASHSCREEN);
	public static final Color SPLASH_TEXTCOLOR = new Color(0, 67, 134);

	private static final String SITE = "SITE";

	/**
	 * set the path to the scanner software
	 */
	public static final String SCANNER_SOFTWARE_PATH = "SCANNER_SOFTWARE_PATH";

	/**
	 * set the path where the scanned images are saved
	 */
	public static final String SCANNER_IMAGE_PATH = "SCANNER_IMAGE_PATH";

	private static final String ERROR_MSG_LOGIN_NOT_FOUND = "No matching username found";

	private static final String ERROR_MSG_INCORRECT_PASSWORD = "Password Incorrect";
	
	private static final String ERROR_MSG_NO_MANAGEDCONNECTIONS = "No ManagedConnections";

	public static LoginScreen instance;

	private static String portWarning;

	// ~ Instance fields
	// ========================================================

	/**
	 * JAAS logincontext for authentication against JBoss
	 */
	private LoginContext lc = null;

	/**
	 * reference to the login SesstionBean
	 */
	private LoginInterface login;

	/**
	 * properties to load and store values of the settings file
	 */
	protected Properties properties = new Properties();

	/**
	 * progressbar on the bottom of the dialog to monitor progress
	 */
	private JProgressBar progressBar;

	/**
	 * current percentage of the login progress
	 */
	private int currState;

	/**
	 * current nr. of logins retries
	 */
	private int logins = 0;

	/**
	 * timestamp of the program start
	 */
	private long startTime;

	/**
	 * timestamp of the last progress step
	 */
	private long lastStepTime;

	/**
	 * enables/disables the listeners on the loginscreen
	 */
	private boolean listenersEnabled = true;

	private JButton cancelButton;
	private JButton okButton;
	private JLabel usernameLabel;
	private JComboBox userField;
	private JLabel passwordLabel;
	private JPasswordField passField;
	private JLabel serverLabel;

	private JLabel versionLabel;

	private JLabel logLabel;

	private JLabel javaInfoLabel;

	public boolean multisite = false;

	public Site site;

	private JLabel siteLabel;

	private JComboBox<Site> siteField;

	public LoginCallbackHandler callbackHandler;

	public String[] commandlineArgs;

	protected Object lookup;

	private JPanel userPanel;

	public static GECAMedLauncherServer gecamedLauncherServer;

	public static Boolean gecamedLauncher = false;
	
	private CellConstraints cc = new CellConstraints();

	// ~ Constructors
	// ===========================================================
	/**
	 * Creates a new LoginScreen the user and password can be provided for
	 * autologin during development
	 * 
	 * @param args
	 */
	public LoginScreen(String user, String pass, String[] args) {
		super("GECAMed- Login");

		this.commandlineArgs = args;

		instance = this;

		// this.setIconImage(GECAMedModule.getIcon(GECAMedIconNames.REDCROSS).getImage());
		// load the supported locales and the default locale
		Translatrix.loadSupportedLocales("lu.tudor.santec.gecamed.core.gui.resources.supportedLocales");
		Translatrix.setLocale(Translatrix.getDefaultLocale());
		Translatrix.setDefaultWhenMissing(true);
		Translatrix.addBundle(SwingLocalizer.getBundle());
		// load resources for core package
		Translatrix.addBundle("lu.tudor.santec.gecamed.core.gui.resources.Translatrix");
		// add translatrix resource bundle for eSanté
		Translatrix.addBundle("lu.tudor.santec.gecamed.esante.gui.resources.Translatrix");

		// set corporate colors and icons
		this.setBackground(GECAMedColors.c_GECAMedBackground);
		this.getContentPane().setBackground(GECAMedColors.c_GECAMedBackground);
		final Border lineBorder = BorderFactory.createLineBorder(getBackground(), 1);
		final Border etchedBorder = BorderFactory.createEtchedBorder();
		final CompoundBorder compoundBorder = BorderFactory.createCompoundBorder(lineBorder, etchedBorder);
		this.getRootPane().setBorder(compoundBorder);
		// remove titlebar from the login window
		try {
			setUndecorated(true);
		} catch (Exception e) {
		}

		// get the Webstart URL
		try {
			BasicService bs = (BasicService) ServiceManager.lookup("javax.jnlp.BasicService");
			WEBSTART_CODEBASE = bs.getCodeBase();
		} catch (Exception e) {
		}

		logger.info("codebase: " + WEBSTART_CODEBASE);
		JBOSS_URL = "localhost";

		if (WEBSTART_CODEBASE != null) {
			JBOSS_URL = WEBSTART_CODEBASE.getHost();
			// WEB_PORT = WEBSTART_CODEBASE.getPort();
		}

		// load client version from file and add it to the system settings
		this.loadVersionFile();

		// load client settings from file and add them to the system settings
		this.loadProperties();

		try {
			JBOSS_URL = properties.getProperty("java.naming.provider.url").split(":")[0];
		} catch (Exception e) {
		}

		logger.info(" \r\n\r\n" + "#######################################################\r\n" + "#\r\n" + "#  Starting GECAMed " + System.getProperty("APP_VERSION") + " @ " + JBOSS_URL + " " + new Date() + "\r\n" + "#\r\n" + "#######################################################\r\n\r\n");

		// set the Locale
		try {
			String[] localeParts = this.properties.getProperty("locale").split("_");
			if (localeParts.length > 1)
				Locale.setDefault(new Locale(localeParts[0], localeParts[1]));
			else if (localeParts.length > 0)
				Locale.setDefault(new Locale(localeParts[0]));
		} catch (Throwable e) {
			logger.error("Cannot cope with the locale \"" + properties.getProperty("locale") + "\" set in the GECAMed local machine settings.", e);
		}

		Translatrix.setLocale(Locale.getDefault());

		// set preselected User
		if (user == null || user.equals("")) {
			user = this.properties.getProperty("user");
		}

		// create the login dialogs gui
		this.setContentPane(buildPanel());
		this.pack();

		// set LookandFeel
		this.setTheme(this.properties.getProperty("lookandfeel"));
		this.relocalize();
		this.enableButtons(true);
		this.setWaitCursor(false);
		logger.info(MainFrame.createLogSectionString(Translatrix.getTranslationString("core.waitingUserInput")));
		this.setStatus(Translatrix.getTranslationString("core.waitingUserInput"), 0);
		this.showCentered();
		this.setVisible(true);

		logger.info("now checking connection to JBoss at: " + JBOSS_URL);
		// test if server is reachable
		performChecks();
		
		try {
			List<Site> sites = GECAMedLists.getListReference(Site.class);
			if (sites != null && sites.size() > 1) {
				multisite = true;
				for (Site site : sites) {
					siteField.addItem(site);
				}
			}
		} catch (Exception e) {
			logger.error("Error while ", e);
		}
		
		if (multisite) {
			userPanel.add(this.siteLabel, cc.xy(1, 5));
			userPanel.add(this.siteField, cc.xy(3, 5));
			validate();
		}
		
		// preselect last used site
		String site = (String) this.properties.get(SITE);
		if (multisite && site != null) {
			for (int i = 0; i < siteField.getItemCount(); i++) {
				if (site.equals(siteField.getItemAt(i).toString())) {
					siteField.setSelectedIndex(i);
					break;
				}
			}
		}
		
		// autologin for easier testing/development
		if (user != null && user != "") {
			this.userField.setSelectedItem(user);
			this.passField.requestFocus();
			if (pass != null) {
				this.passField.setText(pass);
				this.okButton.doClick();
			}
		}

	}

	/**
	 * check if JBoss can be reached on Port 1099 and 8080
	 */
	private void performChecks() {
		LoginInterface loginManager;

		/* **************************************** */
		// CHECK JBOSS CONNECTION
		/* **************************************** */

		String jbossUrl = properties.getProperty("java.naming.provider.url").split(":")[0];
		int port = Integer.parseInt(properties.getProperty("java.naming.provider.url").split(":")[1]);

		try {
			// try to build a connection
			new Socket(jbossUrl, port);
		} catch (Exception e) {
			if (checkPorts()) {
				JOptionPane.showMessageDialog(this, "JBOSS CONNECTION PROBLEM\n" + e.getMessage(), "Server Error", JOptionPane.WARNING_MESSAGE);
				logger.log(Level.WARN, "JBOSS CONNECTION PROBLEM", e);

			} else {
				String[] args = { jbossUrl, portWarning };
				JOptionPane.showMessageDialog(this, Translatrix.getTranslationString("core.serverNotReachable", args), "Server Error", JOptionPane.WARNING_MESSAGE);
				logger.log(Level.WARN, "JBOSS NOT reachable at address: " + jbossUrl + "\n and ports: " + portWarning, e);
			}
		}

		if (!checkJBossRMICommunication(jbossUrl)) {
			System.exit(-1);
		}

		// get the login manager
		loginManager = ((LoginInterface) ManagerFactory.getRemote(LoginBean.class));

		/* **************************************** */
		// CHECK JAVA VERSION
		/* **************************************** */
		try {
			String javaVersion;
			String javaVMName;

			// check if server version is 1.5
			javaVersion = loginManager.getJavaVersion();

			if (!javaVersion.startsWith("1.5.")) {
				GECAMedBaseDialogImpl.showMessageDialog(this, Translatrix.getTranslationString("LoginScreen.wrongJavaVersionTitle"), Translatrix.getTranslationString("LoginScreen.wrongJavaVersionMessage").replaceAll("VERSION", javaVersion), GECAMedBaseDialogImpl.OK_BUTTON_MODE,
						IconFetcher.getIcon(GECAMedModule.class, GECAMedIconNames.WARNING));
			}

			// check if client version NOT OpenJDK
			javaVMName = System.getProperty("java.vm.name");
			if (javaVMName.contains("OpenJDK")) {
				// TODO: translate the dialog
			}
		} catch (Exception e) {
			logger.log(Level.WARN, "Error while trying to check the JBoss Java version.", e);
		}

		/* **************************************** */
		// CHECK TIMEZONE
		/* **************************************** */
		try {
			TimeZoneCheck serverTimeZoneCheck = loginManager.getTimeZoneCheck();
			TimeZoneCheck clientTimeZoneCheck = new TimeZoneCheck();

			int serverHour = serverTimeZoneCheck.getHour();
			int serverMinute = serverTimeZoneCheck.getMinute();
			int clientHour = clientTimeZoneCheck.getHour();
			int clientMinute = clientTimeZoneCheck.getMinute();
			int minuteDif = (clientHour * 60 + clientMinute) - (serverHour * 60 + serverMinute);

			if (minuteDif != 0) {
				if (serverHour != clientHour)
					TimeZone.setDefault(serverTimeZoneCheck.getTimeZone());

				if (clientMinute != serverMinute) {
					TimeZone.getDefault().setRawOffset(minuteDif * 60 * 1000);
				}

				logger.warn("The time of the GECAMed JBoss server is different to the one of this client JVM.\n" + "The Time for the GECAMed client JVM has been changed by " + minuteDif + " minutes");
				// TimeZone.getDefault().getDisplayName() + "\" (" + (serverHour
				// - clientHour)

				Boolean showWarning;
				try {
					showWarning = Boolean.valueOf(this.properties.getProperty(SHOW_WARNING_TIME_ZONE));
				} catch (Exception e) {
					showWarning = null;
				}

				if ((minuteDif < -5 || minuteDif > 5) && (showWarning == null || showWarning.booleanValue())) {
					ButtonOption option = GECAMedBaseDialogImpl.showMessageDialog(this, Translatrix.getTranslationString("LoginScreen.conflictingTimeZonesTitle"),
							Translatrix.getTranslationString("LoginScreen.conflictingTimeZonesMessage", new String[] { String.valueOf((int) (minuteDif / 60)), String.valueOf(minuteDif % 60) }), GECAMedBaseDialogImpl.OK_BUTTON_MODE, GECAMedModule.getBigIcon(GECAMedIconNames.WARNING), true,
							Translatrix.getTranslationString("LoginScreen.conflictingTimeZonesDontShow"));

					this.properties.setProperty(SHOW_WARNING_TIME_ZONE, String.valueOf(!option.applyToAll));
				}
			} else {
				this.properties.setProperty(SHOW_WARNING_TIME_ZONE, String.valueOf(true));
			}
		} catch (Exception e) {
			logger.log(Level.WARN, "Error while trying to check the time zone on conflicts", e);
		}

		/* **************************************** */
		// CHECK THE GECAMed VERSIONS
		/* **************************************** */
		try {
			ListManagerInterface listManager = (ListManagerInterface) ManagerFactory.getRemote(ListManagerBean.class);
			Properties serverProperties = listManager.getServerInfos();
			String serverVersion = serverProperties.getProperty("APP_VERSION");
			String clientVersion = System.getProperty("APP_VERSION");

			if (!serverVersion.equals(clientVersion)) {
				logger.log(Level.ERROR, "Version conflict!" + "The GECAMed Server has a different version than the GECAMed client.\n" + "Client version: " + clientVersion + "\nServer version: " + serverVersion);

				// show user warning
				if (WEBSTART_CODEBASE != null) {
					GECAMedBaseDialogImpl.showMessageDialog(this, Translatrix.getTranslationString("LoginScreen.conflictingGECAMedVersionTitle"), Translatrix.getTranslationString("LoginScreen.conflictingGECAMedVersionMessage", new String[] { clientVersion, serverVersion }),
							GECAMedBaseDialogImpl.OK_BUTTON_MODE, GECAMedModule.getBigIcon(GECAMedIconNames.WARNING));
				} else { // change error message if not using Webstart!!!!!!

					String localPage = "http://" + JBOSS_URL + ":" + WEB_PORT + "/gecamed/";
					String clientPath = new File(".").getAbsolutePath().replaceAll("\\\\", "/");

					GECAMedBaseDialogImpl.showMessageDialog(this, Translatrix.getTranslationString("LoginScreen.conflictingGECAMedVersionTitle"),
							Translatrix.getTranslationString("LoginScreen.conflictingGECAMedVersionMessageLocal", new String[] { clientVersion, serverVersion, clientPath, localPage }), GECAMedBaseDialogImpl.OK_BUTTON_MODE, GECAMedModule.getBigIcon(GECAMedIconNames.WARNING));
				}
			}
		} catch (Exception e) {
			logger.log(Level.WARN, "Error while trying to compare the GECAMed versions of client and server.", e);
		}
	}

	/**		
	 * 
	 */
	private void loadProperties() {
		// set some defaults
		this.properties.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
		this.properties.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
		this.properties.setProperty("java.naming.provider.url", JBOSS_URL + ":1099");
		// defaults for program
		this.properties.setProperty("deployment.javaws.logFileName", LOGFILE.getAbsolutePath());
		this.properties.setProperty("lookandfeel", "javax.swing.plaf.metal.MetalLookAndFeel");
		this.properties.setProperty("locale", Translatrix.getDefaultLocale().toString());
		this.properties.setProperty("user", "admin");

		// try to load properties from conf/ dir
		try {
			this.properties.load(new FileInputStream(PROPERTIES_DEFAULT));
		} catch (Exception e) {
			logger.info("Default properties not found in: " + PROPERTIES_DEFAULT + "trying home dir...");
			try {
				// load properties from user home
				this.properties.load(new FileInputStream(PROPERTIES_USER_HOME));
			} catch (Exception e1) {
				logger.warn("Properties not found in: " + PROPERTIES_USER_HOME + "using defaults...");
			}
		}

		if (WEBSTART_CODEBASE != null) {
			// if started from webstart, set JBOSS_URL to URL of webstart
			this.properties.setProperty("java.naming.provider.url", JBOSS_URL + ":1099");
		} else {
			try {
				File jarDir = new File(LoginScreen.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();
				logger.debug("JarDir: " + jarDir.getAbsolutePath());
				File hostAddrFile = new File(jarDir, "/hostaddress.txt");
				if (hostAddrFile.exists()) {
					// if the GECAMed client was downloaded, there should be a
					// hostaddress.txt file with the appropriate host IP
					logger.debug("hostaddress.txt found!");
					BufferedInputStream hostAddrStream = new BufferedInputStream(new FileInputStream(hostAddrFile));
					byte[] hostAddreBytes = new byte[hostAddrStream.available()];
					hostAddrStream.read(hostAddreBytes);
					hostAddrStream.close();
					JBOSS_URL = new String(hostAddreBytes, "UTF8");
					System.setProperty("java.naming.provider.url", JBOSS_URL + ":1099");
					this.properties.setProperty("java.naming.provider.url", JBOSS_URL + ":1099");
				} else {
					logger.debug("hostaddress.txt does not exist!");
				}

			} catch (Exception e) {
				logger.warn("Error while reading the host IP of the hostaddress.txt file.", e);
			}
		}

		// copy properties to the system properties
		for (Iterator<Object> iter = this.properties.keySet().iterator(); iter.hasNext();) {
			String element = (String) iter.next();
			System.setProperty(element, this.properties.getProperty(element));
		}

		// install a shutdown hook to save settings on program exit
		logger.info("installing ShutdownHook for saveProperties");
		MainFrame.addShutdownHook("save properties", new Thread() {
			public void run() {
				saveProperties();
			}
		});
	}

	// ~ Methods
	// ================================================================
	/**
	 * returns the reference to LoginManagerBean
	 * 
	 * @return the LoginManagerBean
	 */
	public LoginInterface getLogin() {
		return this.login;
	}

	/**
	 * sets the status of the ProgressBar
	 * 
	 * @param text
	 *            the text to display
	 * @param percent
	 *            the percentage of the progress
	 */
	public synchronized void setStatus(String text, int percentagePlus) {
		// get Timestamp
		final long time = System.currentTimeMillis();
		// trim percentage to 0 < 100
		if (percentagePlus <= 0) {
			this.currState = 0;
		} else if (percentagePlus >= 100) {
			this.currState = 100;
		} else {
			this.currState = this.currState + percentagePlus;
		}
		// store startime
		if (startTime == 0) {
			this.startTime = time;
			this.lastStepTime = time;
		}
		// calculate and log time for last step
		final long stepTime = time - this.startTime;
		logger.info(text + "  (at " + stepTime + " ms,\r\n\t last Step took " + (time - this.lastStepTime) + " ms)");
		this.lastStepTime = time;
		// update progressbar
		this.setProgressBar(text, currState);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent e) {
		// okButton pressed --> try to login and start app
		if ((e.getSource().equals(this.okButton)) || (e.getSource().equals(this.passField))) {
			try {
				SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						doLogin();
					}
				});
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			// cancelButton pressed --> System.exit
		} else if (e.getSource().equals(this.cancelButton)) {
			logger.warn("Cancel was pressed.... Bye Bye");
			System.out.println("Cancel was pressed.... Bye Bye");
			MainFrame.exit(0);
		}
	}

	/**
	 * try to login to JBoss, on success create the MainFrame and start the
	 * application. if no success, exit after 3 retries.
	 */
	private void doLogin() {
		String username = (String) this.userField.getSelectedItem();
		String password = new String(this.passField.getPassword());

		// check if username and password are entered
		if (username == null || username.trim().length() <= 0) {
			logger.info("Login canceled, because username is empty");
			setStatus(Translatrix.getTranslationString("main.username.empty"), 0);
			return;
		} else if (password == null || password.length() <= 0) {
			logger.info("Login canceled, because password is empty");
			setStatus(Translatrix.getTranslationString("main.password.empty"), 0);
			return;
		}

		this.setWaitCursor(true);

		logger.info(MainFrame.createLogSectionString(Translatrix.getTranslationString("core.connectiongToJboss")));
		this.setStatus(Translatrix.getTranslationString("core.connectiongToJboss"), 5);

		// manage JAAS login to JBoss
		JaasJbossConfiguration.activateConfiguration();
		callbackHandler = new LoginCallbackHandler(username, password);

		try {
			lc = new LoginContext("gecam_login", callbackHandler);
			lc.login();

			// get a reference to the LoginBean
			new InitialContext();
			this.login = (LoginInterface) ManagerFactory.getRemote(LoginBean.class);

			// load the user that just logged in.
			// this will fail and throw a security exception on an invalid login
			GecamedUser user = this.login.getCurrentUser();

			// set the locales from the current user
			try {
				Locale.setDefault(user.getGecamedLocale().getLocale());
				Translatrix.setLocale(user.getGecamedLocale().getLocale());
				this.relocalize();
			} catch (Exception ee) {
				logger.log(Level.WARN, "error setting locale for user: " + user + " using default....");
				try {
					Locale l = new Locale("en", "US");
					Locale.setDefault(l);
					Translatrix.setLocale(l);
				} catch (Exception e) {
					logger.log(Level.ERROR, "error setting default locale", ee);
				}
			}

			// if we got until here, login succeeded
			logger.info(MainFrame.createLogSectionString(Translatrix.getTranslationString("core.authenticatingToJboss")));
			this.setStatus(Translatrix.getTranslationString("core.authenticatingToJboss"), 5);
			this.enableButtons(false);

			// store some settings
			this.properties.setProperty("locale", Locale.getDefault().toString());
			this.properties.setProperty("user", (String) this.userField.getSelectedItem());

			try {
				if (multisite)
					this.site = (Site) this.siteField.getSelectedItem();
			} catch (Exception e) {
			}

			GECAMedLog.system(LOG_NAME, LOG_OPERATION_LOGIN, "User " + user.getLogin() + " logged in", null);

			// and start the main app
			new Thread() {
				public void run() {
					new MainFrame(LoginScreen.this);
				}
			}.start();
		} catch (CommunicationException e1) {
			try {
				this.lc.logout();
			} catch (Exception e) {
			}

			this.lc = null;
			this.login = null;

			// if server not found
			logger.log(Level.WARN, "Error connecting to JBoss", e1);
			this.setWaitCursor(false);
			// do not count this as wrong login, because username and password
			// haven't been checked
			// this.logins++;
			// if (this.logins >= 3)
			// {
			// // exit program after 3th try
			// doExit();
			// }
			this.setProgressBar(Translatrix.getTranslationString("core.serverNotFound"), 0);
			new ServerDialog(this, this.properties);
			serverLabel.setText(System.getProperty("java.naming.provider.url"));
	
		// TODO catch NoManagedConnections Error "org.jboss.util.NestedSQLException: No ManagedConnections available"
		
		} catch (Exception e) {
			// if login failed --> retry 3 times
			setWaitCursor(false);
			String errorMessage = null;

			StringWriter sw = new StringWriter();
			PrintWriter pw = new PrintWriter(sw);
			e.printStackTrace(pw);
			String stackTrace = sw.toString();
						
			Throwable cause = e.getCause();
			
			if (cause != null && cause instanceof FailedLoginException) {
				if (cause.getMessage().startsWith(ERROR_MSG_LOGIN_NOT_FOUND)) {
					logger.warn("The user \"" + username + "\" does not exist!");
					errorMessage = Translatrix.getTranslationString("main.username.wrong");
				} else if (cause.getMessage().startsWith(ERROR_MSG_INCORRECT_PASSWORD)) {
					logger.warn("Wrong password entered for user \"" + username + "\"!");
					errorMessage = Translatrix.getTranslationString("main.password.wrong");
					if (Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK))
						errorMessage += " - " + Translatrix.getTranslationString("main.password.capslock");
				}

				// only count wrong logins, if username or password was wrong
				this.logins++;
				
			}
				
			// check for "No Managedconnections Error"
			if (stackTrace.indexOf(ERROR_MSG_NO_MANAGEDCONNECTIONS) >= 0) {
				JOptionPane.showMessageDialog(this,
					    Translatrix.getTranslationString("main.nomanagedconnecions"),
					    "Error: No Managed Connections Available",
					    JOptionPane.ERROR_MESSAGE);

				System.exit(-1);
			}

			if (e instanceof EJBAccessException) {
				logger.log(Level.INFO, "Login Failed: ", e);
			} else {
				logger.log(Level.WARN, "Login Failed: ", e);
			}
			// log
			String host1 = "";
			try {
				host1 = InetAddress.getLocalHost().getHostAddress();
			} catch (UnknownHostException e2) {
			}

			GECAMedLog.system(LOG_NAME, LOG_OPERATION_LOGIN, "Login failed for user " + userField.getSelectedItem() + " from Host: " + host1, null);
			// this.logins++;
			if (this.logins >= 3) {
				// exit program after 3th false login
				String host = "";
				try {
					host = InetAddress.getLocalHost().getHostAddress();
				} catch (UnknownHostException e2) {
				}

				// log
				GECAMedLog.system(LOG_NAME, LOG_OPERATION_LOGIN, "Login failed three times from Host: " + host, null);
				doExit();
			}
			// show an errortext
			// this.setProgressBar(Translatrix.getTranslationString("core.loginFailed"),
			// 0);
			if (errorMessage == null)
				errorMessage = Translatrix.getTranslationString("core.loginFailed");

			setProgressBar(errorMessage, 0);
		}

		// initialize the AutoCompletion
		AutoCompletionTextComponent.setDefaultAutoCompletionListener(new GECAMedAutoCompletionHandler());
	}

	public void reLogin(String password) {
		try {
			callbackHandler.renewPassword(password);
			lc.logout();
			lc.login();
		} catch (Exception e) {
			logger.log(Level.ERROR, e.getMessage(), e);
			e.printStackTrace();
		}
	}

	/**
	 * write a system message and exit the program
	 */
	private void doExit() {
		try {
			lc.logout();
		} catch (LoginException e) {
			logger.log(Level.ERROR, e.getMessage(), e);
			e.printStackTrace();
		}
		logger.warn("Exiting after third try...... SORRY");
		// System.out.println("Exiting after third try...... SORRY");
		MainFrame.exit(-1);
	}

	/**
	 * starts the GECAMed Application with a login
	 *
	 * @param args
	 *            [user [password]]
	 */
	public static void main(String[] args) {

		// possible arguments:
		// 1. arument is taken as user
		// 2. argument is taken as password
		//
		// PATIENTSEARCH:karlmeier searches for patient named "karlmeier"
		// PATIENTMATRICULESEARCH:123456 searches for patient with matr.
		// "123456"
		// MODULELIST:lu.tudor.santec.gecamed.billing.gui.BillingModule;lu.tudor.santec.gecamed.labo.gui.LaboModule
		// enables only the BillingModule and the LaboModule
		//

		// SwingTracing.enableEventDispatcherTimeTracing(1000, false);
		// SwingTracing.enableEventDispatcherThreadViolationTracing(false);
		// SwingTracing.enableRepaintTracing("lu.tudor.santec.gecamed.letter");

		// read user and passwd from commandline (for testing purpose)
		try {
			commands = args;
			if (args.length > 0) {
				user = args[0];
				if (args.length > 1) {
					pass = args[1];
				}
			}
			SwingUtilities.invokeAndWait(new Runnable() {
				public void run() {
					initLogger();

					
					try {
						// test if the GECAMedLauncher config file exists. If it
						// exists start up the GECAMedLauncherServer in GECAMed to
						// listen
						// for the parameter which will passed from the
						// GECAMedLauncher to GECAMed
						File configFile = new File("config/GECAMedLaucherServer.conf");

						if (configFile.exists())
							gecamedLauncher = true;

						if (gecamedLauncher) {
							logger.info("Start GECAMEDLaunchserver ... v. 1.5");
							gecamedLauncherServer = new GECAMedLauncherServer();
							gecamedLauncherServer.startServer();
							System.out.println("... wait for params ...");
							logger.info("... wait for params ...");
							if (user == null || pass == null) {
								while (gecamedLauncherServer.getUsername() == null || gecamedLauncherServer.getPassword() == null || gecamedLauncherServer.getCommands() == null) {
									System.out.println("... wait for params ...");
									try {
										Thread.sleep(1000);
									} catch (InterruptedException e) {
										System.out.println("GECAMed Login can't sleep");
										logger.warn("GECAMed Login can't sleep.\n" + e.getStackTrace());
										e.printStackTrace();
									}
								}
								System.out.println("... get params ...");
								logger.info("... get params ...");

								// start launch server
								user = gecamedLauncherServer.getUsername();
								pass = gecamedLauncherServer.getPassword();
								commands = gecamedLauncherServer.getCommands();
								if (user.equalsIgnoreCase(""))
									user = null;
								if (pass.equalsIgnoreCase(""))
									pass = null;
							}

						}
					} catch (Throwable e) {
						// Handle any GECAMed Launcher Errors....
						logger.warn("Error starting GECAMEDLaunchserver ... v. 1.5", e);
					}
					
					logger.info("Start gecamed with params ...");
					new LoginScreen(user, pass, commands);
				}
			});
		} catch (Throwable e) {
			// Here we catch everything else
			logger.log(Level.ERROR, "Unhandled Exception/Error - System Stopped!", e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see lu.tudor.santec.i18n.Relocalizable#relocalize()
	 */
	public void relocalize() {
		this.cancelButton.setText(Translatrix.getTranslationString("core.cancel"));
		this.okButton.setText(Translatrix.getTranslationString("core.ok"));
		this.usernameLabel.setText(Translatrix.getTranslationString("core.username"));
		this.passwordLabel.setText(Translatrix.getTranslationString("core.password"));
		this.validate();
	}

	/**
	 * set the progress bar to the given string an percentage
	 * 
	 * @param string
	 * @param value
	 */
	private synchronized void setProgressBar(final String string, final int value) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				if (progressBar != null) {
					if (value < 0) {
						progressBar.setString(string);
						progressBar.setIndeterminate(true);
					} else {
						progressBar.setIndeterminate(false);
						progressBar.setString(string);
						progressBar.setValue(value);
					}
				}
			}
		});
	}

	private void initComponents() {
		// create the version label
		String gitRev = System.getProperty("APP_GIT_REV");
		if (gitRev != null && gitRev.length() > 7)
			gitRev = gitRev.substring(0, 7);
		String appText = "<html><span style=\"font-size:10px;\">" + "Version: " + System.getProperty("APP_VERSION") + "</span><br>" + "<span style=\"font-size:8px;\">Revision: " + gitRev + "</span></html>";
		this.versionLabel = new JLabel(appText);
		this.versionLabel.setForeground(Color.WHITE);
		this.versionLabel.setVerticalAlignment(JLabel.BOTTOM);

		// create the username label
		this.usernameLabel = new JLabel();
		this.usernameLabel.setForeground(SPLASH_TEXTCOLOR);
		this.usernameLabel.setText(Translatrix.getTranslationString("core.username"));

		// create the username label
		this.passwordLabel = new JLabel();
		this.passwordLabel.setForeground(SPLASH_TEXTCOLOR);
		this.passwordLabel.setText(Translatrix.getTranslationString("core.password"));

		// create the username label
		this.siteLabel = new JLabel();
		this.siteLabel.setForeground(SPLASH_TEXTCOLOR);
		this.siteLabel.setText(Translatrix.getTranslationString("core.site"));

		// user combobox
		String[] logins = { "" };
		try {
			logins = properties.getProperty("validUsers").split(",");
		} catch (Exception e) {
			logger.info("no local user list found!");
		}
		this.userField = new JComboBox(logins);
		this.userField.setEditable(true);
		try {
			((JComponent) this.userField.getRenderer()).setForeground(SPLASH_TEXTCOLOR);
			((JComponent) this.userField.getEditor()).setForeground(SPLASH_TEXTCOLOR);
		} catch (Exception e) {
		}

		this.userField.setForeground(SPLASH_TEXTCOLOR);
		AutoCompletion.enableWithFreeText(this.userField);

		// password input field
		this.passField = new JPasswordField(8);
		this.passField.setPreferredSize(new Dimension(0, 22));
		this.passField.addActionListener(this);
		this.passField.setForeground(SPLASH_TEXTCOLOR);

		// site chooser
		this.siteField = new JComboBox<Site>();
		this.siteField.setEditable(false);
		try {
			((JComponent) this.siteField.getRenderer()).setForeground(SPLASH_TEXTCOLOR);
			((JComponent) this.siteField.getEditor()).setForeground(SPLASH_TEXTCOLOR);
		} catch (Exception e) {
		}

		this.siteField.setForeground(SPLASH_TEXTCOLOR);
		AutoCompletion.enable(this.siteField);

		// install focus listener to select context of password field if focus
		// is gained
		this.passField.addFocusListener(new FocusAdapter() {
			public void focusGained(FocusEvent e) {
				try {
					passField.setSelectionStart(0);
					passField.setSelectionEnd(passField.getPassword().length);
				} catch (Exception ee) {
				}
			}
		});

		// create progress bar
		UIManager.put("ProgressBar.selectionBackground", SPLASH_TEXTCOLOR);
		this.progressBar = new JProgressBar(SwingConstants.HORIZONTAL);
		this.progressBar.setStringPainted(true);
		this.progressBar.setBackground(Color.WHITE);
		this.progressBar.setForeground(SPLASH_TEXTCOLOR);

		// create Buttons
		this.cancelButton = new JButton();
		this.cancelButton.setForeground(SPLASH_TEXTCOLOR);
		this.cancelButton.addActionListener(this);
		this.okButton = new JButton();
		this.okButton.setForeground(SPLASH_TEXTCOLOR);
		this.okButton.addActionListener(this);
		this.cancelButton.setText(Translatrix.getTranslationString("core.cancel"));
		this.okButton.setText(Translatrix.getTranslationString("core.ok"));

		// create the server label
		serverLabel = new JLabel();
		serverLabel.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if (listenersEnabled) {
					new ServerDialog(LoginScreen.this, properties);
					serverLabel.setText(System.getProperty("java.naming.provider.url"));
				}
			}
		});
		serverLabel.setFont(new Font("Arial", Font.PLAIN, 9));
		serverLabel.setText(System.getProperty("java.naming.provider.url"));

		// create the server label
		logLabel = new JLabel();
		logLabel.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if (listenersEnabled) {
					LogFileViewer.showLogFile(LoginScreen.this, "client-log");
				}
			}
		});
		logLabel.setFont(new Font("Arial", Font.PLAIN, 9));
		logLabel.setText("Logfile");

		StringBuilder javaInfo = new StringBuilder("Java version: ").append(System.getProperty("java.version")).append(GECAMedUtils.isJava64Bit() ? " (64-Bit)" : " (32-Bit)");

		String webstartVersion = System.getProperty("javawebstart.version");
		if (webstartVersion != null)
			javaInfo.append(" / WebStart version: ").append(webstartVersion.replace("javaws-", ""));

		javaInfoLabel = new JLabel();
		javaInfoLabel.setFont(new Font("Arial", Font.ITALIC, 8));
		javaInfoLabel.setText(javaInfo.toString());
		// javaInfoLabel.setBorder(new EmptyBorder(0, 0, 0, 0));

		LoginMouseAdapter lma = new LoginMouseAdapter();
		addMouseListener(lma);
		addMouseMotionListener(lma);
	}

	/**
	 * creates the main panel of the login dialog.
	 * 
	 * @return
	 */
	private JPanel buildPanel() {
		initComponents();

		// create the layout
		FormLayout layout = new FormLayout("4px, 40px, 276px, 114px, 40px", "fill:85px, 13px, 114px, 5px, 33px, 5px, 33px, 0px, pref, fill:pref");
		JPanel backgroundPanel = new ImagePanel(SPLASH_IMAGE);
		backgroundPanel.setLayout(layout);

		// add the version label
		backgroundPanel.add(versionLabel, cc.xyw(4, 1, 2, CellConstraints.LEFT, CellConstraints.BOTTOM));

		// add the user panel
		userPanel = new JPanel();
		
//		if (multisite) {
			userPanel.setLayout(new FormLayout("pref:grow, 8px, fill:pref:grow", "pref, 5px, pref, 5px, pref"));
//		} else {
//			userPanel.setLayout(new FormLayout("pref:grow, 8px, fill:pref:grow", "pref, 5px, pref"));
//		}
			
		userPanel.setOpaque(true);
		userPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
		userPanel.setBackground(new Color(255, 255, 255, 150));
		userPanel.add(this.usernameLabel, cc.xy(1, 1));
		userPanel.add(userField, cc.xy(3, 1));
		userPanel.add(this.passwordLabel, cc.xy(1, 3));
		userPanel.add(passField, cc.xy(3, 3));
		
//		if (multisite) {
//			userPanel.add(this.siteLabel, cc.xy(1, 5));
//			userPanel.add(this.siteField, cc.xy(3, 5));
//		}
		
		backgroundPanel.add(userPanel, cc.xyw(3, 3, 2, CellConstraints.FILL, CellConstraints.BOTTOM));

		// add the progress bar
		backgroundPanel.add(this.progressBar, cc.xyw(3, 5, 2));

		// add the buttonbar
		ButtonBarBuilder bbuilder = new ButtonBarBuilder();
		// add Buttons
		bbuilder.addRelatedGap();
		bbuilder.addGlue();
		bbuilder.addGriddedButtons(new JButton[] { cancelButton, okButton });
		JPanel bottomPanel = new JPanel(new BorderLayout());
		bottomPanel.setOpaque(false);
		JPanel bBar = bbuilder.getPanel();
		bBar.setOpaque(false);
		bottomPanel.add(bBar, BorderLayout.CENTER);

		JPanel labelPanel = new JPanel(new BorderLayout(10, 10));
		labelPanel.setOpaque(false);
		labelPanel.add(logLabel, BorderLayout.WEST);
		labelPanel.add(serverLabel, BorderLayout.CENTER);

		bottomPanel.add(labelPanel, BorderLayout.WEST);
		backgroundPanel.add(bottomPanel, cc.xyw(3, 7, 2));
		backgroundPanel.add(javaInfoLabel, cc.xyw(3, 9, 2));

		enableButtons(false);
		backgroundPanel.setOpaque(false);
		return backgroundPanel;
	}

	/**
	 * en/disables the buttons and inputfields on the gui
	 * 
	 * @param enabled
	 *            true/false
	 */
	private void enableButtons(boolean enabled) {
		this.cancelButton.setEnabled(enabled);
		this.okButton.setEnabled(enabled);
		this.userField.setEnabled(enabled);
		this.passField.setEnabled(enabled);
		this.siteField.setEnabled(enabled);
		this.listenersEnabled = enabled;
	}

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

	/**
	 * saves the local Settings to the settingfile
	 */
	private void saveProperties() {
		try {
			logger.info("Saving user properties ...");

			JFrame mainFrame = MainFrame.getInstance();

			if (mainFrame == null)
				return;

			// save Userlist
			try {
				this.properties.setProperty("validUsers", this.login.getUserLoginList());
			} catch (Exception e1) {
				logger.warn("Failed to fetch user list");
			}

			// save selected site
			if (multisite) {
				try {
					this.properties.setProperty(SITE, this.siteField.getSelectedItem().toString());
				} catch (Exception e) {
				}
			}

			// save ScreenSettings
			this.properties.put(MAIN_LOCATION_X, mainFrame.getLocation().x + "");
			this.properties.put(MAIN_LOCATION_Y, mainFrame.getLocation().y + "");

			int width = mainFrame.getWidth();
			int height = mainFrame.getHeight();
			if (width > 640 && height > 480) {
				this.properties.put(MAIN_WIDTH, width + "");
				this.properties.put(MAIN_HEIGHT, height + "");
			}

			if (PROPERTIES_DEFAULT.exists() && PROPERTIES_DEFAULT.canWrite()) {
				this.properties.store(new FileOutputStream(PROPERTIES_DEFAULT), "changed by loginscreen");
				logger.info("writing properties to: " + PROPERTIES_DEFAULT);
			} else {
				this.properties.store(new FileOutputStream(PROPERTIES_USER_HOME), "changed by loginscreen");
				logger.info("writing properties to: " + PROPERTIES_USER_HOME);
			}
			logger.info("... saving properties completed.");
		} catch (Throwable e) {
			logger.log(Level.WARN, "saveProperties failed", e);
		}
	}

	public Properties getProperties() {
		return this.properties;
	}

	/**
	 * sets the application to the given LookAndFeel
	 *
	 * @param lookandFeel
	 *            the name of the lookandfeel or the path to the Themepack for
	 *            skinlf
	 * @param mainWindow
	 *            the mainwindow of the application to update the L&F
	 */
	private void setTheme(String lookandFeel) {
		try {
//			UIManager.getSystemLookAndFeelClassName();
			// for skinlf
			if (lookandFeel.toLowerCase().endsWith(".zip")) {
				SkinLookAndFeel.setSkin(SkinLookAndFeel.loadThemePack(lookandFeel));
				UIManager.setLookAndFeel(new SkinLookAndFeel());

				// for others
			} else {
				UIManager.setLookAndFeel(lookandFeel);
			}
			SwingUtilities.updateComponentTreeUI(this);
			this.pack();
			properties.setProperty("lookandfeel", lookandFeel);
		} catch (Exception e) {
			logger.warn("setting of LookandFeel " + lookandFeel + " failed!");
			
			System.out.println("Supported UIs:");
			for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { 
				System.out.println("\t" + info.getClassName());
			}
		}
	}

	/**
	 * sets the Mousecursor of the LoginScreen to a WaitCursor and Back
	 *
	 * @param on
	 *            true=waitcursor false=normalcursor
	 */
	private void setWaitCursor(boolean on) {
		if (on) {
			this.getGlassPane().setBackground(new Color(255, 255, 255, 0));
			this.getGlassPane().setVisible(true);
			this.getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		} else {
			this.getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			this.getGlassPane().setVisible(false);
		}
	}

	/**
	 * load version infos and add them to system properties
	 */
	private void loadVersionFile() {
		Properties version = new Properties();
		try {
			version.load(LoginScreen.class.getResourceAsStream("resources/VERSION.properties"));
			for (Iterator<Object> iter = version.keySet().iterator(); iter.hasNext();) {
				String element = (String) iter.next();
				System.setProperty(element, version.getProperty(element));
			}
		} catch (Exception e) {
			try {
				version.load(new FileInputStream("src/META-INF/VERSION.properties"));
				for (Iterator<Object> iter = version.keySet().iterator(); iter.hasNext();) {
					String element = (String) iter.next();
					System.setProperty(element, version.getProperty(element));
				}
			} catch (Exception ee) {
				logger.log(Level.WARN, "unable to read version infos", ee);
			}
		}
	}

	/**
	 * @return the instance
	 */
	public static LoginScreen getInstance() {
		return instance;
	}

	/**
	 * Get the value of a propertie by propertie name of the client settings
	 * 
	 * @param name
	 *            of the propertie
	 * @return value of the propertie
	 */
	public static String getMachineSetting(String name) {
		return (String) instance.properties.get(name);
	}

	/**
	 * Set/Create a propertie of the client settings with name and value
	 * 
	 * @param name
	 *            the name of the propertie
	 * @param value
	 *            the value of the propertie
	 */
	public static void setMachineSetting(String name, String value) {
		instance.properties.put(name, value);
	}

	public static boolean checkPorts() {
		// scan the ports, needed to be open for communication with JBoss
		Collection<Integer> closedPorts = PortScanner.scan(JBOSS_URL, NEEDED_PORTS).getClosedPorts();
		if (closedPorts.size() > 0) {
			StringBuilder warning = new StringBuilder();
			for (Integer port : closedPorts)
				warning.append(port).append(" ");
			portWarning = warning.toString();
			logger.warn("The following ports are NOT open: " + warning.toString());
			return false;
		} else {
			portWarning = null;
			logger.info("All needed ports at: " + JBOSS_URL + " are open");
			return true;
		}
	}

	private static void initLogger() {
		/* ---------------------------------------- */
		// INIT THE org.apache.log4j.Logger
		/* ---------------------------------------- */

		try {
			// create an initial logger
			LOGFILE.getParentFile().mkdirs();

			Logger.getRootLogger().removeAllAppenders();

			// define the logging layouts
			Layout fileLayout = new PatternLayout("%d{yyyy-MM-dd HH:mm:ss,SSS} %c %M (line %L)%n%p: %m%n");
			Layout consoleLayout = fileLayout;
			// HTMLLoggerLayout htmlLayout = new HTMLLoggerLayout();
			// htmlLayout.setTitle("GECAMed Client Log");

			// set the logger
			ConsoleAppender consoleAppender = new ConsoleAppender(consoleLayout);
			Logger.getRootLogger().addAppender(consoleAppender);

			RollingFileAppender fileAppender = new RollingFileAppender(fileLayout, LOGFILE.getAbsolutePath(), true);
			fileAppender.setMaxFileSize("5MB");
			fileAppender.setMaxBackupIndex(3);
			fileAppender.setEncoding("UTF-8");
			fileAppender.setName("GECAMed default Logger");
			BasicConfigurator.configure(fileAppender);

			// fileAppender = new RollingFileAppender(
			// htmlLayout,
			// HTML_LOGFILE.getAbsolutePath(),
			// true);
			// fileAppender.setMaxFileSize("5MB");
			// fileAppender.setMaxBackupIndex(3);
			// fileAppender.setEncoding("UTF-8");
			// BasicConfigurator.configure(fileAppender);

			// configure the eSanté logger
			RollingFileAppender eSanteAppender = new RollingFileAppender(fileLayout, ESANTE_LOGFILE.getAbsolutePath(), true);
			eSanteAppender.setMaxFileSize("2MB");
			eSanteAppender.setMaxBackupIndex(3);
			eSanteAppender.setEncoding("UTF-8");
			eSanteAppender.setName("GECAMed eSante Logger");
			// fileAppender.addFilter();
			// BasicConfigurator.configure(fileAppender);
			Logger.getLogger("lu.tudor.santec.gecamed.esante").addAppender(eSanteAppender);

			// define level for logging levels
			Logger.getRootLogger().setLevel(Level.INFO);
			Logger.getLogger("org.apache.fop").setLevel(Level.ERROR);
			Logger.getLogger("net.sf.jasperreports").setLevel(Level.ERROR);
			Logger.getLogger("lu.tudor.santec.gecamed.esante").setLevel(Level.DEBUG);

			logger = Logger.getLogger(LoginScreen.class.getName());
			logger.log(Level.INFO, "########################### BEGIN STARTING GECAMED ###########################\n");
			
			logger.setLevel(Level.DEBUG);
			logger.log(Level.TRACE, "org.apache.log4j works!");
		} catch (Exception e) {
			logger = Logger.getLogger(LoginScreen.class.getName());
			logger.log(Level.ERROR, "Error initializing log4j Logger", e);
		}

		/* ---------------------------------------- */
		// INIT THE java.util.Logger
		/* ---------------------------------------- */

		try {
			SLF4JBridgeHandler.uninstall();
			for (Handler h : java.util.logging.Logger.getLogger("").getHandlers())
				java.util.logging.Logger.getLogger("").removeHandler(h);
			SLF4JBridgeHandler.install();

			java.util.logging.Logger.getLogger(LoginScreen.class.getName()).fine("java.util.logging works!");
		} catch (Exception e) {
			logger.log(Level.WARN, "setting up java.util.logging.Logger failed", e);
		}
	}

	private class LoginMouseAdapter implements MouseListener, MouseMotionListener {
		private Rectangle linkArea;

		private String linkUrl;

		public LoginMouseAdapter() {
			linkArea = new Rectangle(262, 8, 478 - 262, 32);
			linkUrl = "http://www.tudor.lu/social-media";
		}

		public void mouseClicked(MouseEvent e) {
			if (linkArea.contains(e.getPoint())) {
				UrlOpener.openURL(linkUrl);
			}
		}

		public void mouseMoved(MouseEvent e) {
			if (linkArea.contains(e.getPoint())) {
				LoginScreen.this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
			} else {
				LoginScreen.this.setCursor(Cursor.getDefaultCursor());
			}
		}

		public void mouseDragged(MouseEvent e) {
		}

		public void mousePressed(MouseEvent e) {
		}

		public void mouseReleased(MouseEvent e) {
		}

		public void mouseEntered(MouseEvent e) {
		}

		public void mouseExited(MouseEvent e) {
		}
	}

	/**
	 * Method should only be called if a general ip connection to the JBoss can
	 * be established saying, JBoss URL is reachable and ports are open. This
	 * method will check if the RMI Interface is working proper and if JBoss RMI
	 * Services are bound to the address we are connecting to.
	 * 
	 * @param jbossHost
	 *            IP/Hostname of JBoss
	 * 
	 * @return true on success, else false.
	 */
	private boolean checkJBossRMICommunication(String jbossHost) {
		lookup = null;
		final StringBuffer sb = new StringBuffer();

		// just do a lookup to a bean that has no access control.
		// if it does not return a bean reference within 10sec, we will report
		// the error.
		Thread t = new Thread() {
			public void run() {
				try {
					InitialContext ctx = new InitialContext();
					lookup = ctx.lookup(ManagerFactory.PREFIX + ListManagerBean.class.getSimpleName() + "/remote");
				} catch (CommunicationException e) {
					Throwable t = e.getRootCause();
					if (t instanceof ConnectException) {
						sb.append(((ConnectException) t).getMessage()).append("\n");
					}
				} catch (Exception ee) {
					sb.append(ee.getMessage()).append("\n");
				}
			}
		};
		t.start();

		for (int i = 0; i < 10; i++) {
			if (lookup != null) {
				return true;
			}
			try {
				Thread.sleep(1000);
				System.out.print(".");
			} catch (InterruptedException e) {
			}
		}
		System.out.println();

		if (t.isAlive()) {
			try {
				t.interrupt();
			} catch (Exception e) {
			}
			sb.append("Server at: " + jbossHost + " did not answer to RMI call within 10 sec.\n");
		}

		StringBuffer errorMessage = new StringBuffer();

		// fetch some server infos
		try {
			String[] ips = readURL("http://" + jbossHost + ":8080/gecamed/ToolServlet?do=rmiip").split("#");
			ips[0] = jbossHost;
			errorMessage.append(Translatrix.getTranslationString("core.RMIError", ips));
			sb.append(Translatrix.getTranslationString("core.RMIError", ips).replaceAll("<br>", "\n"));

			sb.append(readURL("http://" + jbossHost + ":8080/gecamed/ToolServlet?do=checkrmi").replaceAll("<br>", "\n"));
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			errorMessage.append(sb.toString());
		}

		ErrorDialog.showErrorDialog(this, "UNABLE TO CONNECT TO GECAMED SERVER AT: " + jbossHost, errorMessage.toString(), sb.toString());

		// JOptionPane.showMessageDialog(this,
		// errorMessage.toString(),
		// "Server Connection Error",
		// JOptionPane.ERROR_MESSAGE);

		System.err.println(sb.toString());
		return false;
	}

	public static String readURL(String url) throws Exception {

		URL oracle = new URL(url);
		BufferedReader in = new BufferedReader(new InputStreamReader(oracle.openStream()));
		StringBuffer sb = new StringBuffer();

		String inputLine;
		while ((inputLine = in.readLine()) != null)
			sb.append(inputLine);
		in.close();
		return sb.toString();
	}

}
