
/* "UNTIL", a graphics editor,
   Copyright (C) 1985, 1990 California Institute of Technology.
   Original authors: Glenn Gribble, port by Steve DeWeerth
   Unix Port Maintainer: John Lazzaro
   Maintainers's address: lazzaro@hobiecat.cs.caltech.edu;
                          CB 425 CU Boulder/Boulder CO 91125. 

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (Version 1, 1989).

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
USA. */


/*******************************************************************************/
/*                                                                             */ 
/*  A bunch of stuff for displaying text menus and getting names               */
/*  cleaned up by steve - 9 May 1990                                           */
/*                                                                             */ 
/*******************************************************************************/

#include <p2c/p2c.h>

#include "name_stuff.h"


#ifndef NEWCRT_H
#include <p2c/newcrt.h>
#endif

#ifndef FILEPACK_H
#include <p2c/filepack.h>
#endif

#ifndef FS_H
#include <p2c/fs.h>
#endif

#ifndef MISC_H
#include <p2c/misc.h>
#endif


#define saMax           282  /* Max things in a StrArray = (128 col per line / 20 col per name)*47 lines*/
#define maxfiles        35   /* should be a multiple of 7 */



/* special records and arrays for alpha menu stuff */

typedef struct strrecord {
  Char name[40];
  short color;
  void *ptr;   /* random pointer to something */
} strrecord;

typedef strrecord strarray[saMax + 1];   /* data strings for pen text menu */

typedef struct kprecord {
  Char str[31];   /* actual text */
  short xp, yp;   /* position on screen */
  short wid;   /* width of select field */
  short col;   /* color */
} kprecord;

typedef kprecord kparray[11];   /* mainly for use in ANYVAR statements */
typedef kprecord kparr3[3];


boolean prompt_filename;



Local void waitfor(long centiseconds)
{
  long endtime;

  endtime = sysclock() + centiseconds;
  while (endtime > sysclock()) ;
}

Static boolean listdir_array(Char *dname_, strrecord *s, long *num)
{
  boolean Result;
  Char dname[fidleng + 1];
  fib dirfib;
  misc_catentry dirinfo;
  short numfiles;
  misc_catentry fileinfo[maxfiles];
  short i;
  /*num:shortint;  { current position in array */
  short max;   /* Maximum number of files in a display */
  strrecord *WITH;

  strcpy(dname, dname_);
  Result = true;
  /* first 2 filenames are special (also illegal file names) */
  strcpy(s[0].name, " --abort-- ");
  s[0].color = nc_cyan;
  strcpy(s[1].name, " .. ");
  s[1].color = nc_red;
  *num = 2;
  max = (nc_curWindow->height - 1) * (nc_curWindow->width / 20);

  TRY(try1);
    fp_open_dir(&dirfib, dname, &dirinfo);
    if (*dirfib.UU.ftitle != '\0') {
      printf("%s\007: not a directory\n", dname);
      P_escapecode = 10;
      goto _Ltry1;
    }
    do {
      numfiles = maxfiles;
      fp_cat_dir(&dirfib, &numfiles, (Anyptr)fileinfo);

      for (i = 0; i < numfiles; i++) {
	if (strpos2(fileinfo[i].cname, ".FF", 1) != 0 ||
	    fileinfo[i].ckind == untypedfile) {
	  WITH = &s[*num];
	  if (fileinfo[i].ckind == untypedfile)
	    WITH->color = nc_red;
	  else
	    WITH->color = nc_green;
	  strcpy(WITH->name, fileinfo[i].cname);
	  WITH->ptr = NULL;
	  (*num)++;
	  if (*num >= max) {
	    printf("\007\201Too many files in DIR!!\200\n");
	    waitfor(50);
	    putchar('\007');
	    waitfor(50);
	    putchar('\007');
	    goto _L1;   /* abort FOR and WHILE loops now!! */
	  }
	}
      }
    } while (numfiles >= maxfiles);
_L1:   /* abort FOR and WHILE loops */
    fp_close_dir(&dirfib);
  RECOVER2(try1,_Ltry1);
    Result = false;
    if (P_escapecode != 10)
      perror("directory");
    TRY(try2);
      fp_close_dir(&dirfib);
    RECOVER(try2);
      ;
    ENDTRY(try2);
  ENDTRY(try1);
  return Result;
}

#undef maxfiles


Static void show_strings(strrecord *s)
{
  short i, j, k, x;
  nc_windowRec *WITH;

  WITH = nc_curWindow;
  k = WITH->height - 1;

  for (j = 1; j <= k; j++) {
    nc_clearXY(0, j, WITH->width, 1);   /* clear current line */

    i = j - 1;
    x = 0;
    while (x + 20 <= WITH->width) {
      crt_write_str(x, j, s[i].name, 0, s[i].color);
      x += 20;
      i += k;
    }
  }
}


Local void cursit(strrecord *s, short last, short c23)
{
  short x, y;
  strrecord *WITH;

  x = last / c23 * 20;
  y = last % c23 + 1;
  WITH = &s[last];

  if ((WITH->color / nc_inv) & 1)   /* toggle inverse mode */
    WITH->color -= nc_inv;
  else
    WITH->color += nc_inv;
  crt_write_str(x, y, WITH->name, 0, WITH->color);
}

Static short getstrarray(strrecord *s)
{
  short last, c23;
  short cur;

  c23 = 23;
  if (!hasAlpha)
    c23 = 46;
  nc_setWindow_(nc_defaultWindow);

  show_strings(s);
  update_tablet();
  if (curPen.ay < 1)
    curPen.ay = 1;
  last = curPen.ax / 20 * c23 + curPen.ay - 1;
  if (last > saMax)
    last = saMax;
  acursoroff();
  cursit(s, last, c23);
  do {
    update_tablet();
    if (curPen.ay < 1)
      curPen.ay = 1;
    acursor(curPen.ax, curPen.ay);
    cur = curPen.ax / 20 * c23 + curPen.ay - 1;
    if (cur > saMax)
      cur = saMax;
    /* cur := curPen.ax div 20+curPen.ay*4-4;   old */
    if (last != cur) {
      cursit(s, last, c23);
      last = cur;
      cursit(s, last, c23);
    }
  } while (!(curPen.dn || nk_keybufsize() > 0));
  cursit(s, last, c23);
  acursoroff();
  if (nk_keybufsize() > 0)
    return -1;
  else
    return last;
}


Static int compare(void *a, void *b)
{
  strrecord *x, *y;

  x = a;
  y = b;

  /* Put empty strings last */
  if (*x->name == '\0')
    return 1;

  if (*y->name == '\0')
    return -1;

  if (strcmp(x->name, y->name) > 0)
    return 1;
  else
    return -1;
}

Static void sortstrarray(strrecord *s, long n)
{
  long i;

  /* null out remaining fields */
  *s[n].name = '\0';
  s[n].color = nc_green;
  s[n].ptr = NULL;
  for (i = n + 1; i <= saMax; i++)
    s[i] = s[n];

  qsort((void *)s, n, sizeof(strrecord),(int (*)()) compare);
}


Char *getfname(Char *Result, Char *start_)
{
  Char start[fidleng + 1];
  strarray s;
  short n;
  boolean done;
  long nfiles;
  Char STR1[130];
  Char STR2[140];
  Char *TEMP;

  strcpy(start, start_);
  do {
    do {
      sprintf(STR1, "Reading: %s", start);
      crt_write_str(0, 0, STR1, -80, nc_green);
      done = listdir_array(start, s, &nfiles);
      if (!done) {
	printf("Directory read failed. New directory? ");
	fgets(start, fidleng + 1, stdin);
	TEMP = (char *) strchr(start, '\n');
	if (TEMP != NULL)
	  *TEMP = 0;
	n = 0;   /* in case we abort */
	if (*start == '\0')
	  goto _L1;
      }
    } while (!done);
    sortstrarray(s, nfiles);
    printf("\f");
    sprintf(STR2, "Current directory: %s", start);
    crt_write_str(0, 0, STR2, -80, nc_cyan);
    n = getstrarray(s);
    if (n < 0) {
      printf("\001\tFile or ?directory: ");
      fgets(start, fidleng + 1, stdin);
      TEMP = (char *) strchr(start, '\n');
      if (TEMP != NULL)
	*TEMP = 0;
      done = true;
      if (*start != '\0' && start[0] == '?') {
	strcpy(start, start + 1);
	done = false;
      }
    } else {
      done = (s[n].color != nc_red);   /* red==directory */
      if (!done) {
	strcat(start, "/");
	strcat(start, s[n].name);
	fs_zapspaces(start);
      }
    }
  } while (!done);
_L1:
  if (n == 0)
    return strcpy(Result, "");
  else if (n < 0)
    return strcpy(Result, start);
  else if (start[strlen(start) - 1] != '/' && start[strlen(start) - 1] != ':') {
    sprintf(Result, "%s/%s", start, s[n].name);
    return Result;
  } else {
    sprintf(Result, "%s%s", start, s[n].name);
    return Result;
  }
}


Local short findit(short num, kprecord *strs)
{
  /* find which string we are in */
  short i;

  for (i = 0; i < num; i++)
    if (curPen.ay == strs[i].yp && curPen.ax >= strs[i].xp && curPen.ax < strs[i].xp + strs[i].wid)
      return i;

  return -1;
}

Local void cursit_(short laststr, kprecord *strs)
{
  if (laststr < 0)
    return;

  if ((strs[laststr].col / nc_inv) & 1)   /* toggle inverse mode */
    strs[laststr].col -= nc_inv;
  else
    strs[laststr].col += nc_inv;

  crt_write_str(strs[laststr].xp, strs[laststr].yp, strs[laststr].str, 0, strs[laststr].col);
}

/* return -1 if keyboard data becomes available before pen press */
Static short kbd_or_pen(short num, kprecord *strs)
{
  short laststr, curstr;   /* last, current string in strs */
  short i;

  for (i = 0; i < num; i++)
    crt_write_str(strs[i].xp, strs[i].yp, strs[i].str, 0, strs[i].col);

  if (nk_keybufsize() > 0)   /* already typeahead!! */
    return -1;

  update_tablet();
  laststr = findit(num, strs);
  acursoroff();
  cursit_(laststr, strs);
  while (!(curPen.dn && laststr >= 0) && nk_keybufsize() == 0) {
    update_tablet();
    acursor(curPen.ax, curPen.ay);
    curstr = findit(num, strs);
    if (laststr == curstr)
      continue;
    acursoroff();
    cursit_(laststr, strs);
    laststr = curstr;
    cursit_(laststr, strs);
    acursor(curPen.ax, curPen.ay);
  }

  cursit_(laststr, strs);
  acursoroff();
  if (nk_keybufsize() > 0)
    return -1;
  else
    return laststr;
}


typedef kprecord kparr2[2];


const kparr2 kpconst = {
  { " (Y", 0, 0, 3, nc_red },
  { "N)?", 4, 0, 3, nc_red }
};


boolean yes_no_quest(Char *pmpt)
{
  boolean Result;
  kparr2 kp;
  long x, y;
  short i;
  Char resp;

  memcpy(kp, kpconst, sizeof(kparr2));
  fputs(pmpt, stdout);
  nk_getxy(&x, &y);
  printf(" (Y/N)? ");
  for (i = 0; i <= 1; i++) {
    kp[i].xp += x;
    kp[i].yp += y;
  }
  do {
    i = kbd_or_pen(2, kp);
    if (i == 0)
      resp = 'Y';
    else if (i == 1)
      resp = 'N';
    else
      resp = nk_getkey();
  } while (resp != 'n' && resp != 'N' && resp != 'y' && resp != 'Y');

  Result = (resp == 'y' || resp == 'Y');
  return Result;
}


Static Char *getnames_setup(Char *Result, Char *pmpt, Char *def, Char *pmpt2, kprecord *kp_)
{
  kparr3 kp;
  long x, y;
  short i;

  memcpy(kp, kp_, sizeof(kparr3));
  fputs(pmpt, stdout);
  if (*def != '\0') {
    nk_getxy(&x, &y);
    strcpy(kp[2].str, def);
    kp[2].xp = x + 1;
    kp[2].yp = y;
    kp[2].wid = strlen(def);
    printf("[%s]", def);
  }

  nk_getxy(&x, &y);
  fputs(pmpt2, stdout);
  for (i = 0; i <= 1; i++) {
    kp[i].xp += x;
    kp[i].yp += y;
  }

  i = kbd_or_pen(3, kp);

  if (i == 0)
    return strcpy(Result, "?");
  else if (i == 1)
    return strcpy(Result, "-ABORT");
  else if (i == 2)
    return strcpy(Result, "");  /* default */
  else
    return gets(Result);
}


kparr3 kpconst_ = {
  { "?dir", 5, 0, 4, nc_red },
  { "-ABORT", 13, 0, 6, nc_red },
  { "", 0, 0, 0, nc_red }
};


Char *getfilename(Char *Result, Char *prompt_, Char *default__)
{
  Char prompt[81], default_[81];
  Char resp[fidleng + 1], STR1[fidleng + 1];
  Char STR2[256];

  strcpy(prompt, prompt_);
  strcpy(default_, default__);
  if (prompt_filename)
    getnames_setup(resp, prompt, default_, " (or ?dir or -ABORT) : ", kpconst_);
  else {
    strcpy(resp, "?");
    printf("\001%s", prompt);
    if (*default_ != '\0')
      printf(" default would have been [%s]", default_);
  }
  if (*resp == '\0')
    strcpy(resp, default_);
  else if (!strcmp(strupper(STR2, resp), "-ABORT"))
    *resp = '\0';
  else if (resp[0] == '?') {
    strcpy(resp, resp + 1);
    if (*resp == '\0')
      strcpy(resp, ":");
    strcpy(resp, getfname(STR1, resp));
    if (*resp != '\0' && resp[0] == ':')
      strcpy(resp, resp + 1);
    else if (*resp == '\0')
      strcpy(resp, default_);
    nk_gotoxy(0, 23);
    putchar('\t');
  }
  strcpy(Result, resp);
  return Result;
}


Char *getFigure(Char *Result)
{
  strarray s;
  short n, j;
  Char name[81];
  Char fn[17];
  fileSpec *filp;
  figure *figp;
  Char *TEMP;

  strcpy(s[0].name, " --abort-- ");   /* this must be first ! */
  s[0].color = nc_cyan;

  filp = files;
  j = 1;
  while (filp != NULL && j < saMax) {
    figp = filp->figures;
    strlower(name, filp->fileName);
    if (strends(name, ".ff"))
      name[strlen(name) - 3] = '\0';
    if (strposb(name, "/", 256) > 0)
      strcpy(name, name + strposb(name, "/", 256));
    sprintf(fn, "%s:", name);

    while (figp != NULL && j < saMax) {
      sprintf(s[j].name, "%s%s", fn, figp->name);
      s[j].color = nc_green;
      if (figp->changes != 0)
	s[j].color += nc_under;
      s[j].ptr = figp;
      j++;
      figp = figp->next;
    }
    filp = filp->next;
  }

  if (j >= saMax)
    printf("\007Too many figures (only showing %ld)\n", (long)saMax);

  sortstrarray(s, j);
  printf("\f");
  crt_center_str("Select a figure using pen", 0, nc_cyan);
  n = getstrarray(s);
  printf("\f");

  if (n == 0)
    strcpy(Result, "");
  else if (n > 0) {
    figp = s[n].ptr;
    if (figp == NULL)
      strcpy(Result, "");
    else
      strcpy(Result, figp->name);
  }
  else {
    printf("\001\n\t\037\tFigure name? ");
    fgets(name, 81, stdin);
    TEMP = (char *) strchr(name, '\n');
    if (TEMP != NULL)
      *TEMP = 0;
    strcpy(Result, name);
  }
  return Result;
}
