#include <curses.h>
#ifdef __NetBSD__
#include <termios.h>
#endif
#include "roloP.h"
#include "arrows.h"

void Cleanup()
{
  endwin();
}

#ifdef _STANDOUT
#define waddchso(win,ch) waddch((win),(ch)|_STANDOUT)
#else
#define waddchso(win,ch) waddch((win),(ch)); waddch((win),')')
#endif

WINDOW *w;
WINDOW *inst;
WINDOW *listWin;
int linew, linec;
int top_of_screen;
int active_line;
int re_x, re_y;

void Startup()
{

  w = initscr();

  inst = subwin(stdscr,2,COLS-4,LINES-2,1);
  waddchso(inst,'A');
  waddstr(inst,"dd Card  ");
  waddchso(inst,'D');
  waddstr(inst,"elete Card  ");
  waddchso(inst,'R');
  waddstr(inst,"edraw  ");
  waddchso(inst,'Q');
  waddstr(inst,"uit  ");
  waddchso(inst,'C');
  waddstr(inst,"lear Filter  ");
  waddchso(inst,'F');
  waddstr(inst,"ilter: ");
  getyx(inst,re_y,re_x);

  linew = COLS;
  linec = LINES - 3;
  listWin = subwin(stdscr,linec,linew,0,0);
  leaveok(stdscr,FALSE);
  leaveok(listWin,FALSE);
  leaveok(inst,FALSE);

  top_of_screen = active_line = 0;

  idlok(listWin,TRUE);
  cbreak();
  noecho();
#if defined(SYSV) || defined(__osf__) || defined(__NetBSD__)
  atexit(Cleanup);
#else
  on_exit(Cleanup,NULL);
#endif

  get_arrow_info();
}

int c;

void ShowMain()
{
  /*PutListOnScreen();*/
}

void GetInput()
{
  c = getch();
}

int InputEq(n)
     int n;
{
  return ( c == n );
}

static void mygetstr(win,str)
     WINDOW *win;
     char *str;
{
  int c, sx, sy, cx, n;
  char killc, erasec;

  erasec = erasechar();
  killc = killchar();
  getyx(win,sy,sx);
  cx = 0;
  str[0] = '\0';

  c = wgetch(win);
  while ( c != '\n' && c != '\r' ) {
    if ( c == erasec ) {
      if ( cx > 0 ) {
        cx--;
        mvwaddch(win,sy,sx+cx,' ');
      }
    } else if ( c == killc ) {
      wmove(win,sy,sx);
      for ( n = 0; n < cx; n++ )
	waddch(win,' ');
      cx = 0;
    } else {
      str[cx] = c & 255;
      cx++;
      waddch(win,c);
    }
    wmove(win,sy,sx+cx);
    wrefresh(win);
    c = wgetch(win);
  }
  str[cx] = '\0';
}

void DoFilter()
{
  char buf[500];

  wmove(inst,re_y,re_x);
  wclrtoeol(inst);
  wrefresh(inst);
  mygetstr(inst,buf);
  RoloFilter(buf);
  top_of_screen = active_line = 0;
  PutListOnScreen();
}

void ClearFilter()
{
  RoloFilter(NULL);
  wmove(inst,re_y,re_x);
  wclrtoeol(inst);
  wrefresh(inst);
  PutListOnScreen();
}

#ifndef DEFAULT_EDITOR
#ifdef SYSV
#define DEFAULT_EDITOR "/usr/bin/vi"
#else
#define DEFAULT_EDITOR "/usr/ucb/vi"
#endif
#endif

void ShowDetail(n)
     int n;
{
  RoloRec *rr;
  char *fn, *ed, cmd[500];
  char name[STRSIZE], number[STRSIZE], number2[STRSIZE], text[STRSIZE];
  extern char *getenv();
  FILE *f;
  int cnt, same;

  if ( n < 0 ) rr = NULL;
  else rr = GetN(n);

  fn = tmpnam(NULL);
  f = fopen(fn,"w");
  if ( f == NULL ) return;
  if ( rr != NULL )
    fprintf(f,"%s\n%s\n%s\n%s",
	    (rr->name==NULL)?"":rr->name,
	    (rr->number==NULL)?"":rr->number,
	    (rr->number2==NULL)?"":rr->number2,
	    (rr->text==NULL)?"":rr->text);
  else
    fprintf(f,"\n\n\n");
  fclose(f);

  ed = getenv("EDITOR");
  if ( ed == NULL )
    ed = DEFAULT_EDITOR;
  sprintf(cmd,"%s %s",ed,fn);
  system(cmd);
  clearok(curscr,TRUE);

  f = fopen(fn,"r");
  if ( f == NULL ) return;
  fgets(name,STRSIZE,f);
  fgets(number,STRSIZE,f);
  fgets(number2,STRSIZE,f);
  cnt = fread(text,1,STRSIZE-1,f);
  text[cnt] = '\0';
  fclose(f);
  unlink(fn);

  if ( n < 0 ) same = 0;
  else {
    same = (( strcmp(name,rr->name) == 0 ) &&
	    ( strcmp(number,rr->number) == 0 ) &&
	    ( strcmp(number2,rr->number2) == 0 ) &&
	    ( strcmp(text,rr->text) == 0 ));
    if ( !same ) DeleteRoloCard(n);
  }

  if ( ! same ) {
    MakeNewRolo(name,number,number2,text,1);
    WriteRolo();
    PutListOnScreen();
  }
}

void NewCard()
{
  ShowDetail(-1);
}

void DoDir(dir)
  int dir;
{
  switch(dir) {
  case MY_KEY_UP:
    if ( active_line == top_of_screen ) {
      if ( active_line == 0 ) break;
      wmove(listWin,0,0);
      winsertln(listWin);
      top_of_screen--;
    }
    active_line--;
    PutLineOnScreen(active_line+1);
    PutLineOnScreen(active_line);
    break;
  case MY_KEY_DOWN:
    if ( active_line == NumRoloOn() - 1 ) break;
    if ( active_line == top_of_screen + linec - 1 ) {
      wmove(listWin,0,0);
      wdeleteln(listWin);
      top_of_screen++;
    }
    active_line++;
    PutLineOnScreen(active_line-1);
    PutLineOnScreen(active_line);
    break;
  case MY_KEY_RIGHT:
    active_line += (linec-1);
    top_of_screen += (linec-1);
    if ( top_of_screen + linec >= NumRoloOn() ) {
      active_line = NumRoloOn() - 1;
      if ( active_line < 0 ) active_line = 0;
      top_of_screen = NumRoloOn() - linec;
      if ( top_of_screen < 0 ) top_of_screen = 0;
    }
    PutListOnScreen();
    break;
  case MY_KEY_LEFT:
    active_line -= (linec-1);
    top_of_screen -= (linec-1);
    if ( top_of_screen < 0 ) {
      active_line = 0;
      top_of_screen = 0;
    }
    PutListOnScreen();
    break;
  }
}

void HandleEscape()
{
  c = do_escape(c);
  DoDir(c);
}

void Redraw()
{
  clearok(curscr,TRUE);
}

int Check(m)
     char *m;
{
  WINDOW *chWin;
  int c;

  chWin = newwin(2,COLS-4,LINES-2,1);
  wmove(chWin,re_y,re_x);
  wclrtoeol(chWin);
  wmove(chWin,re_y,re_x+2);
  waddstr(chWin,m);
  wrefresh(chWin);
  do
    c = wgetch(chWin);
  while ( c != 'y' && c != 'Y' && c != 'n' && c != 'N' );
  delwin(chWin);
  touchwin(inst);

  return ( c == 'y' || c == 'Y' );
}

void DeleteCard(n)
     int n;
{
  if ( ! Check("Really?") ) return;
  DeleteRoloCard(n);
  WriteRolo();
  if ( active_line > NumRoloOn() - 1 ) 
    active_line = NumRoloOn() - 1;
  PutListOnScreen();
}

void DoGoto()
{
  char s[2];
  int n, oa;

  if ( isalpha(c) && isupper(c) ) {
    s[0] = c;
    s[1] = '\0';
    n = GetIndex(s);
    if ( n < top_of_screen + linec && n >= top_of_screen ) {
      /* no scrolling needed */
      oa = active_line;
      active_line = n;
      PutLineOnScreen(oa);
      PutLineOnScreen(active_line);
    } else {
      /* scrolling needed */
      active_line = n;
      top_of_screen = NumRoloOn() - linec; /* lowest it should ever be */
      if ( n < top_of_screen ) top_of_screen = n;
      PutListOnScreen();
    }
  }
}

#define CTRL_L 12

main(argc,argv)
     int argc;
     char *argv[];
{
  InitRolo(argc,argv,1);
  SetupRolo();
  Startup();
  PutListOnScreen();
  while (1) {
    ShowMain();
    wmove(inst,re_y,re_x);
    refresh();
    wrefresh(listWin);
    wrefresh(inst);
    GetInput();
    if ( InputEq('q') ) return 0;
    else if ( InputEq('f') ) DoFilter();
    else if ( InputEq('a') ) NewCard();
    else if ( InputEq('c') ) ClearFilter();
    else if ( InputEq('\n') || InputEq('\r') || InputEq(' ') ) ShowDetail(active_line);
    else if ( InputEq(CTRL_L) ) Redraw();
    else if ( InputEq('r') ) Redraw();
    else if ( InputEq('d') ) DeleteCard(active_line);
    else if ( InputEq(ESCAPE) ) HandleEscape();
    else if ( InputEq('+') || InputEq('=') || InputEq('j') ) DoDir(MY_KEY_DOWN);
    else if ( InputEq('-') || InputEq('k') ) DoDir(MY_KEY_UP);
    else if ( InputEq(6) || InputEq(4) ) DoDir(MY_KEY_RIGHT);
    else if ( InputEq(2) || InputEq(21) ) DoDir(MY_KEY_LEFT);
    else DoGoto();
  }
}

