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

#include "util.h"
#include "history.h"

struct history {
  const char **cmdLines;
  /* This is a bit messy, I don't really need
     to keep track of firstIndex, next, and count,
     I could just keep a total.  But it works now
     and I don't want to risk messing it up. */
  int max,firstIndex,next,count;
};

struct history *historyAlloc(int max) {
  struct history *self=talloc(struct history,1);
  self->max=max;
  self->count=0;
  self->next=0;
  self->firstIndex=INITIAL_INDEX;
  self->cmdLines=talloc(const char *,max);
  { int i; for (i=0;i<self->max;i++) self->cmdLines[i]=NULL; }
  return self;
}

void historyFree(struct history *self) {
  int i;
  for (i=0; i<self->count; i++) free((char *)self->cmdLines[i]);
  free((char **)self->cmdLines);
  free(self);
}

int historyExpand(struct history *self,const char ** cmdLine) {
  if ((*cmdLine)[0]=='!') {
    int n;
    if ((*cmdLine)[1]=='!') n=-1; /* !! = !-1 */
    else n = atoi((*cmdLine)+1);

    if (n<0) n+=self->firstIndex+self->count;
    if (self->firstIndex <=n && n < self->firstIndex+self->count) {
      int i = (n - INITIAL_INDEX)  % self->max;
      *cmdLine=strclone(self->cmdLines[i]);
      fprintf(stderr,"%s\n",*cmdLine); 
    } else {
      if (n<self->firstIndex)
        fprintf(stderr,"I've forgotten event %d\n",n);
      else
        fprintf(stderr,"event %d hasn't happened yet\n",n);
      return -1;
    }
  }
  return 0;
}

void historyAdd(struct history *self,const char *cmdLine) {
  self->cmdLines[self->next]=strclone(cmdLine);
  self->next=(self->next+1) % (self->max);
  if (self->count<self->max) self->count++;
  else {
    self->firstIndex++;
  }
}

void historyList(struct history *self) {
  int i=(self->count<self->max)?0:self->next,j=0;
  assert(self);
  /* This needs to be a do-while b/c otherwise the loop will execute 0 instead
   * of self->max times (wraparound problem)
   */
  do {
    printf("%-6d%s\n",j+self->firstIndex,self->cmdLines[i]);
    i=(i+1) % (self->max);
    j++;
  } while (i!=self->next && j < self->count);
}
