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

import java.io.ByteArrayInputStream;
import java.security.Principal;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import javax.annotation.Resource;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Remote;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.sql.DataSource;

import lu.tudor.santec.gecamed.core.ejb.entity.beans.GECAMedLocale;
import lu.tudor.santec.gecamed.core.utils.ServerConfig;
import lu.tudor.santec.gecamed.core.utils.TimeZoneCheck;
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.Permission;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.Role;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.Setting;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.UserRole;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface;
import lu.tudor.santec.settings.SettingReader;

import org.apache.log4j.Logger;
import org.jboss.annotation.security.SecurityDomain;

/**
 * This Bean-Class Manages the Login and Authentification into JBoss it provides
 * Methods to retrieve rights, rightinfo and userinfo on the User which is
 * currently logged in.
 * 
 * @author Johannes Hermen
 * 
 * @Version 
 * <br>$Log: LoginBean.java,v $
 * <br>Revision 1.45  2013-12-05 16:38:50  ferring
 * <br>Throwables catching changed to get more output about errors
 * <br>
 * <br>Revision 1.44  2013-05-23 14:27:14  ferring
 * <br>Conflicting time zone detection - changing client time zone to server time zone
 * <br>
 * <br>Revision 1.43  2013-01-09 08:29:18  ferring
 * <br>Errors in auto backup caught
 * <br>
 * <br>Revision 1.42  2012-02-07 10:39:23  ferring
 * <br>Warn if server has wrong Java version
 * <br>
 * <br>Revision 1.41  2010-09-06 13:11:34  hermen
 * <br>changed logging to info
 * <br>
 * <br>Revision 1.40  2010-07-08 08:25:37  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.39  2010-05-05 12:22:07  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.38  2010-04-27 15:13:10  mack
 * <br>Added getModulePermissions method
 * <br>
 * <br>Revision 1.37  2010-04-20 07:24:52  hermen
 * <br>added show server log to tools menu
 * <br>
 * <br>Revision 1.36  2009-11-27 09:56:02  hermen
 * <br>removed stacktrace, as not needed here
 * <br>
 * <br>Revision 1.35  2009-10-14 09:21:01  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.34  2009-02-27 15:25:56  hermen
 * <br>added button to create an empty incident for a patient visit
 * <br>
 * <br>Revision 1.33  2009-02-04 10:15:56  hermen
 * <br>added functionality to get all Users that are logged in on a GECAMed Server
 * <br>
 * <br>Revision 1.32  2009-01-26 13:21:25  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.31  2008-10-07 09:34:37  heinemann
 * <br>translations of roles and rights;
 * <br>show only  roles and rights of the activated modules in the usermanagement section
 * <br>
 * <br>Revision 1.30  2008-10-02 15:09:41  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.29  2008-09-25 09:43:10  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.28  2008-09-24 09:11:52  heinemann
 * <br>added first run actions to gecamed. will disable all views except the ones of the admin tab for user, office and physician.
 * <br>Tabs are enabled, if an physican was saved.
 * <br>
 * <br>Revision 1.27  2008-06-10 08:43:05  hermen
 * <br>fixed NPE when reading settings
 * <br>
 * <br>Revision 1.26  2008-03-28 14:56:36  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.25  2008-03-26 10:20:29  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.24  2008-01-15 12:58:13  hermen
 * <br>added getAllUsers
 * <br>
 * <br>Revision 1.23  2008-01-15 09:30:13  hermen
 * <br>updated Javadoc and refactured code
 * <br>
 * 
 */
@Remote ({LoginInterface.class})
@Stateless
@SecurityDomain ("gecamedLoginDS")
public class LoginBean implements LoginInterface
{
/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(LoginBean.class.getName());

	
	// Injections
	@Resource SessionContext sessionContext;

	@PersistenceContext(unitName ="gecam")
	protected EntityManager em;


	private static SettingReader adminSettings;


//	private static int instanceNr;

	private static java.util.Hashtable<GecamedUser, Long> onlineUsers = new java.util.Hashtable<GecamedUser, Long>();

    //~ Static fields/initializers =============================================

//    private static final long serialVersionUID = 1L;

    public static final int GLOBAL_SETTINGS_ID = -1;
    
	public static final String		USER_NAME_SYSTEM	= "System";
	
	public static final GecamedUser	USER_SYSTEM			= new GecamedUser(USER_NAME_SYSTEM);

	static
	{
		USER_SYSTEM.setGecamedLocale(new GECAMedLocale(new Locale(GECAMedLocale.ENGLISH)));
	}

	
    //========================================================================
   
    
    private static final String MODULE_PERMISSIONS_FOR_USER = "SELECT name FROM Permission WHERE name like :moduleName AND " +
	   													   	  "(id IN " +
	   													   		   "(Select permission.id FROM RolePermission WHERE role.id IN " +
	   													   		   "(Select role.id FROM UserRole WHERE user.id = :userId))" +
	   													      " OR id IN " +
	   													   		   "(Select permission.id FROM UserPermission WHERE user.id = :userId))";

	private static final String MODULE_ROLES_FOR_USER 		 = "SELECT name FROM Role WHERE name = :moduleName AND " +
														       "id IN " +
														   		   "(Select role.id FROM UserRole WHERE user.id = :userId)";
    
    
    
    //~ Instance fields ========================================================


    //~ Constructors ===========================================================

    /**
     * creates a new instance of a LoginBean
     */
    public LoginBean()
    {
        super();
    }
    
    //~ Methods ================================================================

    /* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.beans.UserManagementInterface#getCurrentUser()
	 */
    @RolesAllowed("gecam")
    public GecamedUser getCurrentUser()
    {
        String login = this.getCurrentUserName();
        GecamedUser staff;
        
        if (USER_NAME_SYSTEM.equals(login))
        {
        	return USER_SYSTEM;
        }
        
        try
        {
	        staff = (GecamedUser) em.createNamedQuery(GecamedUser.FIND_USERS_BY_LOGIN)
		        	.setParameter("login", login)
		        	.setMaxResults(1)
		        	.getSingleResult();
	        return staff;
        }
        catch (Exception e)
        {
        	return USER_SYSTEM;
        }
    }

    /* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.beans.UserManagementInterface#getCurrentUserID()
	 */
//    @RolesAllowed("gecam")
    public Integer getCurrentUserID()
    {
    	return getCurrentUser().getId();
    }


    /* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.beans.UserManagementInterface#getCurrentUserName()
	 */
//    @RolesAllowed("gecam")
    public String getCurrentUserName()
    {
    	Principal p = sessionContext.getCallerPrincipal();
    	
    	if (p == null || p.getName() == null)
    		return USER_NAME_SYSTEM;
    	else
    		return p.getName();
    }


    /* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.beans.UserManagementInterface#getUserLoginList()
	 */
//    @SuppressWarnings("unchecked")
    @RolesAllowed("gecam")
    public String getUserLoginList()
    {
        Collection<?> cHome;
        String logins = "";
        cHome = em.createQuery("SELECT l.login FROM GecamedUser AS l")
    	 		.getResultList();

        for (Iterator<?> it = cHome.iterator(); it.hasNext();) {
            logins += ((Object) it.next()) + ",";
        }
        return logins;
    }

    /* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.beans.UserManagementInterface#getSettings()
	 */
    @RolesAllowed("gecam")
    public Setting getSettings() {
		try {
			return  (Setting) em.createNamedQuery("findSettingByUserID")
										.setParameter("userId", getCurrentUserID())
										.setMaxResults(1)
										.getSingleResult();
		} catch (Exception e) {
			logger.warn("No Settings for UserID: " + getCurrentUserID()+ " found. " + e.getLocalizedMessage());
			return null;
		}
    }

    /* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.beans.UserManagementInterface#saveSettings(lu.tudor.santec.gecamed.usermanagement.ejb.entity.Setting)
	 */
    @RolesAllowed("gecam")
    public Setting saveSettings(Setting setting)  {
    	
    	Setting s = getSettings();
    	if (s != null) {
    		s.setSettingData(setting.getSettingData());
    		setting = s;
    	}
    	
    	return em.merge(setting);
    }

    /* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.beans.UserManagementInterface#getUser(java.lang.Integer)
	 */
    @RolesAllowed("gecam")
    public GecamedUser getUser(Integer id)
    {
        return (GecamedUser) em.find(GecamedUser.class, id);
    }

    
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#getModulePermissions(java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	public List <Permission> getModulePermissions (String p_ModuleName)
		{
		List <Permission> 	l_Permissions = null;
		
		l_Permissions = em.createNamedQuery("getAllPermissionsByModule")
						 .setParameter ("module", p_ModuleName + ".%")
						 .getResultList();
	
		return l_Permissions;
		}

	/**
	 * Fetches names of all permissions defined for specified module and granted to specified user
	 * @param p_ModuleName : specifies the name of the module to get permissions of
	 * @param p_UserId     : specifies the id of the user to get permissions for
	 * @return a list of permission names defined for the specified module and granted to the specified
	 * user. If no permissions were defined or none were granted to user, <code>null</code> will
	 * be returned.
	 */
	
	@SuppressWarnings("unchecked")
	public Collection <String> getModulePermissions (String p_ModuleName, Integer p_UserId)
		{
		Collection <String> 	l_Permissions = null;
	
		if (p_UserId == null) return l_Permissions;
		
		try	{
			l_Permissions = em.createQuery (MODULE_PERMISSIONS_FOR_USER)
						 	  .setParameter ("moduleName", p_ModuleName + ".%")
						 	  .setParameter ("userId", p_UserId)
						 	  .getResultList();
			}
		catch (NoResultException p_Exception)
			{
			l_Permissions = null;
			}
		
		return l_Permissions;
		}

	/**
	 * Returns the roles offered by this module
	 * 
	 * @param moduleName
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Role> getModuleRoles(String moduleName) {
		/* ================================================== */
		// create a query for roles
		/* ------------------------------------------------------- */
		Query q = em.createQuery("SELECT OBJECT (o) FROM Role o WHERE o.name LIKE :name");
		q.setParameter("name", moduleName + ".%");
		try {
			/* --------------------------------------------- */
			List<Role> result =  q.getResultList();
			return result;
			/* --------------------------------------------- */
		} catch (Exception e) {
			/* --------------------------------------------- */
			e.printStackTrace();
			/* --------------------------------------------- */
		}
		return null;
		/* ================================================== */
	}

	/**
	 * Fetches names of all roles defined for specified module and granted to specified user
	 * @param p_ModuleName : specifies the name of the module to get roles of
	 * @param p_UserId     : specifies the id of the user to get roles for
	 * @return a list of role names defined for the specified module and granted to the specified
	 * user. If no roles were defined or none were granted to user, <code>null</code> will
	 * be returned.
	 */

	@SuppressWarnings("unchecked")
	public Collection<String> getModuleRoles (String p_ModuleName, Integer p_UserId)
		{
		Collection <String> 	l_Roles = null;
	
		if (p_UserId == null) return l_Roles;
		
		try	{
			l_Roles = em.createQuery (MODULE_ROLES_FOR_USER)
						.setParameter ("moduleName", p_ModuleName + ".%")
						.setParameter ("userId", p_UserId)
						.getResultList();
			}
		catch (NoResultException p_Exception)
			{
			l_Roles = null;
			}
		
		return l_Roles;
		}
	
	

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#userHasPermission(lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser, java.lang.Integer)
	 */
	@SuppressWarnings("unchecked")
	public Boolean userHasPermission (GecamedUser p_User, Integer p_PermissionId) throws Exception
		{
		Integer				l_UserID;
		Query				l_Query;
		String				l_QueryString;
		List <Integer> 		l_Permissions;
	
		if (p_User == null) return false;
	
		l_UserID = p_User.getId();
	
		// Assemble the Query of Death...
		// The Query checks in one go whether a given permission has been granted
		// to user either via an assigned role or via an explicit permission grant.
		// The Query will return one or more permission objects with the sought ID in
		// case the user has the permission, or nothing if the user doesn't have it
	
		l_QueryString =
	
			"SELECT id FROM Permission WHERE id = :permissionid AND " +
			"(id IN " +
				"(Select permission.id FROM RolePermission WHERE role.id IN " +
		         	"(Select role.id FROM UserRole WHERE user.id = :userid))" +
		    "OR id IN " +
			"(Select permission.id FROM UserPermission WHERE user.id = :userid))";
	
		try	{
			l_Query = em.createQuery(l_QueryString);
			l_Query.setParameter("permissionid", p_PermissionId);
			l_Query.setParameter("userid",       l_UserID);
	
			l_Permissions = l_Query.getResultList();
			}
		catch (NoResultException p_Exception)
			{
			l_Permissions = null;
			}
	
		if ((l_Permissions != null) && (l_Permissions.size() > 0)) return Boolean.TRUE;
														   else return Boolean.FALSE;
		}
	
	//---------------------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#userHasPermission(java.lang.Integer)
	 */
	public Boolean userHasPermission (Integer p_PermissionId) throws Exception
		{
		return this.userHasPermission(this.getCurrentUser(),p_PermissionId);
		}
	
	//---------------------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#userHasPermission(lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser, java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	public Boolean userHasPermission (GecamedUser p_User, String p_PermissionName) throws Exception
		{
		Integer				l_UserID;
		Query				l_Query;
		String				l_QueryString;
		List <Integer> 		l_Permissions;
	
		if (p_User == null) return false;
	
		l_UserID = p_User.getId();
	
		// Assemble the Query of Death...
		// The Query checks in one go whether a given permission has been granted
		// to user either via an assigned role or via an explicit permission grant.
		// The Query will return one or more permission objects with the sought ID in
		// case the user has the permission, or nothing if the user doesn't have it
	
		l_QueryString =
	
		"SELECT id FROM Permission WHERE name = :permissionname AND " +
			"(id IN " +
				"(Select permission.id FROM RolePermission WHERE role.id IN " +
		         	"(Select role.id FROM UserRole WHERE user.id = :userid))" +
		    "OR id IN " +
			"(Select permission.id FROM UserPermission WHERE user.id = :userid))";
	
		try	{
			l_Query = em.createQuery(l_QueryString);
			l_Query.setParameter("permissionname", 	p_PermissionName);
			l_Query.setParameter("userid",   		l_UserID);
	
			l_Permissions = l_Query.getResultList();
			}
		catch (NoResultException p_Exception)
			{
			l_Permissions = null;
			}
	
		if ((l_Permissions != null) && (l_Permissions.size() > 0)) return Boolean.TRUE;
														   else return Boolean.FALSE;
		}
	
	//---------------------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#userHasPermission(java.lang.String)
	 */
	public Boolean userHasPermission (String p_PermissionName) throws Exception
		{
		return this.userHasPermission(this.getCurrentUser(),p_PermissionName);
		}
	
	//---------------------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#userHasRole(lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser, java.lang.Integer)
	 */
	public Boolean userHasRole (GecamedUser p_User, Integer p_RoleId) throws Exception
		{
		Integer		l_UserID;
		UserRole		l_UserRole;
	
		if (p_User == null) return false;
	
		l_UserID = p_User.getId();
	
		try	{
			l_UserRole = (UserRole) em.createNamedQuery("getUserRole")
									  .setParameter ("roleid", p_RoleId)
									  .setParameter ("userid", l_UserID)
									  .getSingleResult();
			}
		catch (NoResultException p_Exception)
			{
			l_UserRole = null;
			}
	
		if (l_UserRole != null) return Boolean.TRUE;
						  else return Boolean.FALSE;
		}
	
	//---------------------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#userHasRole(java.lang.Integer)
	 */
	public Boolean userHasRole (Integer p_RoleId) throws Exception
		{
		return this.userHasRole(this.getCurrentUser(),p_RoleId);
		}
	
	//---------------------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#userHasRole(lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser, java.lang.String)
	 */
	public Boolean userHasRole (GecamedUser p_User, String p_Role) throws Exception
		{
		Integer			l_UserID;
		String			l_QueryString;
		Query			l_Query;
		Integer			l_RoleId;
	
		if (p_User == null) return false;
	
		l_UserID = p_User.getId();
	
		l_QueryString = "SELECT id FROM Role WHERE name = :rolename AND " +
						"id IN " +
							"(Select role.id FROM UserRole WHERE user.id = :userid)";
	
		try	{
			l_Query = em.createQuery(l_QueryString);
			l_Query.setParameter("rolename", p_Role);
			l_Query.setParameter("userid",   l_UserID);
	
			l_RoleId = (Integer) l_Query.getSingleResult();
			}
		catch (NoResultException p_Exception)
			{
			l_RoleId = null;
			}
	
		if (l_RoleId != null) return Boolean.TRUE;
						else return Boolean.FALSE;
		}
	
	//---------------------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#userHasRole(java.lang.String)
	 */
	public Boolean userHasRole (String p_Role) throws Exception
		{
		return this.userHasRole(this.getCurrentUser(),p_Role);
		}
	
	//---------------------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#getGlobalSettings()
	 */
	public Setting getGlobalSettings() {
		try {
			return  (Setting) em.createNamedQuery("findSettingByUserID")
										.setParameter("userId", GLOBAL_SETTINGS_ID)
										.setMaxResults(1)
										.getSingleResult();
		} catch (Exception e) {
			logger.warn("No Global Settings found. " + e.getLocalizedMessage());
			return null;
		}
	}
	
	//---------------------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#saveGlobalSettings(lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.Setting)
	 */
	public Setting saveGlobalSettings(Setting setting) {
		setting.setUserId(GLOBAL_SETTINGS_ID);
		
		Setting s = getGlobalSettings();
		if (s != null) {
			s.setSettingData(setting.getSettingData());
			setting = s;
		}
		
		setting = em.merge(setting);
		
		// reset serverside cached Admin settings
		adminSettings = null;
		getAdminSettingsReader();
		
		return setting;
	}
	
	//---------------------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#getSettingsReader()
	 */
	public SettingReader getSettingsReader() {
		try {
			SettingReader sr = new SettingReader();
			Setting settings = getSettings();
			if (settings == null)
			    return null;
			ByteArrayInputStream bStream  = new ByteArrayInputStream(settings.getSettingData().getBytes());
			sr.loadSettings(bStream);
			return sr;
		} catch (Exception e) {
			logger.warn("error reading settings", e);
		}
		return null;
	}
	
	//---------------------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#getSettingValue(java.lang.String, java.lang.String)
	 */
	public Object getSettingValue(String plugin, String setting) {
		SettingReader sr = getSettingsReader();
		if (sr != null) 
			return sr.getValue(plugin, setting);
		return null;
	}
	
	//---------------------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#getAdminSettingsReader()
	 */
	public SettingReader getAdminSettingsReader() {
		if (adminSettings != null) {
			return adminSettings;
		}
		try {
			adminSettings = new SettingReader();
			Setting settings = getGlobalSettings();
			if (settings == null)
			    return null;
			ByteArrayInputStream bStream  = new ByteArrayInputStream(settings.getSettingData().getBytes());
			adminSettings.loadSettings(bStream);
			return adminSettings;
		} catch (Exception e) {
			logger.warn("error reading admin settings", e);
		}
		return null;
	}
	
	//---------------------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#getAdminSettingValue(java.lang.String, java.lang.String)
	 */
	public Object getAdminSettingValue(String plugin, String setting) {
		return getAdminSettingValue(plugin, setting, null);
	}
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#getAdminSettingValue(java.lang.String, java.lang.String)
	 */
	public Object getAdminSettingValue(String plugin, String setting, Object defaultVal) {
		if (adminSettings == null) {
			getAdminSettingsReader();			
		}
		
		Object val = null;
		try {
			if (adminSettings != null) 
				val=  adminSettings.getValue(plugin, setting);			
		} catch (Exception e) {
			logger.warn("error reading admin setting: " +  plugin + " " + setting);
		}
		if (val == null) {
			val = defaultVal;
		}
		
		return val;
	}
	
	//---------------------------------------------------------------------------

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#getInfos(java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	public Collection<GecamedInfo> getInfos(String key)  throws Exception{
		return (Collection<GecamedInfo>) em.createNamedQuery(GecamedInfo.FIND_INFOS_BY_KEY).setParameter("key", key).getResultList();
	}
	
	//---------------------------------------------------------------------------
	

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#getInfo(java.lang.String)
	 */
	public GecamedInfo getInfo(String key) throws Exception {
		try {
		return (GecamedInfo) em.createNamedQuery(GecamedInfo.FIND_LATEST_INFO_BY_KEY).setParameter("key", key).getResultList().get(0);
		} catch (Exception e) {
		    logger.info("Key: " + key + " not found in core.info...");
		    return null;
		}
	}
	
	//---------------------------------------------------------------------------
	

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#setInfo(lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedInfo)
	 */
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public void setInfo(GecamedInfo info) {
		/* ================================================== */
		if (info == null || info.getKey() == null || "".equals(info.getKey()))
			return;
		/* ------------------------------------------------------- */
		try {
			/* --------------------------------------------- */
			em.merge(info);
			/* --------------------------------------------- */
		} catch (Exception e) {
			/* --------------------------------------------- */
			e.printStackTrace();
			/* --------------------------------------------- */
		}
		/* ================================================== */
	}

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#getDatabaseInfo()
	 */
	public String getDatabaseInfo() {
		try {
			Context ic = new InitialContext();
			DataSource  ds = (DataSource)ic.lookup("java:/gecamdb");
			Connection c = ds.getConnection();
			return c.getMetaData().getURL();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#getDatabaseInfo()
	 */
	public String getDatabaseServerVersion() {
		try {
			Object result = em.createNativeQuery("SHOW server_version;").getSingleResult();
			return result + "";
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	
	public String getServerLog() {
	    return ServerConfig.getServerLog();
	}
	

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#getAllUsers()
	 */
	@SuppressWarnings("unchecked")
	public Collection<GecamedUser> getAllUsers() {
		try {
			return em.createNamedQuery("findAllGecamedUsers").getResultList();			
		} catch (Exception e) {
			return null;
		}
	}

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#getOnlineUsers(java.lang.Integer)
	 */
	public Collection<GecamedUser> getOnlineUsers(Integer siteID) {
	    // find old users 
	    long minuteAgo = System.currentTimeMillis() - 60000;
	    Collection<GecamedUser> users = new ArrayList<GecamedUser>();
	    for (GecamedUser user : onlineUsers.keySet()) {
		long lastKeepalive = onlineUsers.get(user);
		if (lastKeepalive < minuteAgo) {
		    users.add(user);
		}
	    }
	    
	    // delete old users from list
	    for (GecamedUser gecamedUser : users) {
		onlineUsers.remove(gecamedUser);
	    }
	    
	    // only return users with siteID
	    users = new ArrayList<GecamedUser>();
	    for (GecamedUser gecamedUser : onlineUsers.keySet()) {
		if (siteID == null) {
		    users.add(gecamedUser);
		} else if (siteID.equals(gecamedUser.getSiteID())) {
		    users.add(gecamedUser);
		}
	    }
	    return users;
	}

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface#isOnline(lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser)
	 */
	public void iAmOnline(GecamedUser user) {
	    onlineUsers.remove(user);
	    onlineUsers.put(user, System.currentTimeMillis());
	}

	public void iAmOffline(GecamedUser user) {
	    onlineUsers.remove(user);
	}
	
	
	public String getJavaVersion ()
	{
		return System.getProperty("java.version");
	}
	
	
	public TimeZoneCheck getTimeZoneCheck ()
	{
		return new TimeZoneCheck();
	}


//	@PostConstruct
//	public void postConstruct () {
//	    instanceNr++;
//	    logger.info("LoginBean postConstruct instances: " + instanceNr);
//	}
//	
//	
//	@PreDestroy
//	public void preDestroy () {
//	    instanceNr--;
//	    logger.info("LoginBean preDestroy instances: " + instanceNr);
//	}
}
