/* -*- c++ -*- */
#ifndef _sigc_eventsignals_h_
#define _sigc_eventsignals_h_
#ifdef  USE_SIGCPLUSPLUS 

#include <sigc++/signal_system.h>
#include <vdk/sigc_events.h>
using namespace SigC;

/*!
  \class VDKRawEventSignal
  \brief raw event ala gdk
  This signal we deliver every GdkEvent the object receives directly
  to you. Normaly you should use the specialised eventsignals delivering
  you a more comfortable VDKEvent (what uses much less resources and
  is typesafe).
*/
class VDKRawEventSignal : public VDKSignal1<void, const GdkEvent *>,
			  private VDKNotCopyAble
{
public:
     VDKRawEventSignal(VDKObject*);
     ~VDKRawEventSignal();
     Connection connect(const Slot1<void, const GdkEvent*>&);
     Connection connect(const Slot2<void, VDKObject*, const GdkEvent *>&);
     void disconnect(Connection&);
     
private:
     VDKObject* _obj;
     guint _handler_id;
     static gint event_handler(GtkObject* wid, GdkEvent* eve, gpointer obj);
};

/* here generic eventsignals begin */

/* not used in user-land */
typedef enum{
     BUTTON_PRESS,
     BUTTON_RELEASE,
     FOCUS_KEY_IN,
     FOCUS_KEY_OUT,
     FOCUS_POINTER_IN,
     FOCUS_POINTER_OUT,
     GEOMETRY,
     KEY_PRESS,
     KEY_RELEASE,
     MAPEVENT,
     PAINT,
     POINTER_MOVE,
     POINTER_PRESSED
} W2_TraitEnum;

/** Specify on what of the following event-subtypes you are interested:
 *  FULLY_VISIBILE: The object got completely unmaped
 *  PRATIAL_VISIBLE: The object got partialy maped
 *  NOT_VISBLE: The object got completely maped 
*/
// typedef enum{
//      ME_FULLY_VISIBLE,
//      ME_PARTIAL_VISIBLE,
//      ME_NOT_VISIBLE
// } VDKMapEventFilter;
typedef VDKMapState VDKMapEventFilter;

/*!
 *  \enum VDKButtonEventFilter
 *  Specify on what of the following event-subtypes you are interested:
 *  \arg BE_RELEASE Mousebutton was released
 *  \arg BE_PRESS   Mousebutton was pressed  
 *  \arg BE_CLICK2  Double click
 *  \arg BE_CLICK3  Triple click 
 *  \sa VDKButtonEvent
 */

typedef enum{
     BE_RELEASE,
     BE_PRESS,
     BE_CLICK2,
     BE_CLICK3
} VDKButtonEventFilter;



/*!
 * \enum VDKKeyEventFilter
 *  Specify on what of the following event-subtypes you are interested:
 *  \arg KE_RELEASE: key was released
 *  \arg KE_PRESS:   key was pressed  
 */
typedef enum{
     KE_RELEASE,
     KE_PRESS
} VDKKeyEventFilter;

/** Specify on what of the following event-subtypes you are interested:
 *  FOCUS_IN: Object got this kind of focus
 *  FOCUS_OUT: Object lost this kind of focus
 *  @see VDKKeyFocus
 *  @see VDKMouseFocus
 */
typedef enum{
     FE_IN,
     FE_OUT
} VDKFocusEventFilter;

/** Specify on what of the following event-subtypes you are interested:
 *  ALL: Every pointer move, regardless of any modifier's state
 *  PRESSED: Register pointer moves only while any modifier was pressed
 *  @see VDKPointerSignal
 */
typedef enum{
     PE_ALL,
     PE_PRESSED
} VDKPointerEventFilter;



/* *******************************************************************
 * ******* Different Trait classes for template instantiation  *******
 * ******************************************************************/
template<W2_TraitEnum id, int scount=0>
class W2_Trait
{
public:
     typedef GdkEvent ge_type;    // Subclass of GdkEvent to dispatch
     typedef int T_vcmp;          // Filter-parameter-type
     typedef GdkEventType T_gcmp; // Event-filter-type (must be 
                                  // convertible to int!)
     static const char* signame;      // Name to connect
     static T_gcmp Field(GdkEvent* eve)
     {return eve->type;}
};

template<W2_TraitEnum id>
class W2_Trait<id, 1>
{
public:
     typedef GdkEvent ge_type;
     typedef int T_vcmp;
     typedef GdkEventType T_gcmp;
     static const int s_count;
     static const char* signame;
     static T_gcmp Field(GdkEvent* eve);
     static const T_vcmp EN1;
     static const T_gcmp GN1;
};

template<W2_TraitEnum id>
class W2_Trait<id,2>
{
public:
     typedef GdkEvent ge_type;
     typedef int T_vcmp;
     typedef GdkEventType T_gcmp;
     static const int s_count;
     static const char* signame;
     static T_gcmp Field(GdkEvent* eve);
     static const T_vcmp EN1;
     static const T_gcmp GN1;
     static const T_vcmp EN2;
     static const T_gcmp GN2;
};

template<W2_TraitEnum id>
class W2_Trait<id,3>
{
public:
     typedef GdkEvent ge_type;    // Subclass of GdkEvent to dispatch
     typedef int T_vcmp;          // Filter-parameter-type
     typedef GdkEventType T_gcmp; // Event-filter-type (must be 
                                  // convertible to int!)
     static const int s_count; // Anzahl der Signal-Objekte
     static const char* signame;      // Name to connect
     static T_gcmp Field(GdkEvent* eve)
     {return eve->type;}
     static const T_vcmp EN1;
     static const T_gcmp GN1;
     static const T_vcmp EN2;
     static const T_gcmp GN2;
     static const T_vcmp EN3;
     static const T_gcmp GN3;
};

#include <vdk/sigc_eventtraits.h>

/* *******************************************************************
 * *        DirectEventSignal                                        *
 * *Simple Eventsignal, has one connection and no filtering parameter*
 * ******************************************************************/
// Second parameter to reduce number of traits
template<W2_TraitEnum id, class T_vevent>
class DirectEventSignal : public VDKSignal1<void, const T_vevent &>
{
     int _handler_id;
     static void event_handler(GtkObject*, GdkEvent*, gpointer obj);
     VDKObject* _sender;
     typedef W2_Trait<id> T_trait;
public:
     DirectEventSignal(VDKObject* sender) : _handler_id(0),_sender(sender) {}
     ~DirectEventSignal();
     Connection connect(const Slot2<void,VDKObject*,const T_vevent &>&);
     Connection connect(const Slot1<void, const T_vevent &>&);
     void disconnect(Connection& con);
};

/* *******************************************************************
 * * SignalWrapperStage2Base template                                *
 * * Provides basefunctionality for SignalWrapperStage2-class        *
 * ******************************************************************/
template<W2_TraitEnum id, class T_vevent, int s_count, class trait>
class SignalWrapperStage2Base
{
     typedef W2_Trait<id> Trait;
     typedef W2_Trait<id>::T_vcmp T_vcmp;
     typedef W2_Trait<id>::T_gcmp T_gcmp;     
     int _handler_id; // holds gdksigc-connection id
     VDKObject* _sender;
     VDKSignal1<void,const T_vevent& > sig_vec[s_count];
     static void event_handler(GtkObject*, GdkEvent*, gpointer obj);
public:
     SignalWrapperStage2Base(VDKObject* obj)
	  : _handler_id(0), _sender(obj) {}
     ~SignalWrapperStage2Base();
     // Überprüft alle  internen Verbindungen und hebt ggf. die
     // gtksigc-Verbindung auf.
     void cleanup();
     void disconnect(Connection&);
     Connection connect(const Slot2<void,VDKObject*,const T_vevent &>&,
			T_vcmp spec);
     Connection connect(const Slot1<void,const T_vevent &>&, T_vcmp spec);
     bool empty()const;
     bool responsible(T_vcmp spec) const;
};

template<W2_TraitEnum id, class T_vevent, int s>
class SignalWrapperStage2
{
     typedef W2_Trait<id> Trait;
     typedef Trait::T_vcmp T_vcmp;
     typedef Trait::T_gcmp T_gcmp;

public:
     SignalWrapperStage2(VDKObject* obj);
};

/* Acts as factroy at the same time */
template<W2_TraitEnum id, class T_vevent>
class SignalWrapperStage2<id,T_vevent,1>
     : public SignalWrapperStage2Base<id,T_vevent,1, SignalWrapperStage2<id,T_vevent,1> > 
{
     typedef W2_Trait<id> Trait;
     typedef W2_Trait<id>::T_vcmp T_vcmp;
     typedef W2_Trait<id>::T_gcmp T_gcmp;

     friend class SignalWrapperStage2Base<id, T_vevent,1, SignalWrapperStage2<id,T_vevent,1> >;
     static int vdk2vec(T_vcmp);
     static int eve2vec(GdkEvent* eve);
public: /* ??? */
     SignalWrapperStage2(VDKObject* obj)
	  : SignalWrapperStage2Base<id, T_vevent,1, SignalWrapperStage2<id,T_vevent,1> >(obj)
     {}
};

template<W2_TraitEnum id, class T_vevent>
class SignalWrapperStage2<id,T_vevent,2>
     : public SignalWrapperStage2Base<id,T_vevent,2, SignalWrapperStage2<id,T_vevent,2> >
{     
     typedef W2_Trait<id> myTrait;
     typedef myTrait::T_vcmp T_vcmp;
     typedef myTrait::T_gcmp T_gcmp;
     friend class SignalWrapperStage2Base<id,T_vevent,2,SignalWrapperStage2<id,T_vevent,2> >;
     static int vdk2vec(T_vcmp);
     static int eve2vec(GdkEvent* eve);
public: /* ??? */
     SignalWrapperStage2(VDKObject* obj)
	  : SignalWrapperStage2Base<id,T_vevent,2, SignalWrapperStage2<id,T_vevent,2> >(obj)
     {}
};

template<W2_TraitEnum id, class T_vevent>
class SignalWrapperStage2<id,T_vevent,3> 
     : public SignalWrapperStage2Base<id,T_vevent,3, SignalWrapperStage2<id,T_vevent,3> >
{
     typedef W2_Trait<id> myTrait;
     typedef myTrait::T_vcmp T_vcmp;
     typedef myTrait::T_gcmp T_gcmp;
     friend class SignalWrapperStage2Base<id,T_vevent, 3, SignalWrapperStage2<id,T_vevent,3> >;
     static int vdk2vec(T_vcmp);
     static int eve2vec(GdkEvent* eve);
public: /* ??? */
     SignalWrapperStage2(VDKObject* obj)
	  : SignalWrapperStage2Base<id,T_vevent,3, SignalWrapperStage2<id,T_vevent,3> >(obj)
     {}
};

/* **************************************************************************
 * ***               SignalWrapperStage1M2                                ***
 * *************************************************************************/
template<W2_TraitEnum id1, int s_count1, W2_TraitEnum id2, int s_count2, class T_vevent>
class SignalWrapperStage1M2
{
private:
     typedef W2_Trait<id1> Trait1;
     typedef W2_Trait<id2> Trait2;
     typedef Trait1::T_vcmp T_vcmp;
     SignalWrapperStage2<id1, T_vevent, s_count1> swrap1;
     SignalWrapperStage2<id2, T_vevent, s_count2> swrap2;
public:
     SignalWrapperStage1M2(VDKObject* obj)
	  : swrap1(obj), swrap2(obj){}
     bool empty() const;
     Connection connect(const Slot2<void, VDKObject*, const T_vevent&>& sl,
			T_vcmp spec);
     Connection connect(const Slot1<void, const T_vevent&>& sl, T_vcmp spec);
     void disconnect(Connection& con);
};

/* ************************************************************************
 * ***              Definition of different signals                     ***
 * ***********************************************************************/
typedef SignalWrapperStage1M2<BUTTON_PRESS,3, BUTTON_RELEASE, 1, VDKMouseEvent> 
        VDKButtonSignal;
typedef SignalWrapperStage1M2<FOCUS_KEY_IN,1, FOCUS_KEY_OUT,1, VDKKeyFocusEvent> 
        VDKKeyFocusSignal;
typedef SignalWrapperStage1M2<FOCUS_POINTER_IN,1, FOCUS_POINTER_OUT,1, VDKMouseFocusEvent>
        VDKPointerFocusSignal;
typedef SignalWrapperStage1M2<KEY_PRESS,1, KEY_RELEASE,1, VDKKeyEvent>
        VDKKeySignal;
typedef SignalWrapperStage1M2<POINTER_PRESSED,1, POINTER_MOVE,1, VDKMouseEvent>
        VDKPointerSignal;
typedef SignalWrapperStage2<MAPEVENT, VDKMapEvent, 3>
        VDKMapSignal;
typedef DirectEventSignal<GEOMETRY,VDKGeometryEvent>
        VDKGeometrySignal;
typedef DirectEventSignal<PAINT,VDKPaintEvent>
        VDKPaintSignal;

#endif /* USE_SIGCPLUSPLUS */
#endif /* !_sigc_eventsignals_h_ */
