#include "cons.h"
#include <stdio.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <signal.h>
#include <curses.h>

#define BIGSIZ 8192
#define puke(msg) { perror(msg); exit(1); }

FILE *fp;
struct conmon {
  int win; /* associated window */
  int osize; /* size of file excluding unread data */
  char serv[32];
  char fname[64];
  char buf[BIGSIZ];
  int bufdex;
} cm[64];

struct mywins {
  WINDOW *twin; /* title window */
  WINDOW *dwin; /* data window */
  char free;
  long tym;
} sw[64];

int numw=0, numserv=0, dietym=60, numfree=0;

main(argc,argv)
int argc;
char *argv[];
{
  int lfd, n, i, j, nc;
  char ch[BIGSIZ], log[32], dum[32], **namelist, optc;
  char beep=0, col2=0, optdone=0, incld=0, xcld=0, skip=0;
  int wlin=5, wcol;
  struct stat st;
  extern int optind;
  extern char *optarg;
  void leave(), checkold(), freewin();

/* options to add:
     -f list of filenames to tail
*/

  while ((optc = getopt(argc, argv, "2bixl:t:w:")) != EOF) {
    switch (optc) {
    case 'b':
      beep=1;
      break;
    case '2':
      col2=1;
      break;
    case 'i':
      incld=1;
      break;
    case 'x':
      xcld=1;
      break;
    case 'w':
      numw=atol(optarg);
      break;
    case 'l':
      wlin=atol(optarg);
      break;
    case 't':
      dietym=atol(optarg);
      break;
    case '?':
      fprintf(stderr, "usage: conview [-2] [-b] [-w number of windows] [-l lines per window]\n               [-t timeout] [-x server exclude list] [-i server include list]\n");
      exit(1);
      break;
    }
    if (incld || xcld) {
      namelist=argv+optind;
      break;
    }
  }

  /* read the config file */
  if ((fp=fopen("/n/pun/0/console/constab","r")) == NULL) puke ("fopen");
  while(fgets(ch,127,fp) != NULL) {
    if (ch[0] != '#') {
      sscanf(ch,"%[^:]:%[^:]:%[^:]:%d\n",cm[numserv].serv,dum,log,dum);
      if (xcld) {
        skip=0;
        for (j=0; namelist[j] != NULL; ++j) {
/*     if (strncmp(namelist[j],cm[numserv].serv,strlen(namelist[j])) == 0) { */
          if (strcmp(namelist[j],cm[numserv].serv) == 0) {
            skip=1;
            break;
          }
        }
        if (skip) continue;
      }
      else if (incld) {
        skip=1;
        for (j=0; namelist[j] != NULL; ++j) {
/*     if (strncmp(namelist[j],cm[numserv].serv,strlen(namelist[j])) == 0) { */
          if (strcmp(namelist[j],cm[numserv].serv) == 0) {
            skip=0;
            break;
          }
        }
        if (skip) continue;
      }
      if (strcmp(log,"/dev/null") == 0) continue;
      sprintf(cm[numserv].fname,"/n/pun/0/console/%s\0",cm[numserv].serv);
      if (stat(cm[numserv].fname,&st) == -1) puke(cm[numserv].fname);
      cm[numserv].osize=st.st_size;
      cm[numserv].win=(-1);
      cm[numserv].bufdex=0;
      cm[numserv].serv[strlen(cm[numserv].serv)]='\0';
      ++numserv;
    }
  }
  fclose(fp);

  signal(SIGINT,leave);
  signal(SIGALRM,checkold);
  alarm(dietym/4);
  initscr();
  if (numw) {
    if (col2) numw=(numw+1)/2; /* round up;  it will be mult by 2 below */
    wlin=LINES/numw-1;
  }
  else numw=LINES/(wlin+1);
  wcol=COLS;
  if (col2) {
    numw *= 2;
    wcol=wcol/2-1;
  }
  numfree=numw;
  for (i=0; i<numw; ++i) {
    if (col2) {
      sw[i].twin=subwin(stdscr,1,wcol,(i/2)*(wlin+1),(i%2)*wcol+(i%2)*2);
      sw[i].dwin=subwin(stdscr,wlin,wcol,(i/2)*(wlin+1)+1,(i%2)*wcol+(i%2)*2);
    }
    else {
      sw[i].twin=subwin(stdscr,1,0,i*(wlin+1),0);
      sw[i].dwin=subwin(stdscr,wlin,0,i*(wlin+1)+1,0);
    }
    scrollok(sw[i].dwin,TRUE);
    sw[i].free=1;
    sw[i].tym=0;
  }

  /* go ahead and send some ctrl characters as is (more or less) */
  /* ctrl-M in curses clears current line, so force it to come after ctrl-J */
  _unctrl['']=""; /* ctrl-M */
  _unctrl[10]="\n\r"; /* ctrl-J */
  _unctrl[9]="\t"; /* tab */
  _unctrl['']=""; /* bell */

  refresh();

  while (1) {
    for (i=0; i<numserv; ++i) {
      if (stat(cm[i].fname,&st) == -1) puke(cm[i].fname);
      if(st.st_size == cm[i].osize) continue;
      lfd = open (cm[i].fname,O_RDONLY);
      if (lfd == -1) puke(cm[i].fname);
      n=lseek(lfd,cm[i].osize,L_SET);  /* go to EOF */
      nc=read(lfd,(cm[i].buf+cm[i].bufdex),BIGSIZ);
      cm[i].osize+=nc;
      if (nc > 0) {
        cm[i].buf[cm[i].bufdex+nc]='\0';
        spitout(i,cm[i].bufdex+nc);
      }
      close(lfd);
    }
  }
}

spitout(sern,len)
int sern, len;
{
  int i, j, oldest, oldtym;
  char *ptr;

  ptr=cm[sern].buf;
  if (cm[sern].win == -1) {
    if (numfree == 0) { /* no free ones - free the oldest one */
      oldtym=time(NULL);
      oldest=0;
      for (j=0; j<numserv; ++j)
        if (cm[j].win == -1) continue;
        else if (sw[cm[j].win].tym < oldtym) {
          oldtym=sw[cm[j].win].tym;
          oldest=j;
        }
      freewin(oldest);
    }
    for (i=0; i<numw; ++i)
      if (sw[i].free) {
        cm[sern].win=i;
        sw[i].free=0;
        wstandout(sw[cm[sern].win].twin);
        mvwaddstr(sw[cm[sern].win].twin,0,5,"---------- ");
        waddstr(sw[cm[sern].win].twin,cm[sern].serv);
        waddstr(sw[cm[sern].win].twin," ----------");
        wstandend(sw[cm[sern].win].twin);
        --numfree;
        break;
      }
  }
  sw[cm[sern].win].tym=time(NULL);
  for(i=0; i<len; ++i) {
    waddstr(sw[cm[sern].win].dwin,unctrl(cm[sern].buf[i]));
  }
  wmove(sw[cm[sern].win].twin,0,0);
  waddstr(sw[cm[sern].win].twin,"****");
  refresh();
  wmove(sw[cm[sern].win].twin,0,0);
  waddstr(sw[cm[sern].win].twin,"    ");
}

void freewin(sern)
int sern;
{
  if (cm[sern].win == -1) return;
  werase(sw[cm[sern].win].twin);
  werase(sw[cm[sern].win].dwin);
  sw[cm[sern].win].free=1;
  cm[sern].win=(-1);
  ++numfree;
}

void checkold()
{
  int i;
  long t;
  void freewin();

  t=time(NULL);
  for (i=0; i<numserv; ++i)
    if (cm[i].win == -1) continue;
    else if (t-sw[cm[i].win].tym > dietym) freewin(i);
  alarm(dietym/4);
}

void leave()
{
  endwin();
  exit(1);
}
