// this is a template file to drive any fs backend that sets up stdin/out
// and the core parsers and init/shutdown funcs. the expectation is you build
// this along with an implementation file that implements that fs
#include <Eina.h>
#include <Ecore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>

#include "cmd.h"

void do_handle_cmd(Cmd *c);
int  do_init(int argc, const char **argv);
void do_shutdown(void);

static Ecore_Fd_Handler *fdh = NULL;
static Eina_Strbuf      *strbuf = NULL;

static Eina_Bool
_cb_stdio_in_read(void *data EINA_UNUSED, Ecore_Fd_Handler *fd_handler EINA_UNUSED)
{
   ssize_t ret;
   char buf[4096 + 1];

   errno = 0;
   ret = read(0, buf, sizeof(buf) - 1);

   if (ret < 1)
     {
        int e = errno;

        if ((e == EIO) || (e == EBADF) || (e == EPIPE) || (e == EINVAL) ||
            (e == ENOSPC) || (!((e == EAGAIN) || (e == EINTR))))
          {
             ecore_main_loop_quit();
             goto done;
          }
        goto done;
     }
   else
     {
        const char *nl, *str;

        buf[ret] = '\0';
        eina_strbuf_append(strbuf, buf);

        for (;;)
          {
             char *s;
             Cmd *c;

             str = eina_strbuf_string_get(strbuf);
             nl = strchr(str, '\n');
             if (!nl) break;

             s = strndup(str, nl - str);
             if (!s) break;
             c = cmd_parse(s);
             if (c)
               {
                  do_handle_cmd(c);
                  cmd_free(c);
               }
             free(s);
             eina_strbuf_remove(strbuf, 0, nl - str + 1);
          }
     }
done:
   return EINA_TRUE;
}

static void
_init(void)
{
   strbuf = eina_strbuf_new();
   if (!strbuf)
     {
        fprintf(stderr, "ERR: Can't allocate strbuf\n");
        goto err;
     }
   if (fcntl(0, F_SETFL, O_NONBLOCK) != 0)
     {
        fprintf(stderr, "ERR: Can't set stdin to O_NONBLOCK\n");
        goto err;
     }
   fdh = ecore_main_fd_handler_add(0, ECORE_FD_READ, _cb_stdio_in_read,
                                   NULL, NULL, NULL);
   if (!fdh) goto err;
   return;
err:
   exit(-1);
}

static void
_shutdown(void)
{
   ecore_main_fd_handler_del(fdh);
   fdh = NULL;
   eina_strbuf_free(strbuf);
   strbuf = NULL;
}

int
main(int argc, const char **argv)
{
   int ret;

   eina_init();
   ecore_init();

   _init();

   ret = do_init(argc, argv);

   if (ret == 0)
     {
        ecore_main_loop_begin();
        do_shutdown();
     }

   _shutdown();

   ecore_shutdown();
   eina_shutdown();

   return ret;
}
