#ifndef _event_consumer_hh_
#define _event_consumer_hh_

// 	Copyright 11/07/01 Sun Microsystems, Inc. All Rights Reserved.

#pragma ident  "@(#)event_consumer.hh	1.12 01/11/07 Sun Microsystems"

#include <cgw_utils/cgw_utils.hh>
#include <sem_threads/sem_thrpool.hh>
#include <cgw_utils/ts_ptr_hash_table.hh>
#include <cgw_utils/cgw_exceptions.hh>

#include <rw/cstring.h>
#ifdef ORBACUS
#include <CosEventComm_skel.h>
#include <jidm/JIDM.h>
#include <Any.h>
#else
#ifdef ORBIX
#include <CosEventCommS.hh>
#include <jidm/JIDM.hh>
#else
#include <CosEventComm_s.hh>
#include <jidm/JIDM_c.hh>
#include <any.h>
#endif
#endif

#include <pmi/asn1_val.hh>
#include <pmi/message.hh>
/*******************************************************************************
** EventConsumer is the intermediary between EDS and CORBA event consumer. In
** other words, it is a consumer to EDS and a supplier to CORBA event consumer.
*/

class EventConsumer
    : public  POA_CosEventComm::PushSupplier
{
  public:
    /*
    ** get_consumer() will return a pointer to EventConsumer that MUST NOT be
    ** deleted. get_consumer() may trigger a remote method invocation on
    ** EventPortRegistry and EventPort CORBA objects, if the consumer is not in
    ** the local cache. If the consumer doesn't exist, then it throws
    ** JIDM::NoEventPort exception. If the remote invocation has problems, it
    ** throws CORBA::SystemException.  */

    static EventConsumer* const
    get_consumer(
	const RWCString& ae_title
    ) throw (
	JIDM::InvalidCriteria,
	JIDM::NoEventPort,
	GeneralPMIException,
	CORBA::SystemException,
    	SEMTHRInvalidPointer
    );

    static void remove_consumer(
		const RWCString& ae_title
    ) throw();
    static void disconnect_all_consumers() throw();

    ~EventConsumer() throw();

    /*
    ** push() will schedule the delivery of the event to the consumer. It does
    ** not necessarily result in the immediate delivery of the event to the
    ** consumer.
    */

    void
    push(
	const CORBA::Any& any_event
    ) throw();
    void EventConsumer::push(
    EventReq& event_msg,bool convert) throw();

    /*
    ** disconnect_push_supplier() is the method from PushSupplier interface. It
    ** will be invoked when the CORBA event consumer disconnects from this
    ** supplier.
    */
  
    void
    disconnect_push_supplier() throw (CORBA::SystemException);

    bool
    wants_text_events() const throw();

    const Asn1Value&
    get_user_id() const throw();

  private:
    static TSPtrHashTable<RWCString, EventConsumer> consumer_list_;
    
    bool cleanup_started;
    Asn1Value user_id_;
    RWCString ae_title_;
    bool want_text_events_;
    JIDM::EventPort_var event_port_;
    CosEventChannelAdmin::ProxyPushConsumer_var consumer_;

    // event_scheduler_ ensures ordered delivery of events to the consumer.
    //SyncTaskScheduler event_scheduler_;
	SemThreadPool* event_scheduler_;

    //RWPCValQueue<CORBA::Any> event_q_;
    //SemThSafeQueue<CORBA::Any> event_q_;	

    EventConsumer(
	const RWCString& ae_title,
	const JIDM::EventPort_var& event_port
    )  throw(
	JIDM::InvalidCriteria,
	CORBA::SystemException,
	GeneralPMIException,
	SEMTHRInvalidPointer
    );

    Asn1Value
    extract_user_id(
	const JIDM::Criteria& access_criteria
    ) throw (
	JIDM::InvalidCriteria,
	GeneralPMIException,
	SEMTHRInvalidPointer,
	CORBA::SystemException
    );
    

    /*
    ** cleanup() will shutdown the internal event scheduler and destroy this
    ** object.
    */
    void
    cleanup() throw();
    
    // suppress explicitly
    EventConsumer();
    EventConsumer(const EventConsumer&);
    EventConsumer& operator=(const EventConsumer&);
    
    static void
    convert_event_to_idl_any(
        EventReq& event_msg,
        CORBA::Any& any_event
    ) throw (GeneralPMIException, MTEMException);

    static void
    convert_event_to_idl_text(
        EventReq& event_msg,
        CORBA::Any& text_event
    ) throw (GeneralPMIException, MTEMException);
};

class CorbaEvent:  public SemTask
{
    public:

	static CorbaEvent *mkCorbaEvent(CosEventChannelAdmin::ProxyPushConsumer_var& consumer,const RWCString &ae_title,const  CORBA::Any &any_event);

    // Implementation of the Task Interface virtual method.
    // This will do a push of the event and clean itself
	void execute() throw();

	~CorbaEvent(){  };

    private:

	CorbaEvent(CosEventChannelAdmin::ProxyPushConsumer_var& consumer, const RWCString &ae_title,const CORBA::Any &any_event):ae_title_(ae_title),event(any_event)
	{
		consumer_=CosEventChannelAdmin::ProxyPushConsumer::_duplicate(consumer);	
	};
    // suppress explicitly
    	CorbaEvent();
    	CorbaEvent(const CorbaEvent&);
    	CorbaEvent& operator=(const CorbaEvent&);

    	RWCString ae_title_;
    	CosEventChannelAdmin::ProxyPushConsumer_var consumer_;
    	CORBA::Any event;
};

/******************************************************************************/
inline
CorbaEvent * CorbaEvent::mkCorbaEvent(CosEventChannelAdmin::ProxyPushConsumer_var& consumer, const RWCString &ae_title, const CORBA::Any &any_event)
{
	return  new CorbaEvent(consumer, ae_title,any_event);
}

inline
bool
EventConsumer::wants_text_events() const throw()
{
    return want_text_events_;
}

inline
const Asn1Value&
EventConsumer::get_user_id() const throw() 
{
    return user_id_;
}

/******************************************************************************/
#endif // _event_consumer_hh_
