#ifndef HW_LIB_PLOOC_CLASS_BLACK_BOX_H
#define HW_LIB_PLOOC_CLASS_BLACK_BOX_H
/*============================ INCLUDES ======================================*/
//#include <stdint.h>
//#include <stdbool.h>


#ifdef __cplusplus
extern "C" {
#endif

/*============================ MACROS ========================================*/
#undef declare_class
#undef dcl_class
#undef def_class
#undef define_class
#undef __def_class
#undef end_def_class
#undef end_define_class
#undef __end_def_class
#undef extern_class
#undef __extern_class
#undef end_extern_class
#undef __end_extern_class
#undef class
#undef __class
/*============================ MACROFIED FUNCTIONS ===========================*/

#if   defined(__PLOOC_CLASS_IMPLEMENT__) || defined(__PLOOC_CLASS_IMPLEMENT)

#   ifdef __OOC_DEBUG__
#       define __def_class(__name, __public ,...)                               \
    typedef struct __name __name;                                               \
    typedef struct __##__name __##__name;                                       \
    struct __##__name {                                                         \
        __public                                                                \
        PLOOC_VISIBLE(__VA_ARGS__)                                              \
    };                                                                          \
    struct __name {                                                             \
        __public                                                                \
        PLOOC_VISIBLE(__VA_ARGS__)                                              \
    };
#   else
#       define __def_class(__name, __public, ...)                               \
    typedef struct __name __name;                                               \
    typedef struct __##__name __##__name;                                       \
    struct __##__name {                                                         \
        __public                                                                \
        PLOOC_VISIBLE(__VA_ARGS__)                                              \
    };                                                                          \
    struct __name {                                                             \
        __public                                                                \
        PLOOC_INVISIBLE(__VA_ARGS__)                                            \
    };

#   endif

#   define __end_def_class(__name, ...)

#   undef private_member
#   define private_member(...)              PLOOC_VISIBLE(__VA_ARGS__)

#   undef public_member
#   define public_member(...)               PLOOC_VISIBLE(__VA_ARGS__)

#   undef  __class
#   define __class(__name)                  __##__name

#   define class(__name)                    __class(__name)

#define __extern_class(__name,...)
#define __end_extern_class(__name, ...)

#else

#ifndef __OOC_DEBUG__

#   define __def_class(__name, __public, ...)                                   \
    typedef struct __name __name;                                               \
    typedef struct __##__name __##__name;                                       \
    struct __##__name {                                                         \
        __public                                                                \
        PLOOC_VISIBLE(__VA_ARGS__)                                              \
    };

#define __extern_class(__name, __public, ...)                                    \
    typedef struct __name __name;                                               \
    struct __name {                                                             \
        __public                                                                \
        PLOOC_INVISIBLE(__VA_ARGS__)                                            \
    };


#define __end_extern_class(__name, ...)

#   undef private_member
#   define private_member(...)              PLOOC_VISIBLE(__VA_ARGS__)

#   undef public_member
#   define public_member(...)               PLOOC_VISIBLE(__VA_ARGS__)

#else

#   define __def_class(__name, __public, ...)                                   \
    typedef struct __name __name;                                               \
    typedef struct __##__name __##__name;                                       \
    struct __##__name {                                                         \
        __public                                                                \
        PLOOC_VISIBLE(__VA_ARGS__)                                              \
    };

#define __extern_class(__name,__public, ...)                                    \
    typedef struct __name __name;                                               \
    struct __name {                                                             \
        __public                                                                \
        PLOOC_VISIBLE(__VA_ARGS__)                                              \
    };


#define __end_extern_class(__name, ...)

#   undef private_member
#   define private_member(...)              PLOOC_INVISIBLE(__VA_ARGS__)

#   undef public_member
#   define public_member(...)               PLOOC_VISIBLE(__VA_ARGS__)

#endif


#   define __end_def_class(__name, ...)

#endif


#   undef  __class
#   define __class(__name)                  __##__name

#   undef  class
#   define class(__name)                    __class(__name)


#define declare_class(__name)           typedef struct __name __name;
#define dcl_class(__name)               declare_class(__name)

#define end_def_class(__name, ...)      __end_def_class(__name, __VA_ARGS__)
#define end_define_class(__name, ...)   end_def_class(__name, ...)

#define def_class(__name, __public, ...)                                         \
            __def_class(__name, __public, __VA_ARGS__)
#define define_class(__name, __public, ...)                                     \
            def_class(__name,__public, __VA_ARGS__)

#define class(__name)                   __class(__name)

#define extern_class(__name, __public, ...)                                     \
            __extern_class(__name, __public,__VA_ARGS__)
#define end_extern_class(__name, ...)   __end_extern_class(__name, __VA_ARGS__)

#ifndef __PLOOC_CLASS_BLACK_BOX_H__
#define __PLOOC_CLASS_BLACK_BOX_H__

/*! \brief macro for initializing class in compiler-time
 *! \param __type class name
 *! \param __obj target object
 *! \param ... initialization list
 */
#define __INIT_CLASS_OBJ(__type, __obj, ...)                                    \
            union {                                                             \
                class(__type) __##__obj;                                        \
                __type;                                                         \
            } __obj = {                                                         \
                .__##__obj = __VA_ARGS__                                        \
            }
#define init_class_obj(__type, __obj, ...)                                      \
            __INIT_CLASS_OBJ(__type, __obj, __VA_ARGS__)

#define __EXTERN_CLASS_OBJ(__type, __obj)                                     \
            extern union {                                                      \
                class(__type) __##__obj;                                        \
                __type;                                                         \
            }__obj;
#define extern_class_obj(__type, __obj)                                         \
            __EXTERN_CLASS_OBJ( __type, __obj )
#endif

/*----------------------------------------------------------------------------*
 * new standard (lower case)                                                  *
 *----------------------------------------------------------------------------*/

#   undef __class_internal
#   define __class_internal(__src, __des, __type, ...)                          \
            class(__type) *(__des) = (class(__type) *)(__src);                  \
            PLOOC_UNUSED_PARAM(__des);                                          \
            __with_class(__type, (__src), __VA_ARGS__)

#   undef class_internal
#   define class_internal(__src, __des, __type, ...)                             \
            __class_internal(__src, __des, __type, __VA_ARGS__)

#   undef __with_class
#   define __with_class(__type, __src, ...)                                     \
        {                                                                       \
            class(__type)*_ =(class(__type) *)(__src);                          \
            PLOOC_UNUSED_PARAM(_);                                              \
            __VA_ARGS__;                                                        \
        }                                                                       \
        for (class(__type)*_ =(class(__type) *)(__src); NULL != _; _ = NULL)

#   undef with_class
#   define with_class(__type, __src, ...)                                       \
            __with_class(__type, __src, __VA_ARGS__)

#undef which
#define which(...)                      PLOOC_VISIBLE(__VA_ARGS__)

/*============================ TYPES =========================================*/

/*============================ GLOBAL VARIABLES ==============================*/
/*============================ LOCAL VARIABLES ===============================*/
/*============================ PROTOTYPES ====================================*/

#undef __PLOOC_CLASS_IMPLEMENT__
#undef __PLOOC_CLASS_INHERIT__
#undef __PLOOC_CLASS_IMPLEMENT
#undef __PLOOC_CLASS_INHERIT

#ifdef __cplusplus
}
#endif
#endif //HW_LIB_PLOOC_CLASS_BLACK_BOX_H