package com.idtect.detector.message;

import java.util.*;
import javax.jms.*;
import org.apache.commons.messagelet.impl.*;
import org.apache.commons.messenger.*;
import org.apache.log4j.Logger;

/**
 * @author michael
 *
 * To change this generated comment edit the template variable "typecomment":
 * Window>Preferences>Java>Templates.
 * To enable and disable the creation of type comments go to
 * Window>Preferences>Java>Code Generation.
 */
public class MessageManager {

  private static Logger log = Logger.getLogger(MessageManager.class.getName());

  public MessageManager() {}
  
  private MessengerManager manager;
  protected MessengerManager getManager() {return manager;}
  protected void setManager(MessengerManager manager) {this.manager = manager;}
  
  private SubscriptionList subscriptionList;
  
  protected MessengerManager createMessengerManager() throws Exception {
    String config = "file:///C|/idtect/projects/detector/bin/Messenger.xml";

    log.info( "Creating the Messenger connections from the file: " + config );
    
    try {
      return MessengerManager.load( config );
    }
    catch (JMSException e) {
        log.warn( "Could not parse Messenger connection XML deployment document for URL: " + config, e );
        throw new Exception(
            "Could not parse Messenger connection XML deployment document for URL: " + config
            + " reason: " + e, e
        );
    }
  }

  protected SubscriptionList createSubscriptionList() throws Exception {
    String config = "file:///C|/idtect/projects/detector/bin/subscriptions.xml";
    
    log.info( "Loading the Messenger subscriptions from: " + config );
    
    try {
      SubscriptionDigester digester = new SubscriptionDigester();
      return (SubscriptionList) digester.parse( config );
    }
    catch (Exception e) {
      log.fatal( "Could not parse Messenger subscription XML deployment document for URL: " + config, e );
      
      throw new Exception(
          "Could not parse Messenger subscription XML deployment document for URL: " + config
          + " reason: " + e, e
      );
    }
  }

  public Messenger getMessenger(String name) throws Exception {
    MessengerManager messengerManager = getManager();
    if ( messengerManager == null ) {
        throw new Exception( "No MessengerManager has been initialized yet" );
    }
    return messengerManager.getMessenger( name );
  }

  protected void subscribe( SubscriptionList list ) throws Exception {
    for (Iterator iter = list.getSubscriptions().iterator(); iter.hasNext(); ) {
      Subscription subscription = (Subscription) iter.next();
      subscribe( subscription );
    }
  }

  protected void subscribe( Subscription subscription ) throws Exception {
    String name = subscription.getConnection();
    Messenger messenger = getMessenger( name );
    if ( messenger == null ) {
        throw new Exception( "No such Messenger called: " + name + " for subscription: " + subscription );
    }
    MessageListener listener = null;
    String servlet = subscription.getServlet();

    listener = subscription.getMessageListener();
    if ( listener == null ) {
        throw new Exception( "No MessageListener is defined for subscription: " + subscription );
    }
    
    /*
     * THIS ISN'T USED OUTSIDE A SERVLET ENGINE
     * 
    // if its an MDO the initialise it!
    if ( listener instanceof MessageDrivenObject ) {
        MessageDrivenObject mdo = (MessageDrivenObject) listener;
        if ( mdo instanceof MessengerMDO ) {
            MessengerMDO messengerMDO = (MessengerMDO) mdo;
            messengerMDO.setMessenger( messenger );
            messengerMDO.setMessengerManager( getMessengerManager() );
        }
        mdo.init( getServletContext() );
    }
    */
    
    String subject = subscription.getSubject();
    if ( subject == null || subject.length() == 0 ) {
        throw new Exception( "No destination defined for subscription: " + subscription );
    }
    
    Destination destination = null;        
    try {
        destination = messenger.getDestination( subject );
    }
    catch (JMSException e) {
        throw new Exception( "Could not create destination for name: " + subject + " for subscription: " + subscription, e );
    }
    if ( destination == null ) {
        throw new Exception( "No destination could be found for name: " + subject + " for subscription: " + subscription );
    }

    // #### at this point we may wish to create a thread pool of multiple threads
    // #### each consuming from the same Destination in parallel
    
    try {
        String selector = subscription.getSelector();
        if ( selector != null && selector.length() > 0 ) {
            log.info( "Subscribing to messenger: " + name + " destination: " + subject + " selector: " + selector );
            
            messenger.addListener( destination, selector, listener );
        }
        else {
            log.info( "Subscribing to messenger: " + name + " destination: " + subject );
            
            messenger.addListener( destination, listener );
        }
    }
    catch (JMSException e) {
        throw new Exception( "Could not subscribe to destination:" + destination + " for subscription: " + subscription, e );
    }
  }
    
  public void init() throws Exception {
    // ensure Messenger is initialised
    manager = createMessengerManager();
    setManager( manager );

    // load the subscriptions....
    SubscriptionList list = createSubscriptionList();
    subscribe( list );
    setSubscriptionList( list );
    
    // now lets start all the connections...
    for (Iterator iter = manager.getMessengerNames(); iter.hasNext(); ) {
        String name = (String) iter.next();
        Messenger messenger = manager.getMessenger( name );
        try {
            messenger.getConnection().start();
        }
        catch (JMSException e) {
            log.warn( "Caught exception trying to start messenger: " + name + ". Exception: " + e, e );
        }
    }
  }

  /**
   * Returns the subscriptionList.
   * @return SubscriptionList
   */
  public SubscriptionList getSubscriptionList() {
    return subscriptionList;
  }

  /**
   * Sets the subscriptionList.
   * @param subscriptionList The subscriptionList to set
   */
  public void setSubscriptionList(SubscriptionList subscriptionList) {
    this.subscriptionList = subscriptionList;
  }

}

