
#ifndef HISTORYC
#define HISTORYC 1
#pragma once

#include <String.h>
#include <errno.h>
#include "other.h"


//
// class History is a finite length record of the last appended characters.
//
// History(int sz) creates a record of size sz.
//   There is a default History().
//   The record is never longer than size sz.
//   Only the last sz characters Append'ed are kept.
//   The record origininally consists of spaces.
//
// Initialize() sets the records to all nulls.
//
// Append(char*pc,int nchars) appends to the end of the record.
//
// bool Match(char*str,int range) indicates if string str occurs in the record,
//   and ends within (_nonzero_) range characters of the end of the record.
//   It is an error for range+strlen(str) to exceed record sz.
//
// Implementation:
//   Buffers are 1 longer than buflen.
//   Two buffers are alternated.
//   Not very efficient.
//
//
// Notes:
//   Handling of overly long strlen+range Match arguments seems arbitrary.
//

class History {
  int      buflen =0;

  char     *hist1;      // two alterternating character buffers
  char     *hist2;

  char     *hist_crnt;  // pointers to current and next buffers
  char     *hist_next;

 public:
  History() { History(30); };
  History(int sz);

  void     Initialize();

  void     Append (char*chars, int nchars);

  bool     Match  (char*str, int within_what_nonzero_distance_of_last);
};

inline History::History (int sz)
{
  buflen = (sz > 0) ? sz : 1;
  hist1 = (char*) malloc(buflen+1);
  hist2 = (char*) malloc(buflen+1);
  if(!hist1 || !hist2) {perror("History::History: memory allocation");exit(1);}
  Initialize();
}

inline void History::Initialize()
{
  char *p1 = hist1, *p2 = hist2;
  for(int i=0;i<buflen;i++) { *p1++ ='\000'; *p2++ ='\000'; }
  p1 =NULL; p2 =NULL;
  hist_crnt = hist1;
  hist_next = hist2;
}

inline void History::Append (char* buf, int nchars)
{
  if(nchars<=0) return;

  int use_last_nchars = (nchars<=buflen) ? nchars : buflen;
  char *first_char_used = &buf[nchars - use_last_nchars];

  int& hist_punt_nchars = use_last_nchars;
  int hist_keep_nchars = buflen - hist_punt_nchars;

  memcpy(hist_next,&hist_crnt[hist_punt_nchars],hist_keep_nchars);
  memcpy(&hist_next[hist_keep_nchars],first_char_used,use_last_nchars);

  char *tmp = hist_next;
  hist_next = hist_crnt;
  hist_crnt = tmp;
}

inline bool History::Match (char* str, int range)
{
  if(strlen(str)+range >buflen ||range<1)
    {fprintf(stderr,"History::Match-arguments out of range\n");exit(1);}

  char *p = &hist_crnt[buflen-strlen(str)];

  for(int i=0;i<range;i++)
    if(0==strncmp(p--,str,strlen(str))) return 1;

  return 0;
}

#endif
