#ifndef IOS_EVENT_H_
#define IOS_EVENT_H_
/*---------------------------------------------------------------------------*/
/* ios_event.h                                                               */
/* copyright (c) innovaphone 2015                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

NAMESPACE_BEGIN

#ifdef __cplusplus
extern "C" {
#endif

#define IOS_EVENT_QUEUE_SIZE_EXP    14
#define IOS_EVENT_QUEUE_SIZE        (1 << IOS_EVENT_QUEUE_SIZE_EXP)
#define IOS_EVENT_QUEUE_MASK        (~(0xffffffff << IOS_EVENT_QUEUE_SIZE_EXP))

typedef union tag_ios_event_queue_arg {
    bool z;
    int i;
    const char *a;
    const byte *b;
    byte *m;
    void *l;
} t_ios_event_queue_arg;

#ifdef __cplusplus
typedef void (*ios_event_handler)(class ios_event *ios_event);
#else
typedef void *ios_event_handler;
#endif

struct tag_ios_event_handler {
    const ios_event_handler handler;
    const char *format;
};

typedef struct tag_ios_event_handler t_ios_event_handler;

extern volatile t_ios_event_queue_arg *ios_event_queue;

extern volatile dword ios_event_in_doorbell_req;
extern dword ios_event_in_doorbell_ack;
extern volatile dword ios_event_out_doorbell_req;
extern dword ios_event_out_doorbell_ack;

void async_event_release_memory(void * ref, byte * b, bool modified);

#ifdef __cplusplus
}
#endif
/*---------------------------------------------------------------------------*/
#if defined(__cplusplus)

class ios_event
{
    t_ios_event_handler *handler_table;
    unsigned int handler_count;

    dword queue_pos;

public:
    ios_event();

    bool init(t_ios_event_handler *handler_table, unsigned int handler_count);
    dword dequeue();
    bool get_bool() { bool z = ios_event_queue[queue_pos & IOS_EVENT_QUEUE_MASK].z; queue_pos++; return z; }
    int get_int() { int i = ios_event_queue[queue_pos & IOS_EVENT_QUEUE_MASK].i; queue_pos++; return i; }
    const char *get_string() { const char *a = ios_event_queue[(queue_pos+1) & IOS_EVENT_QUEUE_MASK].a; queue_pos += 2; return a; }
    const byte *get_byte_array(int * p_len) { *p_len = ios_event_queue[(queue_pos+1) & IOS_EVENT_QUEUE_MASK].i;
        const byte *b = ios_event_queue[(queue_pos+2) & IOS_EVENT_QUEUE_MASK].b; queue_pos += 3; return b; }
    byte *get_memory(int * p_len, void ** p_ref, bool *is_copy) { *p_ref = ios_event_queue[queue_pos & IOS_EVENT_QUEUE_MASK].l; *is_copy = false;
        *p_len = ios_event_queue[(queue_pos+1) & IOS_EVENT_QUEUE_MASK].i; byte *b = ios_event_queue[(queue_pos+2) & IOS_EVENT_QUEUE_MASK].m; queue_pos += 3; return b; }
    void set_checked() {};
};

#endif /* defined(__cplusplus) */
/*---------------------------------------------------------------------------*/

NAMESPACE_END

/*---------------------------------------------------------------------------*/
#endif /* IOS_EVENT_H_ */
