#pragma once

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// required for ei.h to work
#ifndef _REENTRANT
#define _REENTRANT
#endif

#include <ei.h>
#include <ei_connect.h>

#include "../../inotify.h"
#include <unifex/cnode.h>
#include <unifex/payload.h>
#include <unifex/unifex.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef State UnifexState;

UnifexState *unifex_alloc_state(UnifexEnv *env);
void unifex_release_state(UnifexEnv *env, UnifexState *state);
void handle_destroy_state(UnifexEnv *env, UnifexState *state);

#ifdef __cplusplus
enum Events {
  NOTIFY_IN_ACCESS,
  NOTIFY_IN_ATTRIB,
  NOTIFY_IN_CLOSE_WRITE,
  NOTIFY_IN_CLOSE_NOWRITE,
  NOTIFY_IN_CREATE,
  NOTIFY_IN_DELETE,
  NOTIFY_IN_DELETE_SELF,
  NOTIFY_IN_MODIFY,
  NOTIFY_IN_MOVED_FROM,
  NOTIFY_IN_MOVED_TO,
  NOTIFY_IN_OPEN,
  NOTIFY_IN_MOVE
};
#else
enum Events_t {
  NOTIFY_IN_ACCESS,
  NOTIFY_IN_ATTRIB,
  NOTIFY_IN_CLOSE_WRITE,
  NOTIFY_IN_CLOSE_NOWRITE,
  NOTIFY_IN_CREATE,
  NOTIFY_IN_DELETE,
  NOTIFY_IN_DELETE_SELF,
  NOTIFY_IN_MODIFY,
  NOTIFY_IN_MOVED_FROM,
  NOTIFY_IN_MOVED_TO,
  NOTIFY_IN_OPEN,
  NOTIFY_IN_MOVE
};
typedef enum Events_t Events;
#endif

UNIFEX_TERM init(UnifexEnv *env);
UNIFEX_TERM ex_inotify_add_watch(UnifexEnv *env, char *pathname, Events *events,
                                 unsigned int events_length, int opts);
UNIFEX_TERM ex_inotify_rm_watch(UnifexEnv *env, int wd);
UNIFEX_TERM init_result_ok(UnifexEnv *env, UnifexState *state);
UNIFEX_TERM init_result_error(UnifexEnv *env, char const *error);
UNIFEX_TERM ex_inotify_add_watch_result_ok(UnifexEnv *env, int wd);
UNIFEX_TERM ex_inotify_add_watch_result_error(UnifexEnv *env,
                                              char const *error);
UNIFEX_TERM ex_inotify_rm_watch_result(UnifexEnv *env);
UNIFEX_TERM ex_inotify_rm_watch_result_error(UnifexEnv *env, char const *error);
UNIFEX_TERM init_caller(UnifexEnv *env, UnifexCNodeInBuff *in_buff);
UNIFEX_TERM ex_inotify_add_watch_caller(UnifexEnv *env,
                                        UnifexCNodeInBuff *in_buff);
UNIFEX_TERM ex_inotify_rm_watch_caller(UnifexEnv *env,
                                       UnifexCNodeInBuff *in_buff);
int send_inotify_event(UnifexEnv *env, UnifexPid pid, int flags, int wd,
                       char const *name, Events const *events,
                       unsigned int events_length);
int handle_main(int argc, char **argv);

#ifdef __cplusplus
}
#endif
