/*
----------------------------------------------------------------------

PPMOC - PreProcessor Meta Object Compiler

Copyright (c) 2008 by Gael Guennebaud. (firstnamedotlastnameatgmaildotcom)

----------------------------------------------------------------------

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.

This program 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.

http://www.gnu.org/licenses/lgpl.html
----------------------------------------------------------------------
*/

#ifndef _PPMOC_H_
#define _PPMOC_H_

#include <QObject>

// re-define emit to support template inheritance
#undef emit
#define emit this->

//----------------------------------------------------------------------------------------------------
// PUBLIC API:
//----------------------------------------------------------------------------------------------------

/** A replacement for Q_OBJECT */
#define Q_OBJECT_X \
public: \
    Q_OBJECT_CHECK \
    static const QMetaObject staticMetaObject; \
    static void ppmoc_staticInitialization(void); \
    virtual const QMetaObject *metaObject() const; \
    virtual void *qt_metacast(const char *); \
    QT_TR_FUNCTIONS \
    virtual int qt_metacall(QMetaObject::Call, int, void **); \
private:


/** mimics Qt's Q_CLASSINFO
 * \code PPMOC_CLASSINFO("key","value") \endcode
 */
#define PPMOC_CLASSINFO(KEY,VALUE) ((PPMOC_CLASSINFO_ID) (KEY) (VALUE) ())

/** declares a signal
 * \param NAME name of the signal function
 * \param ARGS list of the arguments declared using PPMOC_ARG
 */
#define PPMOC_SIGNAL(NAME,ARGS) ((PPMOC_SIGNAL_ID) () (NAME) (ARGS))

/** declares a method/slot 
 * \param RETURNTYPE type returned by the method (leave it empty for void)
 * \param NAME name of the function
 * \param ARGS list of the argument sdeclared using PPMOC_ARG
 */
#define PPMOC_SLOT(RETURNTYPE,NAME,ARGS) ((PPMOC_SLOT_ID) (RETURNTYPE) (NAME) (ARGS))

/** declares a property, see Qt's Q_PROPERTY 
 * \param PROPNAME name of the property
 * \param TYPE type of the property
 * \param GET get method
 * \param SET set method (might be empty)
 * \param FLAGS additional flags, e.g.: \code Designable | Stored \endcode
 */
#define PPMOC_PROPERTY(PROPNAME,TYPE,GET,SET,FLAGS) ((PPMOC_PROPERTY_ID) (PROPNAME) (TYPE) \
  ( Readable | Scriptable  \
    BOOST_PP_EXPR_IF(BOOST_PP_NOT(BOOST_PP_IS_EMPTY(SET)),   | Writable)  \
    BOOST_PP_EXPR_IF(BOOST_PP_NOT(BOOST_PP_IS_EMPTY(FLAGS)), | FLAGS)) \
  (GET) (SET))

/** use it to declare method's arguments
 * \code PPMOC_ARG(int,nb)PPMOC_ARG(float*,data) \endcode
 */
#define PPMOC_ARG(TYPE,VAR) ((TYPE)(VAR))

/** declare an enumerator
 * \param NAME name of the enumerator
 * \param NB number of values
 * \param LIST list of the values
 * Example:
 * \code PPMOC_ENUMS(AnEnum,3,(Val0,Val1,Val2)) \endcode
 */
#define PPMOC_ENUMS(NAME,NB,LIST) ( (PPMOC_ENUMS_ID) (NAME) ((NB,LIST)) )


/** Call the PPMOC for non templated class
 * \param NAMESPACE the namespace containing the class (can be empty)
 * \param CLASS the name of the class
 * \param BASECLASS the name of the base class
 * \param DECL the declaration of the class using PPMOC_*
 */
#define PPMOC(NAMESPACE,CLASS,BASECLASS,DECL) \
    PPMOC_TPL(()(),NAMESPACE,CLASS,BASECLASS,(CLASS),DECL)

/** Call the PPMOC for templated class
 * \param TEMPLATE array of the template arguments, e.g.: \code (2,(typename T,int N))\endcode
 * \param NAMESPACE the namespace containing the class (could be empty)
 * \param CLASS the name of the class
 * \param BASECLASS the name of the base class
 * \param INSTANCE sequence of the type to instanciate (they have to be declared using typedef)
 * \param DECL the declaration of the class using PPMOC_*
 */
#define PPMOC_TPL(TEMPLATE,NAMESPACE,CLASS,BASECLASS,INSTANCES,DECL) \
    PPMOC_COMMON(_PPMOC_TPL_EXTRACT(TEMPLATE),NAMESPACE,CLASS,BASECLASS,DECL) \
    BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(INSTANCES), _PPMOC_KERNEL, \
        (_PPMOC_TPL_EXTRACT(TEMPLATE))(NAMESPACE)(INSTANCES)(BASECLASS)(DECL) )


#define PPMOC_MAKE_TPL_DECLARATION(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
    (_PPMOC_TPL_EXTRACT(TEMPLATE))(NAMESPACE)(CLASS)(BASECLASS)(DECL)


#define PPMOC_DECLARE_TPL(DECLARATION) \
    PPMOC_COMMON( \
        BOOST_PP_SEQ_ELEM(0,DECLARATION), \
        BOOST_PP_SEQ_ELEM(1,DECLARATION), \
        BOOST_PP_SEQ_ELEM(2,DECLARATION), \
        BOOST_PP_SEQ_ELEM(3,DECLARATION), \
        BOOST_PP_SEQ_ELEM(4,DECLARATION) )

#define PPMOC_INSTANCIATE_TPL(DECLARATION,INSTANCENAME) \
    PPMOC_INSTANCIATE( \
        BOOST_PP_SEQ_ELEM(0,DECLARATION), \
        BOOST_PP_SEQ_ELEM(1,DECLARATION), \
        INSTANCENAME, \
        BOOST_PP_SEQ_ELEM(3,DECLARATION), \
        BOOST_PP_SEQ_ELEM(4,DECLARATION))


//----------------------------------------------------------------------------------------------------
// END PUBLIC API
//----------------------------------------------------------------------------------------------------

#include <boost/preprocessor.hpp>
#include <boost/preprocessor/detail/is_nullary.hpp>
#include <boost/preprocessor/facilities/is_empty.hpp>
#include <boost/type_traits.hpp>

#include <iostream>
#include <vector>
#include <cstdlib>
#include <QObject>
#include <QMetaProperty>
#include <QMetaEnum>
#include <QVariant>

enum PropertyFlags  {
    Invalid = 0x00000000,
    Readable = 0x00000001,
    Writable = 0x00000002,
    Resettable = 0x00000004,
    EnumOrFlag = 0x00000008,
    StdCppSet = 0x00000100,
//    Override = 0x00000200,
    Designable = 0x00001000,
    ResolveDesignable = 0x00002000,
    Scriptable = 0x00004000,
    ResolveScriptable = 0x00008000,
    Stored = 0x00010000,
    ResolveStored = 0x00020000,
    Editable = 0x00040000,
    ResolveEditable = 0x00080000,
    User = 0x00100000,
    ResolveUser = 0x00200000
};

template<typename T, bool IsEnum = boost::is_enum<T>::value> struct ppmoc_get_type_flag;

template<typename T>
struct ppmoc_get_type_flag<T,false> {
    inline static int flag(void) { return (qMetaTypeId<T>()<<24); }
};

template<typename T>
struct ppmoc_get_type_flag<T,true> {
    inline static int flag(void) { return EnumOrFlag; }
};


#define _PPMOC_DEBUG(X)
// #define _PPMOC_DEBUG(X) X

#define _PPMOC_KERNEL(Z,I,DATA) \
    PPMOC_INSTANCIATE( \
        BOOST_PP_SEQ_ELEM(0,DATA), \
        BOOST_PP_SEQ_ELEM(1,DATA), \
        BOOST_PP_SEQ_ELEM(I,BOOST_PP_SEQ_ELEM(2,DATA)), \
        BOOST_PP_SEQ_ELEM(3,DATA), \
        BOOST_PP_SEQ_ELEM(4,DATA))

#define PPMOC_COMMON(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  PPMOC_METAOBJECT_COMMON(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  PPMOC_QTMETACAST(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  PPMOC_QTMETACALL(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  PPMOC_SIGNAL_DEFINITIONS(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  PPMOC_STATICINIT(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \

#define PPMOC_INSTANCIATE(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  PPMOC_META_DATA(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  PPMOC_META_DATASTRING(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  PPMOC_METAOBJECT(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  PPMOC_STATICINIT_INSTANCIATE(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \



// internal:
#define PPMOC_CLASSINFO_ID  1
#define PPMOC_SLOT_ID       2
#define PPMOC_SIGNAL_ID     3
#define PPMOC_PROPERTY_ID   4
#define PPMOC_ENUMS_ID      5
#define PPMOC_ENUM_ID       6
#define _PPMOC_NB_INTS (7, (0, 2, 5, 5, 3, 4, 2))

#define PPMOC_ISVOID(X) BOOST_PP_IS_EMPTY(X)

#define _PPMOC_ENUMERATE_N_KERNEL(z, i, data)  data BOOST_PP_COMMA()
#define _PPMOC_ENUMERATE_N(N,EL) BOOST_PP_REPEAT(N, _PPMOC_ENUMERATE_N_KERNEL, EL)


#define _PPMOC_FILTER_DECL_KERNEL(R,ID,EL) \
  BOOST_PP_EXPR_IF(BOOST_PP_EQUAL( BOOST_PP_SEQ_HEAD(EL), ID ), (EL) )

#define _PPMOC_FILTER_DECL(DECL,ID) BOOST_PP_SEQ_FOR_EACH(_PPMOC_FILTER_DECL_KERNEL, ID, DECL)

#define _PPMOC_FILTERED_CALL(DECL,CALL) \
  BOOST_PP_SEQ_FOR_EACH(BOOST_PP_CAT(CALL,_classinfo),  ~, _PPMOC_FILTER_DECL(DECL,PPMOC_CLASSINFO_ID)) \
  BOOST_PP_SEQ_FOR_EACH(BOOST_PP_CAT(CALL,_signal),     ~, _PPMOC_FILTER_DECL(DECL,PPMOC_SIGNAL_ID)) \
  BOOST_PP_SEQ_FOR_EACH(BOOST_PP_CAT(CALL,_slot),       ~, _PPMOC_FILTER_DECL(DECL,PPMOC_SLOT_ID)) \
  BOOST_PP_SEQ_FOR_EACH(BOOST_PP_CAT(CALL,_property),   ~, _PPMOC_FILTER_DECL(DECL,PPMOC_PROPERTY_ID)) \
  BOOST_PP_SEQ_FOR_EACH(BOOST_PP_CAT(CALL,_enums),      ~, _PPMOC_FILTER_DECL(DECL,PPMOC_ENUMS_ID)) \
  BOOST_PP_SEQ_FOR_EACH(BOOST_PP_CAT(CALL,_enum),       ~, _PPMOC_FILTER_DECL(DECL,PPMOC_ENUMS_ID)) \


#define _PPMOC_SEQ_REPEAT_KERNEL(Z,I,CALL_DATA) \
  BOOST_PP_TUPLE_ELEM(2,0,CALL_DATA)(Z,I,BOOST_PP_SEQ_ELEM(I,BOOST_PP_TUPLE_ELEM(2,1,CALL_DATA)))

#define _PPMOC_SEQ_REPEAT(KERNEL,SEQ) \
  BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(SEQ), _PPMOC_SEQ_REPEAT_KERNEL, (KERNEL,SEQ)) \

//----------
// process the template parameters

// #define _PPMOC_TPL_EXTRACT_typename  typename)(
// #define _PPMOC_TPL_EXTRACT_struct    struct)(
// #define _PPMOC_TPL_EXTRACT_class     class)(
// #define _PPMOC_TPL_EXTRACT_int       int)(

#define _PPMOC_TPL_SUPPR_typename
#define _PPMOC_TPL_SUPPR_struct
#define _PPMOC_TPL_SUPPR_class
#define _PPMOC_TPL_SUPPR_int

#define _PPMOC_TPL_CLEAN(...) __VA_ARGS__

#define _PPMOC_TPL_EXTRACT_LEFT_KERNEL(Z,I,DATA) \
    BOOST_PP_COMMA_IF(I) BOOST_PP_ARRAY_ELEM(I,DATA)

#define _PPMOC_TPL_EXTRACT_RIGHT_KERNEL(Z,I,DATA) \
BOOST_PP_COMMA_IF(I) BOOST_PP_CAT(_PPMOC_TPL_SUPPR_,BOOST_PP_ARRAY_ELEM(I,DATA))

#define _PPMOC_TPL_EXTRACT(DATA) \
    ((template<BOOST_PP_REPEAT(BOOST_PP_ARRAY_SIZE(DATA), _PPMOC_TPL_EXTRACT_LEFT_KERNEL, DATA)>)) \
    ((<BOOST_PP_REPEAT(BOOST_PP_ARRAY_SIZE(DATA), _PPMOC_TPL_EXTRACT_RIGHT_KERNEL, DATA)>))

#define _PPMOC_TPL_TPL(X)   BOOST_PP_EXPAND(_PPMOC_TPL_CLEAN BOOST_PP_SEQ_HEAD(X))
#define _PPMOC_TPL_CLASS(X) BOOST_PP_EXPAND(_PPMOC_TPL_CLEAN BOOST_PP_SEQ_ELEM(1, X))

//----------

#define PPMOC_METAOBJECT_COMMON(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
    _PPMOC_TPL_TPL(TEMPLATE) \
    const QMetaObject *NAMESPACE::CLASS _PPMOC_TPL_CLASS(TEMPLATE) \
    ::metaObject() const { return &staticMetaObject; }

#define PPMOC_QTMETACAST(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  _PPMOC_TPL_TPL(TEMPLATE) \
  void *NAMESPACE::CLASS _PPMOC_TPL_CLASS(TEMPLATE) \
  ::qt_metacast(const char *_clname) { \
      if (!_clname) return 0; \
      if (!strcmp(_clname, metaObject()->className())) \
        return static_cast<void*>(const_cast< CLASS*>(this)); \
      return BASECLASS::qt_metacast(_clname); \
    }

// if (!strcmp(_clname, qt_meta_stringdata_##CLASS)) \

#define PPMOC_QTMETACALL(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  _PPMOC_TPL_TPL(TEMPLATE) \
  int NAMESPACE::CLASS _PPMOC_TPL_CLASS(TEMPLATE) \
  ::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { \
      _PPMOC_DEBUG(std::cout << "qt_metacall: " << _id << " - " << typeid(CLASS).name() << "\n";) \
      _PPMOC_DEBUG(std::cout << typeid(Scalar).name() << "\n";) \
      _id = BASECLASS::qt_metacall(_c, _id, _a); \
      if (_id < 0) \
        return _id; \
      if (_c == QMetaObject::InvokeMetaMethod) { \
        switch (_id) { \
        _PPMOC_GENERATE_SLOT_CALLS( _PPMOC_FILTER_DECL(DECL,PPMOC_SIGNAL_ID) _PPMOC_FILTER_DECL(DECL,PPMOC_SLOT_ID))  \
        } \
        _id -= BOOST_PP_SEQ_SIZE( _PPMOC_FILTER_DECL(DECL,PPMOC_SIGNAL_ID) _PPMOC_FILTER_DECL(DECL,PPMOC_SLOT_ID) ); \
      } \
      else if (_c == QMetaObject::ReadProperty) { \
        void *_v = _a[0]; \
        _PPMOC_DEBUG(std::cout << "QMetaObject::ReadProperty\n";) \
        switch (_id) { \
        _PPMOC_GENERATE_READ_PROPERTY_CALLS(_PPMOC_FILTER_DECL(DECL,PPMOC_PROPERTY_ID)) \
        } \
        _id -= BOOST_PP_SEQ_SIZE(_PPMOC_FILTER_DECL(DECL,PPMOC_PROPERTY_ID)); \
      } else if (_c == QMetaObject::WriteProperty) { \
        _PPMOC_DEBUG(std::cout << "QMetaObject::WriteProperty\n";) \
        void *_v = _a[0]; \
        switch (_id) { \
        _PPMOC_GENERATE_WRITE_PROPERTY_CALLS(_PPMOC_FILTER_DECL(DECL,PPMOC_PROPERTY_ID)) \
        } \
        _id -= BOOST_PP_SEQ_SIZE(_PPMOC_FILTER_DECL(DECL,PPMOC_PROPERTY_ID)); \
      } else if (_c == QMetaObject::ResetProperty) { \
        _id -= BOOST_PP_SEQ_SIZE(_PPMOC_FILTER_DECL(DECL,PPMOC_PROPERTY_ID)); \
      } else if (_c == QMetaObject::QueryPropertyDesignable) { \
          _id -= BOOST_PP_SEQ_SIZE(_PPMOC_FILTER_DECL(DECL,PPMOC_PROPERTY_ID)); \
      } else if (_c == QMetaObject::QueryPropertyScriptable) { \
          _id -= BOOST_PP_SEQ_SIZE(_PPMOC_FILTER_DECL(DECL,PPMOC_PROPERTY_ID)); \
      } else if (_c == QMetaObject::QueryPropertyStored) { \
          _id -= BOOST_PP_SEQ_SIZE(_PPMOC_FILTER_DECL(DECL,PPMOC_PROPERTY_ID)); \
      } else if (_c == QMetaObject::QueryPropertyEditable) { \
          _id -= BOOST_PP_SEQ_SIZE(_PPMOC_FILTER_DECL(DECL,PPMOC_PROPERTY_ID)); \
      } else if (_c == QMetaObject::QueryPropertyUser) { \
          _id -= BOOST_PP_SEQ_SIZE(_PPMOC_FILTER_DECL(DECL,PPMOC_PROPERTY_ID)); \
      } \
      return _id; \
    }

#define PPMOC_SIGNAL_DEFINITIONS(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  _PPMOC_GENERATE_SIGNAL_DEFINITIONS(_PPMOC_FILTER_DECL(DECL,PPMOC_SIGNAL_ID), (TEMPLATE)(NAMESPACE)(CLASS) )


//----------

#define PPMOC_META_DATA(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  static uint qt_meta_data_##CLASS[] = { \
    1, 0,  -1, -1,  -1, -1,  -1, -1,  -1, -1, \
    _PPMOC_ALLOC_DATASPACE(DECL) 0 };

#define PPMOC_META_DATASTRING(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  static const char qt_meta_stringdata_##CLASS[] = { BOOST_PP_STRINGIZE(NAMESPACE)"::"BOOST_PP_STRINGIZE(CLASS)"\0"\
  _PPMOC_FILTERED_CALL(DECL,_PPMOC_GENERATE_DATASTRING) "\0"};


#define PPMOC_METAOBJECT(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
  template<> const QMetaObject NAMESPACE::CLASS::staticMetaObject = { { &NAMESPACE::CLASS::BASECLASS::staticMetaObject, qt_meta_stringdata_##CLASS, \
      qt_meta_data_##CLASS, 0 } }; \

//----------

#define PPMOC_STATICINIT_INSTANCIATE(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
    struct ppmoc_staticInitialization_##CLASS { \
      ppmoc_staticInitialization_##CLASS() { \
        NAMESPACE::CLASS::ppmoc_staticInitialization(); } }; \
    static ppmoc_staticInitialization_##CLASS _ppmoc_staticInitialization_##CLASS;

#define PPMOC_STATICINIT(TEMPLATE,NAMESPACE,CLASS,BASECLASS,DECL) \
    _PPMOC_TPL_TPL(TEMPLATE) \
    void NAMESPACE::CLASS _PPMOC_TPL_CLASS(TEMPLATE) \
    ::ppmoc_staticInitialization (void) { \
        const char* stringdata = staticMetaObject.d.stringdata; \
        int count = std::string(stringdata).length()+1; \
        int countnull = count-1; \
        int id=0; \
        std::vector<uint> data(10); \
        data[0] = 1; \
        data[1] = 0; \
        data[2] = 0; \
        data[3] = 0; \
        data[4] = 0; \
        data[5] = 0; \
        data[6] = 0; \
        data[7] = 0; \
        data[8] = 0; \
        data[9] = 0; \
        _PPMOC_DEBUG(std::cout << data[0] << "\n";) \
        _PPMOC_SEQ_REPEAT(_PPMOC_STATICINIT_classinfo, _PPMOC_FILTER_DECL(DECL,PPMOC_CLASSINFO_ID) ) \
        _PPMOC_SEQ_REPEAT(_PPMOC_STATICINIT_method, _PPMOC_FILTER_DECL(DECL,PPMOC_SIGNAL_ID) _PPMOC_FILTER_DECL(DECL,PPMOC_SLOT_ID) ) \
        BOOST_PP_SEQ_FOR_EACH_I(_PPMOC_STATICINIT_property, ~, _PPMOC_FILTER_DECL(DECL,PPMOC_PROPERTY_ID) ) \
        _PPMOC_SEQ_REPEAT(_PPMOC_STATICINIT_enums, _PPMOC_FILTER_DECL(DECL,PPMOC_ENUMS_ID) ) \
        _PPMOC_SEQ_REPEAT(_PPMOC_STATICINIT_enum,  _PPMOC_FILTER_DECL(DECL,PPMOC_ENUMS_ID) ) \
        for (int i=0; i<data.size(); ++i) const_cast<uint*>(staticMetaObject.d.data)[i] = data[i]; \
      }


#define _PPMOC_STATICINIT_classinfo(Z,I,EL) \
    data[2]++; if (data[3]==0) data[3]=data.size(); \
    data.push_back(count); \
    _PPMOC_DEBUG(std::cout << "added class info name " << (stringdata+count) << "\n";) \
    count+=std::string((stringdata+count)).length()+1; \
    data.push_back(count); \
    _PPMOC_DEBUG(std::cout << "added class info value " << (stringdata+count) << "\n";) \
    count+=std::string((stringdata+count)).length()+1; \

#define _PPMOC_STATICINIT_method(Z,I,EL) \
    data[4]++; if (data[5]==0) data[5]=data.size(); \
    data.push_back(count); \
    _PPMOC_DEBUG(std::cout << "added method signure " << I << " " << (stringdata+count) << "\n";) \
    count+=std::string((stringdata+count)).length()+1; \
    data.push_back(countnull); \
    BOOST_PP_IF(PPMOC_ISVOID(BOOST_PP_SEQ_ELEM(1,EL)), \
      data.push_back(countnull);, \
      data.push_back(count); \
      _PPMOC_DEBUG(std::cout << "added method return " << I << " " << (stringdata+count) << "\n";) \
      count+=std::string((stringdata+count)).length()+1; ) \
    data.push_back(countnull); \
    BOOST_PP_IF(BOOST_PP_EQUAL( BOOST_PP_SEQ_HEAD(EL), PPMOC_SIGNAL_ID ), data.push_back(0x5);, data.push_back(0xa);) \

#define _PPMOC_STATICINIT_property(R,DECL,I,EL) \
    data[6]++; if (data[7]==0) data[7]=data.size(); \
    data.push_back(count); \
    _PPMOC_DEBUG(std::cout << "added property name " << I << " " << (stringdata+count) << "\n";) \
    count+=std::string((stringdata+count)).length()+1; \
    _PPMOC_DEBUG(std::cout << "added property type " << I << " " << (stringdata+count) << "\n";) \
    data.push_back(count); count+=std::string((stringdata+count)).length()+1; \
    data.push_back( BOOST_PP_SEQ_ELEM(3,EL) | ppmoc_get_type_flag<BOOST_PP_SEQ_ELEM(2,EL)>::flag() );

#define _PPMOC_STATICINIT_enums(Z,I,EL) \
    data[8]++; if (data[9]==0) data[9]=data.size(); \
    data.push_back(count); \
    _PPMOC_DEBUG(std::cout << "added enums name " << I << " " << (stringdata+count) << "\n";) \
    count+=std::string((stringdata+count)).length()+1; \
    data.push_back(0x0); \
    data.push_back(BOOST_PP_ARRAY_SIZE(BOOST_PP_SEQ_ELEM(2,EL))); \
    data.push_back(0);



#define _PPMOC_STATICINIT_enum_KERNEL(Z,I,DATA) \
    data.push_back(count); \
    _PPMOC_DEBUG(std::cout << "added enum name " << I << " " << (stringdata+count) << " value=" << int(BOOST_PP_ARRAY_ELEM(I,DATA)) << "\n";) \
    count+=std::string((stringdata+count)).length()+1; \
    data.push_back(int(BOOST_PP_ARRAY_ELEM(I,DATA))); \
    _PPMOC_DEBUG(std::cout << data[data.size()-2] << " " << data.back() << "\n";)

#define _PPMOC_STATICINIT_enum(Z,I,EL) \
    data[data[9]+I*4+3] = data.size(); \
    BOOST_PP_REPEAT(BOOST_PP_ARRAY_SIZE(BOOST_PP_SEQ_ELEM(2,EL)),_PPMOC_STATICINIT_enum_KERNEL,BOOST_PP_SEQ_ELEM(2,EL))

//----------

#define _PPMOC_GENERATE_ARG_CALL_KERNEL(R,DATA,I,EL)  \
  BOOST_PP_COMMA_IF(I) \
  (*reinterpret_cast< BOOST_PP_SEQ_HEAD(EL) (*)>(_a[I+1]))

#define _PPMOC_GENERATE_ARG_CALL(R,ARGSEQ) BOOST_PP_SEQ_FOR_EACH_I(_PPMOC_GENERATE_ARG_CALL_KERNEL, ~, ARGSEQ)

#define _PPMOC_GENERATE_SLOT_CALLS_KERNEL(Z,I,EL) \
    case I: { \
      BOOST_PP_IF(PPMOC_ISVOID(BOOST_PP_SEQ_ELEM(1,EL)), \
        BOOST_PP_SEQ_ELEM(2,EL) ( _PPMOC_GENERATE_ARG_CALL(R,BOOST_PP_SEQ_ELEM(3,EL)) );, \
      if (_a[0])  *reinterpret_cast< BOOST_PP_SEQ_ELEM(1,EL) (*)>(_a[0]) \
          = BOOST_PP_SEQ_ELEM(2,EL) ( _PPMOC_GENERATE_ARG_CALL(R,BOOST_PP_SEQ_ELEM(3,EL)) ); \
      else \
         BOOST_PP_SEQ_ELEM(2,EL) ( _PPMOC_GENERATE_ARG_CALL(R,BOOST_PP_SEQ_ELEM(3,EL)) );) \
      } break;

#define _PPMOC_GENERATE_SLOT_CALLS(DECL) \
  _PPMOC_SEQ_REPEAT(_PPMOC_GENERATE_SLOT_CALLS_KERNEL, DECL)

//----------

#define _PPMOC_GENERATE_READ_PROPERTY_CALLS_KERNEL(Z,I,EL) \
    case I: *reinterpret_cast< BOOST_PP_SEQ_ELEM(2,EL) (*)>(_v) = BOOST_PP_SEQ_ELEM(4,EL)(); break;

#define _PPMOC_GENERATE_READ_PROPERTY_CALLS(DECL) \
  _PPMOC_SEQ_REPEAT(_PPMOC_GENERATE_READ_PROPERTY_CALLS_KERNEL, DECL)

//----------

#define _PPMOC_GENERATE_WRITE_PROPERTY_CALLS_KERNEL(Z,I,EL) \
  BOOST_PP_EXPR_IF( BOOST_PP_NOT(BOOST_PP_IS_EMPTY(BOOST_PP_SEQ_ELEM(5,EL))), \
  case I: BOOST_PP_SEQ_ELEM(5,EL)(*reinterpret_cast< BOOST_PP_SEQ_ELEM(2,EL) (*) >(_v)); break; )

#define _PPMOC_GENERATE_WRITE_PROPERTY_CALLS(DECL) \
  _PPMOC_SEQ_REPEAT(_PPMOC_GENERATE_WRITE_PROPERTY_CALLS_KERNEL, DECL)

//----------

#define _PPMOC_GENERATE_SIGNAL_PARAMETERS_KERNEL(Z,I,EL) BOOST_PP_SEQ_HEAD(EL) _t##I

#define _PPMOC_GENERATE_SIGNAL_ARGUMENTS_KERNEL(Z,I,EL) const_cast<void*>(reinterpret_cast<const void*>(&_t##I))

#define _PPMOC_GENERATE_SIGNAL_DEFINITIONS_KERNEL(R,TPL_FULLCLASSNAME,I,EL) \
  _PPMOC_TPL_TPL(BOOST_PP_SEQ_HEAD(TPL_FULLCLASSNAME)) \
  void BOOST_PP_SEQ_ELEM(1,TPL_FULLCLASSNAME)::BOOST_PP_SEQ_ELEM(2,TPL_FULLCLASSNAME) _PPMOC_TPL_CLASS(BOOST_PP_SEQ_HEAD(TPL_FULLCLASSNAME)) \
  ::BOOST_PP_SEQ_ELEM(2,EL) ( _PPMOC_SEQ_REPEAT(_PPMOC_GENERATE_SIGNAL_PARAMETERS_KERNEL,BOOST_PP_SEQ_ELEM(3,EL)) ) { \
    void *_a[] = { 0, _PPMOC_SEQ_REPEAT(_PPMOC_GENERATE_SIGNAL_ARGUMENTS_KERNEL,BOOST_PP_SEQ_ELEM(3,EL)) }; \
    QMetaObject::activate(const_cast< BOOST_PP_SEQ_ELEM(2,TPL_FULLCLASSNAME) *>(this), &staticMetaObject, I, _a); \
}

#define _PPMOC_GENERATE_SIGNAL_DEFINITIONS(DECL,TPL_FULLCLASSNAME) \
  BOOST_PP_SEQ_FOR_EACH_I(_PPMOC_GENERATE_SIGNAL_DEFINITIONS_KERNEL, TPL_FULLCLASSNAME, DECL)


//----------

/* const data */

#define _PPMOC_ALLOC_DATASPACE_ENUM_KERNEL(Z,I,DATA) \
    _PPMOC_ENUMERATE_N( BOOST_PP_ARRAY_ELEM(PPMOC_ENUM_ID,_PPMOC_NB_INTS), -1  )
    

#define _PPMOC_ALLOC_DATASPACE_KERNEL(R,DATA,EL) \
  _PPMOC_ENUMERATE_N( BOOST_PP_ARRAY_ELEM(BOOST_PP_SEQ_HEAD(EL),_PPMOC_NB_INTS), -1  ) \

#define _PPMOC_ALLOC_DATASPACE_enum(R,DATA,EL) \
    BOOST_PP_REPEAT(BOOST_PP_ARRAY_SIZE(BOOST_PP_SEQ_ELEM(2,EL)),_PPMOC_ALLOC_DATASPACE_ENUM_KERNEL,DATA)

#define _PPMOC_ALLOC_DATASPACE(DECL) \
    BOOST_PP_SEQ_FOR_EACH(_PPMOC_ALLOC_DATASPACE_KERNEL, ~, DECL) \
    BOOST_PP_SEQ_FOR_EACH(_PPMOC_ALLOC_DATASPACE_enum, ~, _PPMOC_FILTER_DECL(DECL,PPMOC_ENUMS_ID))

//----------

/* const data string */

#define _PPMOC_GENERATE_SIGNATURE_KERNEL(R,DATA,I,EL) BOOST_PP_EXPR_IF(I,",")BOOST_PP_STRINGIZE(BOOST_PP_SEQ_HEAD(EL))
#define _PPMOC_GENERATE_SIGNATURE(ARGSEQ) BOOST_PP_SEQ_FOR_EACH_I(_PPMOC_GENERATE_SIGNATURE_KERNEL,~,ARGSEQ)


#define _PPMOC_GENERATE_DATASTRING_classinfo(R,DATA,EL) \
    BOOST_PP_SEQ_ELEM(1,EL)"\0" BOOST_PP_SEQ_ELEM(2,EL)"\0"

#define _PPMOC_GENERATE_DATASTRING_signal(R,DATA,EL) \
    BOOST_PP_STRINGIZE(BOOST_PP_SEQ_ELEM(2,EL))"("_PPMOC_GENERATE_SIGNATURE(BOOST_PP_SEQ_ELEM(3,EL))")\0"

#define _PPMOC_GENERATE_DATASTRING_slot(R,DATA,EL) \
    BOOST_PP_STRINGIZE(BOOST_PP_SEQ_ELEM(2,EL))"("_PPMOC_GENERATE_SIGNATURE(BOOST_PP_SEQ_ELEM(3,EL))")\0"    \
    BOOST_PP_IF(PPMOC_ISVOID(BOOST_PP_SEQ_ELEM(1,EL)),,BOOST_PP_STRINGIZE(BOOST_PP_SEQ_ELEM(1,EL))"\0")

#define _PPMOC_GENERATE_DATASTRING_property(R,DATA,EL) \
    BOOST_PP_STRINGIZE(BOOST_PP_SEQ_ELEM(1,EL))"\0" \
    BOOST_PP_STRINGIZE(BOOST_PP_SEQ_ELEM(2,EL))"\0"


#define _PPMOC_GENERATE_DATASTRING_enums(R,DATA,EL) \
    BOOST_PP_STRINGIZE(BOOST_PP_SEQ_ELEM(1,EL))"\0"

#define _PPMOC_GENERATE_DATASTRING_ENUM_KERNEL(Z,I,DATA) \
    BOOST_PP_STRINGIZE(BOOST_PP_ARRAY_ELEM(I,DATA))"\0"

#define _PPMOC_GENERATE_DATASTRING_enum(R,DATA,EL) \
    BOOST_PP_REPEAT(BOOST_PP_ARRAY_SIZE(BOOST_PP_SEQ_ELEM(2,EL)),_PPMOC_GENERATE_DATASTRING_ENUM_KERNEL,BOOST_PP_SEQ_ELEM(2,EL))
    

//----------

#endif
