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

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.ejb.FinderException;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.naming.NamingException;

import lu.tudor.santec.gecamed.core.ejb.session.interfaces.LogManager;
import lu.tudor.santec.gecamed.core.ejb.session.interfaces.MessageSenderInterface;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.UserMessage;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.UserAdminInterface;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.UserMessageInterface;

import org.apache.log4j.Category;

/**
 *
 *	This SessionBean class manages provides methods to send JMS-Messages 
 * to the GECAMed JMS Channels, on which all GECAMed-Clients are listening.
 * There channels are used to upate the client if the used data changes
 * 
 * @author Johannes Hermen johannes.hermen(at)tudor.lu
 * 
 * @Version
 * <br>$Log: MessageSenderBean.java,v $
 * <br>Revision 1.16  2012-01-24 10:34:49  ferring
 * <br>unneeded import removed
 * <br>
 * <br>Revision 1.15  2010-02-09 13:30:31  troth
 * <br>update method sendTextMessage which allows now to save usermessages in the date base usermanagement.message
 * <br>
 * <br>Revision 1.14  2008-09-25 09:43:07  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.13  2008-01-15 10:44:12  hermen
 * <br>updated Javadoc and refactured code
 * <br>
 */
@Remote({MessageSenderInterface.class})
@Stateless
public class MessageSenderBean implements MessageSenderInterface,
										  ExceptionListener
{

    @Resource (mappedName=TOPIC_NAME)
    private Topic topic;

    @Resource(mappedName=PRESCRIPTION_LIST_UPDATE_TOPIC)
    private Topic listUpdateTopic;

    @Resource(mappedName=LOG_TOPIC)
    private Topic logTopic;

    @Resource (mappedName="ConnectionFactory")
    private TopicConnectionFactory factory;
    
    @EJB
    private LoginInterface loginInterface;
    
    @EJB
    private UserAdminInterface userAdminInterface;

    @EJB
    private UserMessageInterface userMessageInterface;
    
    private static final Category m_Logger = Category.getInstance(MessageSenderBean.class.getName());

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

    private static final long serialVersionUID = 1L;

    private static int beananz = 0;
    
    /**
     * Topic for general GECAMEd updates and text messages
     */
    private static final String TOPIC_NAME = "topic/GeCam/textTopic";

    /**
     * Topic for GECAMEd prescription list updates
     */
    private static final String PRESCRIPTION_LIST_UPDATE_TOPIC = "topic/GeCam/prescriptionListUpdaterTopic";

    /**
     * Topic for GECAMEd log updates
     */
    private static final String LOG_TOPIC ="topic/GECAMed/gecamedLog";


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

    private TopicConnection conn  = null;
    private TopicSession session  = null;
    private boolean	ready 		  = false;
    
    //~ Methods ================================================================

    /**
     * Notifies all listening clients to update their list
     * by the given type
     *
     * @param type
     * @throws JMSException
     */
    public void sendPrescriptionListUpdate(int type)
        throws JMSException {
		session = conn.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
        /* ======================================================= */
        TopicPublisher send = session.createPublisher(listUpdateTopic);
        ObjectMessage om = session.createObjectMessage(type);
        send.publish(om);
        send.close();
        /* ======================================================= */
        session.close();
        
    }


    /* (non-Javadoc)
     * @see lu.tudor.santec.gecam.base.beans.session.ejb.MessageSenderSessionRemote#sendObjectMessage(java.io.Serializable)
     */
    public void sendObjectMessage(Serializable object)
        throws JMSException
    {
		session = conn.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
    	// Send a text msg
        TopicPublisher send = session.createPublisher(topic);
        ObjectMessage om = session.createObjectMessage(object);
        send.publish(om);
        send.close();
        session.close();
    }

    /* (non-Javadoc)
     * @see lu.tudor.santec.gecam.base.beans.session.ejb.MessageSenderSessionRemote#sendTextMessage(java.lang.String)
     * update method sendTextMessage which allows now to save usermessages in the date base usermanagement.message
     */
    public void sendTextMessage(String text, String receiver, boolean important)
        throws JMSException
    {
    	UserMessage userMessage = new UserMessage();
        
        //get sender_id
        userMessage.setSenderId(loginInterface.getCurrentUserID());
        
        //---------------------------------
        // save usermessage in the data base
        Collection<GecamedUser> allUsers = loginInterface.getAllUsers();
        try {
			// send message to all users
        	if(receiver.equals("ALL")){
				for (GecamedUser gecamedUser : allUsers) {
					// get receiver_id
					userMessage.setReceiverId(gecamedUser.getId());
					userMessage.setMessage(text);
					userMessage.setDate(new Date());
					userMessage.setIsRead(false);
					userMessage.setIsImportant(important);
					userMessage.setAllUser(true);
					userMessageInterface.saveUserMessage(userMessage);
				}
			}else{
				// get receiver_id
				userMessage.setReceiverId(userAdminInterface.getUser(receiver).getId());
				userMessage.setMessage(text);
				userMessage.setDate(new Date());
				userMessage.setIsRead(false);
				userMessage.setIsImportant(important);
				userMessage.setAllUser(false);
				userMessageInterface.saveUserMessage(userMessage);
			}
		} catch (NamingException e) {
			e.printStackTrace();
		} catch (FinderException e) {
			e.printStackTrace();
		}
		//---------------------------------
		
    	session = conn.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
        // Send a text msg
        TopicPublisher send = session.createPublisher(topic);
        TextMessage tm = session.createTextMessage(text);
        tm.setBooleanProperty(IMPORTANT, important);
        tm.setStringProperty(RECEIVER, receiver);
        tm.setStringProperty(SENDER, loginInterface.getCurrentUserName());
        send.publish(tm);
        send.close();
        session.close();
    }
    
    public void notify(UserMessage message) throws Exception {
    	    	
    	session = conn.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
        // Send a text msg
        TopicPublisher send = session.createPublisher(topic);
        TextMessage tm = session.createTextMessage(message.getMessage());
        tm.setBooleanProperty(IMPORTANT, message.getIsImportant());
        tm.setStringProperty(RECEIVER, getLogin(message.getReceiverId()));
        tm.setStringProperty(SENDER, getLogin(message.getSenderId()));
        send.publish(tm);
        send.close();
        session.close();
    }

    private String getLogin(Integer userID) {
    	String login = "ALL";
    	try {
    		GecamedUser u = loginInterface.getUser(userID);
			if (u != null) {
				login = u.getLogin();
			}
		} catch (Exception e) {
		}
    	return login;
    }
    
    /**
     * subscribes to the specified channel and opens a JMS connection
     *
     */
    @PostConstruct
    public void initJMS()
    {
    	beananz ++;
		try {
			conn = factory.createTopicConnection();
			conn.setExceptionListener(this);
			conn.start();
	    	m_Logger.debug("created MessageSenderBean instances: " + beananz);
		} catch (Exception e) {
			e.printStackTrace();
		}
    }

    /**
     * closes the channels and connections
     */
    @PreDestroy
    public void closeJMS()
     {
     try	{
    	 beananz--;
    	 ready = false;
    	conn.stop();
    	conn.close();
    	m_Logger.debug("destroyed MessageSenderBean instances: " + beananz);
     	} catch (Exception e) {
     		throw new EJBException(e);
     	}
     }
    
    
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.core.ejb.session.interfaces.MessageSenderInterface#sendLogUpdateMessage()
	 */
    @RolesAllowed("gecam")
	public void sendLogUpdateMessage() throws JMSException {
		session = conn.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
		/* ============================================= */
		// Send an update message to all clients
		TopicPublisher send = session.createPublisher(logTopic);
		TextMessage tm = session.createTextMessage(LogManager.UPDATE_MESSAGE);
		send.publish(tm);
		send.close();
		/* ============================================= */
		session.close();
	}
	
    /* (non-Javadoc)
     * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException)
     */
    public void onException (JMSException p_Exception) 
		{
		m_Logger.fatal ("Caught JMS Exception. Re-establishing connection!", p_Exception);
		
		try	{
			this.closeJMS();
			}
		catch (Exception e)
			{
			m_Logger.fatal ("Failed to close previous connection!",e);
			}
			
		this.initJMS();
		}

}
