#ifndef ADS_FASTSLOTS_H_
#define ADS_FASTSLOTS_H_

#include <QVector>

extern void* ads_fastslot_receiver_;


#define ADS_FASTSLOT_VTYPE_ QVector

#define ADS_SIGNAL(name_, args_)\
class name_ ## _xx_ \
{\
public:\
  typedef void (*slot_t) args_;\
  void connect(void* const instance, slot_t slot, unsigned long update_events_mask=~0);\
  void disconnect(void* const instance, slot_t slot=0);\
  void operator() args_;\
  struct recv_\
  {\
    void* receiver;\
    unsigned long update_events_mask;\
    slot_t slot;\
  };\
  typedef ADS_FASTSLOT_VTYPE_<recv_> obs_t;\
  obs_t obs;\
  unsigned long events_pending;\
};\
name_ ## _xx_ name_

#define ADS_SIGNAL_IMPLEMENT(class_, name_, args_, args_actual_)\
void class_ :: name_ ## _xx_ :: connect(void* const instance, slot_t s, unsigned long update_events_mask)\
{\
  for(obs_t::iterator i=obs.begin(); i!=obs.end(); ++i)\
  {\
    if (i->receiver==instance && i->slot==s)\
      return;\
  }\
  recv_ tmp;\
  tmp.slot=s;\
  tmp.update_events_mask=update_events_mask;\
  tmp.receiver=instance;\
  obs.push_back(tmp);\
}\
void class_ :: name_ ## _xx_ :: disconnect(void* instance, slot_t slot)\
{\
  bool redo;\
  do {\
    redo=false;\
    for(obs_t::iterator i=obs.begin(); i!=obs.end(); ++i)\
    {\
      if (slot==0)\
      {\
        if (i->receiver==instance)\
        {\
          obs.erase(i);\
          redo=true;\
          break;\
        }\
      }\
      else if (i->receiver==instance && i->slot==slot)\
      {\
        obs.erase(i);\
        break;\
      }\
    }\
  } while(redo);\
}\
void class_ :: name_ ## _xx_ :: operator() args_\
{\
  unsigned int n__=(unsigned int)obs.size();\
  for(unsigned int i__=0; i__<n__; ++i__)\
  {\
    if (obs[i__].receiver && obs[i__].slot)\
    {\
      ads_fastslot_receiver_=obs[i__].receiver;\
      obs[i__].slot(args_actual_);\
    }\
  }\
}

#define ADS_SLOT(name_, args_)\
void name_ args_;\
static void name_ ## _wrapper_ args_;

#define ADS_SLOT_IMPLEMENT(class_, name_, args_, args_actual_)\
void class_ :: name_ ## _wrapper_ args_\
{\
  class_* const c=reinterpret_cast<class_* const>(ads_fastslot_receiver_);\
  c->name_ args_actual_;\
}\
void class_ :: name_ args_

#define ADS_SLOT_REF(name_) (name_ ## _wrapper_)
#define ADS_CONNECT(emitter_, signal_, receiver_, slot_) emitter_.signal_.connect(receiver_, ADS_SLOT_REF((*(receiver_)).slot_))
#define ads_connect(receiver_, slot_) connect(receiver_, ADS_SLOT_REF((*(receiver_)).slot_))
#define ads_connect_mask(receiver_, slot_,mask_) connect(receiver_, ADS_SLOT_REF((*(receiver_)).slot_), mask_)

#define ADS_EMIT(signal_and_args_)  (signal_and_args_)

#define ADS_EMIT_MASK(signal_, args_actual_) ADS_EMIT_MASK_VALUE(signal_.events_pending, signal_, args_actual_)

#define ADS_EMIT_MASK_VALUE(mask_val_, signal_, args_actual_)\
do {\
    unsigned int n__=(unsigned int)signal_.obs.size();\
    for(unsigned int i__=0; i__<n__; ++i__)\
    {\
      if (((mask_val_) & signal_.obs[i__].update_events_mask) && signal_.obs[i__].receiver && signal_.obs[i__].slot)\
      {\
        ads_fastslot_receiver_=signal_.obs[i__].receiver;\
        signal_.obs[i__].slot(args_actual_);\
      }\
    }\
} while(0)

#endif /*ADS_FASTSLOTS_H_*/
