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

#ifdef USE_NLLIBC
#include <nllibc.h>
#endif

#include "history.h"

struct history {
  struct history *next;
  struct history *prev;
  char line[0];
};

static struct history *history_list = NULL;
static struct history *history_current = NULL;

static struct history *history_alloc(const char *line)
{
  struct history *h;

  h = malloc(sizeof(*h) + strlen(line) + 1);
  if (h == NULL)
    return NULL;

  h->next = NULL;
  h->prev = NULL;
  strcpy(h->line, line);

  return h;
}

static struct history *history_free(struct history *h)
{
  if (h != NULL)
    free(h);
  return NULL;
}

int nlline_history_push(const char *line)
{
  struct history *h;

  h = history_alloc(line);
  if (h == NULL)
    return -1;

  if (history_list) {
    history_list->prev = h;
  }
  h->next = history_list;
  h->prev = NULL;
  history_list = h;

  return 0;
}

int nlline_history_pop(void)
{
  struct history *h;

  if (history_list == NULL)
    return -1;

  h = history_list;
  if (h->next)
    h->next->prev = NULL;
  history_list = h->next;

  if (history_current == h)
    history_current = NULL;
  history_free(h);

  return 0;
}

int nlline_history_clear_all(void)
{
  struct history *h, *next;
  for (h = history_list; h != NULL; h = next) {
    next = h->next;
    history_free(h);
  }
  history_list = NULL;
  history_current = NULL;
  return 0;
}

int nlline_history_current_init(void)
{
  history_current = NULL;
  return 0;
}

int nlline_history_current_next(void)
{
  if (history_current == NULL)
    history_current = history_list;
  else if (history_current->next)
    history_current = history_current->next;
  return 0;
}

int nlline_history_current_prev(void)
{
  if (history_current == NULL)
    history_current = history_list;
  else if (history_current->prev)
    history_current = history_current->prev;
  return 0;
}

char *nlline_history_get_current(void)
{
  if (history_current == NULL)
    return NULL;
  return history_current->line;
}

int nlline_history_is_current_start(void)
{
  if (history_current == NULL)
    return -1;
  return history_current->next ? 0 : 1;
}

int nlline_history_is_current_end(void)
{
  if (history_current == NULL)
    return -1;
  return history_current->prev ? 0 : 1;
}
