/*
 * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
 *
 * SPDX-FileCopyrightText: 2024 Hiredict Contributors
 * SPDX-FileCopyrightText: 2024 Pieter Noordhuis <pcnoordhuis at gmail dot com>
 *
 * SPDX-License-Identifier: BSD-3-Clause
 * SPDX-License-Identifier: LGPL-3.0-or-later
 *
 */

#ifndef __HIREDICT_AE_H__
#define __HIREDICT_AE_H__
#include <sys/types.h>
#include <ae.h>
#include "../hiredict.h"
#include "../async.h"

typedef struct redictAeEvents {
    redictAsyncContext *context;
    aeEventLoop *loop;
    int fd;
    int reading, writing;
} redictAeEvents;

static void redictAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) {
    ((void)el); ((void)fd); ((void)mask);

    redictAeEvents *e = (redictAeEvents*)privdata;
    redictAsyncHandleRead(e->context);
}

static void redictAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) {
    ((void)el); ((void)fd); ((void)mask);

    redictAeEvents *e = (redictAeEvents*)privdata;
    redictAsyncHandleWrite(e->context);
}

static void redictAeAddRead(void *privdata) {
    redictAeEvents *e = (redictAeEvents*)privdata;
    aeEventLoop *loop = e->loop;
    if (!e->reading) {
        e->reading = 1;
        aeCreateFileEvent(loop,e->fd,AE_READABLE,redictAeReadEvent,e);
    }
}

static void redictAeDelRead(void *privdata) {
    redictAeEvents *e = (redictAeEvents*)privdata;
    aeEventLoop *loop = e->loop;
    if (e->reading) {
        e->reading = 0;
        aeDeleteFileEvent(loop,e->fd,AE_READABLE);
    }
}

static void redictAeAddWrite(void *privdata) {
    redictAeEvents *e = (redictAeEvents*)privdata;
    aeEventLoop *loop = e->loop;
    if (!e->writing) {
        e->writing = 1;
        aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redictAeWriteEvent,e);
    }
}

static void redictAeDelWrite(void *privdata) {
    redictAeEvents *e = (redictAeEvents*)privdata;
    aeEventLoop *loop = e->loop;
    if (e->writing) {
        e->writing = 0;
        aeDeleteFileEvent(loop,e->fd,AE_WRITABLE);
    }
}

static void redictAeCleanup(void *privdata) {
    redictAeEvents *e = (redictAeEvents*)privdata;
    redictAeDelRead(privdata);
    redictAeDelWrite(privdata);
    hi_free(e);
}

static int redictAeAttach(aeEventLoop *loop, redictAsyncContext *ac) {
    redictContext *c = &(ac->c);
    redictAeEvents *e;

    /* Nothing should be attached when something is already attached */
    if (ac->ev.data != NULL)
        return REDICT_ERR;

    /* Create container for context and r/w events */
    e = (redictAeEvents*)hi_malloc(sizeof(*e));
    if (e == NULL)
        return REDICT_ERR;

    e->context = ac;
    e->loop = loop;
    e->fd = c->fd;
    e->reading = e->writing = 0;

    /* Register functions to start/stop listening for events */
    ac->ev.addRead = redictAeAddRead;
    ac->ev.delRead = redictAeDelRead;
    ac->ev.addWrite = redictAeAddWrite;
    ac->ev.delWrite = redictAeDelWrite;
    ac->ev.cleanup = redictAeCleanup;
    ac->ev.data = e;

    return REDICT_OK;
}
#endif
