// $Id: history.c 4102 2006-12-08 09:43:35Z jj $
//
// $Log$

#include "hstdinc.h"

#include "hercules.h"
#include "history.h"

#define HISTORY_MAX 10

#define CMD_SIZE 256  /* 32767 is way toooooo much */

typedef struct history {
  int number;
  char *cmdline;
  struct history *prev;
  struct history *next;
} HISTORY;


BYTE history_count;          /* for line numbering */

HISTORY *history_lines;      /* points to the beginning of history list (oldest command) */
HISTORY *history_lines_end;  /* points to the end of history list (most recent command) */
HISTORY *history_ptr;        /* points to last command retrieved by key press */
HISTORY *backup;             /* used for backuping last removed command */

/* these 2 are used in panel.c to see if there was history command requested and
   returns that command */ 
char *historyCmdLine;
int history_requested = 0;

void copy_to_historyCmdLine(char* cmdline)
{
  if (historyCmdLine) free(historyCmdLine);
  historyCmdLine = malloc(strlen(cmdline)+1);
  strcpy(historyCmdLine, cmdline);
}

/* initialize environment */
int history_init() {
  history_lines = NULL;
  history_lines_end = NULL;
  historyCmdLine = (char *) malloc(255);
  history_requested = 0;
  backup = NULL;
  history_count = 0;
  history_ptr = NULL;
  return(0);
}

/* add commandline to history list */
int history_add(char *cmdline) {
  HISTORY *tmp;

  /* if there is some backup line remaining, remove it */
  if (backup != NULL) {
    free(backup->cmdline);
    free(backup);
    backup = NULL;
  }

  /* allocate space and copy string */
  tmp = (HISTORY*) malloc(sizeof(HISTORY));
  tmp->cmdline = (char*) malloc(strlen(cmdline) + 1);
  strcpy(tmp->cmdline, cmdline);
  tmp->next = NULL;
  tmp->prev = NULL;
  tmp->number = ++history_count;

  if (history_lines == NULL) {
    /* first in list */
    history_lines = tmp;
    history_lines_end = tmp;
  }
  else {
    tmp->prev = history_lines_end;
    history_lines_end->next = tmp;
    history_lines_end = tmp;
  }
  history_ptr = NULL;

  if (history_count > HISTORY_MAX) {
    /* if we are over maximum number of lines in history list, oldest one should be deleted
       but we don't know whether history_remove will not be called, so oldest line is backuped and        not removed */
    backup = history_lines;
    history_lines = history_lines->next;
    backup->next = NULL;
    history_lines->prev = NULL;
  }
  return(0);
}

/* show list of lines in history */
int history_show() {
  HISTORY *tmp;
  tmp = history_lines;
  while (tmp != NULL) {
    logmsg("%4d %s\n", tmp->number, tmp->cmdline);
    tmp = tmp->next;
  }
  return(0);
}

/* remove last line from history list (called only when history command was invoked) */
int history_remove() {
  HISTORY *tmp;

  if (history_lines == NULL)
    return(0);
  if (history_lines == history_lines_end) {
    ASSERT(history_lines->next == NULL);
    ASSERT(history_count == 1);
    free(history_lines->cmdline);
    free(history_lines);
    history_lines = NULL;
    history_lines_end = NULL;
    history_count--;
    return(0);
  }
  tmp = history_lines_end->prev;
  tmp->next = NULL;
  free(history_lines_end->cmdline);
  free(history_lines_end);
  history_count--;
  history_lines_end = tmp;
  if (backup != NULL) {
    backup->next = history_lines;
    history_lines->prev = backup;
    history_lines = backup;
    backup = NULL;
  }
  return(0);
}

int history_relative_line(int x) {
  HISTORY *tmp = history_lines_end;

  if (-x > HISTORY_MAX) {
    logmsg("History limited to last %d commands\n", HISTORY_MAX);
    return (-1);
  }

  if (-x > history_count) {
    logmsg("only %d commands in history\n", history_count);
    return (-1);
  }

  while (x<-1) {
    tmp = tmp->prev;
    x++;
  }
  copy_to_historyCmdLine(tmp->cmdline);
  history_ptr = NULL;
  return(0);
}

int history_absolute_line(int x) {
  HISTORY *tmp = history_lines_end;
  int lowlimit;

  if (history_count == 0) {
    logmsg("history empty\n");
    return -1;
  }

  lowlimit = history_count - HISTORY_MAX;

  if (x > history_count || x <= lowlimit) {
    logmsg("only commands %d-%d are in history\n", lowlimit<0? 1 : lowlimit + 1, history_count);
    return (-1);
  }

  while (tmp->number != x)
    tmp = tmp->prev;

  copy_to_historyCmdLine(tmp->cmdline);
  history_ptr = NULL;
  return(0);
}

int history_next() {
  if (history_ptr == NULL) {
    history_ptr = history_lines_end;
    if (history_ptr == NULL)
      return(-1);
    copy_to_historyCmdLine(history_ptr->cmdline);
    return(0);
  }
  if (history_ptr->next == NULL)
    history_ptr = history_lines;
  else 
    history_ptr = history_ptr->next;
  copy_to_historyCmdLine(history_ptr->cmdline);
  return(0);
}

int history_prev() {
  if (history_ptr == NULL) {
    history_ptr = history_lines_end;
    if (history_ptr == NULL)
      return(-1);
    copy_to_historyCmdLine(history_ptr->cmdline);
    return(0);
  }
  if (history_ptr->prev == NULL)
    history_ptr = history_lines_end;
  else 
    history_ptr = history_ptr->prev;
  copy_to_historyCmdLine(history_ptr->cmdline);
  return(0);
}
