#include "bbs.h"


int addstrtoliste(tlistetyp **tl, const boolean copy, const int k,
                  const int blocklen, char *str, confrecordtyp *confrecord)
{
  int blocknr, blockidx, nr, s;
  boolean neu = FALSE;
  tlistetyp *tlp;

  blocknr = k / blocklen;
  blockidx = k - blocknr * blocklen;

  if (*tl == (tlistetyp *)0) {
    if ((*tl=malloc(sizeof(tlistetyp))) == NULL) {
      errormsg(E_LOGFILE|E_USER,confrecord,"bbs","addstrtoliste","malloc: %m");
      return(-1);
    }
    if (((*tl)->tp=malloc((blocklen*sizeof(char *)))) == NULL) {
      errormsg(E_LOGFILE|E_USER,confrecord,"bbs","addstrtoliste","malloc: %m");
      exit(-1);
    }
    for (s=0; s<blocklen; s++) (*tl)->tp[s] = (char *)0;
    (*tl)->nr = 0;
    (*tl)->prec = (tlistetyp *)0;
    (*tl)->next = (tlistetyp *)0;
  }
  
  while ((*tl)->nr > blocknr && (*tl)->prec != (tlistetyp *)0) {
    *tl = (*tl)->prec;
  }
  
  while ((*tl)->nr < blocknr && (*tl)->next != (tlistetyp *)0) {
    *tl = (*tl)->next;
  }
    
  while ((*tl)->nr < blocknr) {
    neu = TRUE;
    if (((*tl)->next=malloc(sizeof(tlistetyp))) == NULL) {
      errormsg(E_LOGFILE|E_USER,confrecord,"bbs","addstrtoliste","malloc: %m");
      return(-1);
    }
    nr = (*tl)->nr + 1;
    tlp = (*tl)->next;
    tlp->prec = *tl;
    *tl = (*tl)->next;
    (*tl)->nr = nr;
    (*tl)->next = (tlistetyp *)0;
    if (((*tl)->tp=malloc((blocklen*sizeof(char *)))) == NULL) {
      errormsg(E_LOGFILE|E_USER,confrecord,"bbs","addstrtoliste","malloc: %m");
      exit(-1);
    }
    for (s=0; s<blocklen; s++) (*tl)->tp[s] = (char *)0;
  }

  if ((*tl)->nr == blocknr) {
    if (copy) {
      if (neu) free((*tl)->tp[blockidx]);
      if (((*tl)->tp[blockidx]=malloc((strlen(str)+1)*sizeof(char)))==NULL) {
        errormsg(E_LOGFILE|E_USER,confrecord,"bbs","addstrtoliste",
	         "malloc: %m");
        exit(-1);
      }
      strcpy((*tl)->tp[blockidx],str);
    }
    else {
      (*tl)->tp[blockidx] = str;
    }
  }
  else {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","addstrtoliste",
             "step too large");
    return(-1);
  }
  return(0);
}


int readliste(tlistetyp **tl, const boolean copy, const int k,
              const int blocklen, char **str, confrecordtyp *confrecord)
{
  int blocknr, blockidx;

  if (k < 0) {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","readliste","Index < 0");
    return(-1);
  }
  blocknr = k / blocklen;
  blockidx = k - blocknr * blocklen;

  while ((*tl)->nr<blocknr && (*tl)->next!=(tlistetyp *)0) {
    *tl = (*tl)->next;
  }

  while ((*tl)->nr>blocknr && (*tl)->prec!=(tlistetyp *)0) {
    *tl = (*tl)->prec;
  }

  if ((*tl)->nr != blocknr) {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","readliste","indexoverflow");
    return(-1);
  }
  if ((*tl)->tp[blockidx] == (char *)0) {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","readliste",
             "string point to 0");
    return(-1);
  }
  if (copy) {
    strcpy(*str,(*tl)->tp[blockidx]);
  }
  else {
    *str = (*tl)->tp[blockidx];
  }
  return(0);    
}


int removeliste(tlistetyp *tl, const boolean copy, const int blocklen)
{
  int k;
  
  while(tl->prec != (tlistetyp *)0) tl = tl->prec;
  while(tl->next != (tlistetyp *)0) {
    if (copy) {
      for (k=0; k<blocklen; k++) {
        if (tl->tp[k] != (char *)0) free(tl->tp[k]);
      }
    }
    free(tl->tp);
    tl = tl->next;
    free(tl->prec);
  }
  if (copy) {
    for (k=0; k<blocklen; k++) {
      if (tl->tp[k] != (char *)0) free(tl->tp[k]);
    }
  }
  free(tl->tp);
  free(tl);
  return(0);
}


void sortliste(tlistetyp *tl, const int blocklen, const int anz,
               confrecordtyp *confrecord)
{
  void sort_liste(tlistetyp *, const int, const int, const int,
                  confrecordtyp *);
  
  if (anz > 1)  sort_liste(tl, blocklen, 0, anz-1, confrecord);
  return;
}


void sort_liste(tlistetyp *tl, const int blocklen, const int k1, const int k2,
                confrecordtyp *confrecord)
{
  int i, j;
  char *x, *xi, *xj;
  
  i = k1; j = k2;
  readliste(&tl,FALSE,(k1+k2)/2,blocklen,&x,confrecord);
  do {
    do {
      readliste(&tl,FALSE,i,blocklen,&xi,confrecord);
      i++;
    } while (strcmp(xi,x) < 0 && i <= k2);
    i--;
    do {
      readliste(&tl,FALSE,j,blocklen,&xj,confrecord);
      j--;
    } while (strcmp(xj,x) > 0 && j >= k1);
    j++;
    if (i <= j) {
      addstrtoliste(&tl,FALSE,i,blocklen,xj,confrecord);
      addstrtoliste(&tl,FALSE,j,blocklen,xi,confrecord);
      i++; j--;
    }
  } while (i <= j);
  if (k1 < j)  sort_liste(tl,blocklen,k1,j,confrecord);
  if (i < k2)  sort_liste(tl,blocklen,i,k2,confrecord);
  return;
}


char tlpager(tlistetyp *tliste, const int anz, const char *header,
             confrecordtyp *confrecord)
{
  int kopfzeilen, lines, zstep, offset, ypos, kmax, k, n, lang;
  char prompt[S_STRLEN+1], *sp, key;
  char cset[] = {SPACE_KEY,BACKSPACE_KEY,DELETE_KEY,'Q','\0'};

  lang = confrecord->userrecord.lang;
  kopfzeilen = 2;
  lines = confrecord->userrecord.lines - kopfzeilen -1;
  zstep = lines - 2;
  offset = 0;
  move(0,0);
  clear();
  addstr(header);
  do {
    move(kopfzeilen,0);
    clrtobot();
    kmax = offset+lines > anz ? anz : offset+lines;
    for (k=offset,n=0; k<kmax; k++,n++) {
      ypos = kopfzeilen + k - offset;
      readliste(&tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
      move(ypos,2);
      addstr(sp);
    }
    if (anz > lines) {
      if (offset+lines < anz) {
        if (offset == 0) {
          strcpy(prompt,msg("tlpager",1,lang));
	}
	else {
	  sprintf(prompt,msg("tlpager",2,lang),offset);
	}
      }
      else {
        strcpy(prompt,msg("tlpager",0,lang));
      }
    }
    else {
      if (anz > 0) {
        strcpy(prompt,msg("tlpager",3,lang));
      }
      else {
        strcpy(prompt,msg("tlpager",4,lang));
      }
    }
    key = getkeyonprompt(prompt,cset,TRUE,FALSE,confrecord);
    if (pagerstep(key) < 0) {
      offset -= zstep;
    }
    else if (pagerstep(key) > 0) {
      offset += zstep;
    }
    if (offset > anz-lines) offset = anz-lines;
    if (offset < 0) offset = 0;
  } while (pagerquit(key) == 0);
  
  return(key);
}
