/*  026  02-Jun-87  ovdef.c

        Copyright (c) 1987 by Blue Sky Software.  All rights reserved.
*/

#include <stdio.h>
#include "ov.h"
#include "overr.h"
#include "menu.h"
#include "dialog.h"
#include "direct.h"

#define CFG_VERSION 2  /* <======<<<< incr when parameter file layout changes */

extern WINDOW cw;                      /* current window structure */

extern unsigned char vid_mode;         /* need to know video mode */
extern unsigned char vid_attrib;       /* we hack directly with video attrib */
extern unsigned char restricted;       /* NZ when some functions disabled */
extern unsigned char def_display;      /* NZ when define screen displayed */
extern unsigned char attribs[];        /* array of attrib's */
extern char *cantopen;                 /* common text message */

extern MENU top_file_menu[], *top_menu;

int def_color(), def_exit(), def_pag(), def_udk();
int def_set(), def_noset(), def_reset(), def_snow(), def_nosnow();

static MENU snow_menu[] = {
   { "Disable", "Disable \"snow\" checking", def_nosnow, NULL },
   { "Enable",  "Enable \"snow\" checking", def_snow, NULL },
   { NULL, NULL, NULL, NULL }
};

static MENU set_attr_menu[] = {
   { "Set", "Set color attributes to values shown", def_set, NULL },
   { "Reset", "Reset color attributes to prior values", def_reset, NULL },
   { "Quit", "Quit without changing color attributes", def_noset, NULL },
   { NULL, NULL, NULL, NULL }
};

static MENU top_def_menu[] = {
   { "Colors", "Select video display attributes", def_color, set_attr_menu },
   { "Snow", "Enable/disable video \"snow\" checking", NULL, snow_menu },
   { "Point-and-Go", "Modify Point-and-Go parameters", def_pag, NULL },
   { "UDK", "Modify User Defined Keys", def_udk, NULL },
   { "Quit", "Quit chaning Define parameters", def_exit, top_file_menu },
   { NULL, NULL, NULL, NULL }
};

static char *def_text[] =
   { "NORMAL TEXT            ", "HIGHLIGHTED TEXT       ",
     "WINDOW TEXT            ", "HIGHLIGHTED WINDOW TEXT",
     "HEADING TEXT           ", "BACKGROUND TEXT        ",
     "TAGGED FILE NAME TEXT  " };

static char *directions[] = {
     "PgUp & PgDn select the ", "type of text to be set.",
     "                       ", "\x18\x19\x1b\x1a select the colors." };

static int changed;
static int text_type;
static char *ovcfg = "OV.CFG";
static unsigned char newattr[7];
static char dirliteral[] = "Directions";
static char ent2up[] = "Enter number to update:";

/* allocate the dialog boxes and fields for def_*() routines */

static D_BOX text_box =  { 3, 2, 7, 25, NULL, NULL };
static D_BOX video_box = { 3, 30, 16, 48, NULL, NULL };
static D_BOX dir_box =   { 14, 2, 4, 25, NULL, dirliteral };
static D_BOX pag_box =   { 7, 10, 14, 61, NULL, "Set Point-and-Go Parameters" };
static D_BOX udk_box =   { 7, 10, 14, 62, NULL, "Set User-Defined-Keys" };
static D_FLD pag_fld;
static D_FLD udk_fld;

/****************************************************************************
 Following is the parameter area which holds all user specified parameters.
 This area is updated by the routines in OVDEF.C.  Be very very careful when
 modifying this area.  Make sure that routine def_write() is correct.
 ****************************************************************************/

static unsigned char cfgver = CFG_VERSION;   /* config layout version # */

unsigned char vid_snow = 1;            /* NZ if must chk for video snow */

/* Define the video display attributes.  One set for mono, one for CGA. */
/* The attributes are in the following order:                           */
/* DIS_NORM, DIS_HIGH, DIS_BOX, DIS_HIBOX, DIS_HEAD, DIS_TEXT, DIS_TAGD */

unsigned char monattr[] = { 0x07, 0x70, 0x0F, 0x70, 0x70, 0x07, 0x0F }; /*mono*/
unsigned char cgaattr[] = { 0x0B, 0x30, 0x0E, 0x30, 0x1B, 0x0A, 0x0E }; /* cga*/

/* Define the Point-and-Go parameters and the User-Defined-Keys */

PAG_ENT pag_tbl[NUM_PAG];
UDK_ENT udk_tbl[NUM_UDK];

/*****************************************************************************
                         End of parameter area
 *****************************************************************************/

char *getenv(), *strchr();
FILE *fopen(), *pathopen();

#ifdef LINT_ARGS
void dispagent(int), rdpagent(int);
void disudkent(int), rdudkent(int);
void ALTCALL rdyesno(D_BOX *, D_FLD *, unsigned char *, int);
char * ALTCALL rd_p_u_fld(D_BOX *, D_FLD *, int, int, char *);
void ALTCALL pag_or_udk(D_BOX *, void (*)(), void (*)(), int, char *);
#else
char * ALTCALL rd_p_u_fld();
void dispagent(), rdpagent();
void disudkent(), rdudkent();
void ALTCALL rdyesno(), ALTCALL pag_or_udk();
#endif

/*****************************************************************************
                               D E F I N E
 *****************************************************************************/

define() {     /* allow user to define various parameters */

   changed = FALSE;            /* nothing changed so far    */
   restricted = TRUE;          /* don't allow some commands */
   top_menu = top_def_menu;    /* make define menu THE menu */
}


/*****************************************************************************
                            D E F _ E X I T
 *****************************************************************************/

static int
def_exit() {           /* leave define screen parameters mode */

   int write;

   /* if the user changed anything, ask him if the parameters should be
      written to disk.  If he says yea, then do it. */

   if (changed) {
      write = ask("Write changed parameters to disk? (y/N): ");
      if (yes(write))
         def_write();
   }

   top_menu = top_file_menu;           /* file menu again */
   restricted = FALSE;                 /* allow everything again */
}


/*****************************************************************************
                            D E F _ C O L O R
 *****************************************************************************/

static int
def_color() {          /* define screen "colors" */

   strncpy(newattr,attribs,sizeof(newattr));   /* start with current attribs */

   def_display = TRUE;                 /* define color display is active */
   restricted = FALSE;                 /* allow the cursor keys to work  */
   top_menu = set_attr_menu;           /* so ESC doesn't leave this menu */

   def_init();                         /* actually setup the color display */

   select_t(1,text_type = DIS_NORM);   /* highlight normal text first */
   select_a(1,newattr[text_type]);     /* highlight current attr location */
}


/*****************************************************************************
                            D E F _ x S E T
 *****************************************************************************/

static int
def_set() {            /* use the currently displayed video attributes */

   changed = TRUE;                             /* assume they changed some */
   strncpy(attribs,newattr,sizeof(newattr));   /* SET the current values */
   do_set();                                   /* rest of stuff */
}

static int
def_noset() {          /* back to the prior values */

   strncpy(newattr,attribs,sizeof(newattr));   /* back to current */
   do_set();
}

static int
def_reset() {          /* reset to OverView default/config file value */

   changed = TRUE;                             /* assume some change */
   strncpy(attribs,vid_mode == 7 ? monattr : cgaattr,sizeof(newattr));
   strncpy(newattr,attribs,sizeof(newattr));   /* back to default */
   do_set();
}

static int
do_set() {
   setup_file_scr();                           /* rewrite file screen */
   update_header();                            /* to use possible new colors */
   refresh_screen(0);

   restricted = TRUE;                          /* disable cursor keys    */
   def_display = FALSE;                        /* back to normal display */
   top_menu = top_def_menu;                    /* back to define menu    */
}


/*****************************************************************************
                            D E F _ I N I T
 *****************************************************************************/

static int
def_init() {           /* initialize the define colors screen */

   int i, fg;
   register int bg;

   /* initialize the screen image */

   setvattrib(DIS_NORM);

   clr_scr();
   center_text(0,"DEFINE SCREEN COLORS");

   disp_status();                              /* status line */

   setvattrib(DIS_BOX);                        /* box to enclose text types */
   dbx_open(&text_box,0);

   for (i = DIS_NORM; i <= DIS_TAGD; i++)      /* display text types */
      select_t(0,i);

   setvattrib(DIS_BOX);                        /* box to enclose pattern */
   dbx_open(&video_box,0);

   for (fg = 0; fg < 16; fg++) {               /* display color pattern */
      dbx_goto(&video_box,fg,0);
      for (bg = 0; bg < 8; bg++) {
         vid_attrib = (bg << 4) | fg;
         disp_str(" TEXT ");
      }
   }

   setvattrib(DIS_BOX);               /* box for directions/instructions */
   dbx_open(&dir_box,0);

   for(i = 0; i < 4; i++)                      /* display the directions */
      dbx_disp(&dir_box,directions[i],i,1);

   setvattrib(DIS_NORM);       /* back to "Normal" */

}


/****************************************************************************
                          P A G _ O R _ U D K
 ***************************************************************************/

void ALTCALL
pag_or_udk(dbp,df,rf,num_ent,head)     /* define PAG or UDK entries */
D_BOX *dbp;
void (*df)();
void (*rf)();
int num_ent;
char *head;
{
   char *tmp;
   register int i;
   static D_FLD num_fld = { 13, 40, 3, 0, "   " };

   /* pop up the dialog box to use */

   setvattrib(DIS_BOX);                /* open dialog box */
   dbx_open(dbp,DBX_SAVE);

   setvattrib(DIS_HEAD);               /* display header */
   dbx_disp(dbp,head,0,0);

   setvattrib(DIS_BOX);                /* display existing entries */
   for (i = 0; i < num_ent; i++)
      (*df)(i);

   dbx_disp(dbp,ent2up,13,16);         /* entry to update msg */

   /* read entries from user */

   while (TRUE) {
      setvattrib(DIS_HIBOX);

      if (!*(tmp = dbx_rdfld(dbp,&num_fld)))   /* get # of ent to read */
         break;

      i = atoi(tmp) - 1;                       /* ascii to integer     */

      if (i >= 0 && i < num_ent) {             /* within range?        */
         (*df)(i);                             /* disp ent with HIBOX  */
         (*rf)(i);                             /* read it from user    */
         setvattrib(DIS_BOX);                  /* redisplay with BOX   */
         (*df)(i);                             /* disp ent with HIBOX  */
      }
   }

   setvattrib(DIS_NORM);       /* back to normal */

   dbx_close(dbp);             /* close the dialog box */
}


/*****************************************************************************
                              D E F _ P A G
 *****************************************************************************/

static int
def_pag() {    /* define the Point and Go parameters */

   pag_or_udk(&pag_box,dispagent,rdpagent,NUM_PAG,
              " NUM EXT  COMMAND PROTOTYPE                       PAUSE READ ");
}


/**************************************************************************
                           D I S P A G E N T
 **************************************************************************/

#define NUM_COL (1)            /* offsets within the PAG dialog box */
#define EXT_COL (5)
#define CMD_COL (10)
#define PAUSE_COL (52)
#define READ_COL (58)

static void
dispagent(ent) /* display PAG entry number ent */
int ent;
{
   int row = ent + 2;
   register PAG_ENT *pp = &pag_tbl[ent];

   dbx_goto(&pag_box,row,NUM_COL);
   out_int(ent+1,3,' ');
   dbx_goto(&pag_box,row,EXT_COL);
   out_str(pp->used ? pp->ext : "",sizeof(pp->ext)-1,' ');
   dbx_goto(&pag_box,row,CMD_COL);
   out_str(pp->used ? pp->cmd : "",sizeof(pp->cmd)-1,' ');
   dbx_disp(&pag_box,pp->used ? (pp->pause ? "Y" : "N") : " ",row,PAUSE_COL);
   dbx_disp(&pag_box,pp->used ? (pp->reload ? "Y" : "N") : " ",row,READ_COL);
}

/*****************************************************************************
                              R D P A G E N T
 ****************************************************************************/

static void
rdpagent(ent)  /* read a PAG entry from the user */
int ent;
{
   int row = ent + 2;
   register PAG_ENT *pp = &pag_tbl[ent];

   pag_fld.pos = 0;
   pag_fld.row = row;

   /* read the ext field for this entry, if nothing is read, blank (delete)
      this entry. */

   if (*rd_p_u_fld(&pag_box,&pag_fld,EXT_COL,sizeof(pp->ext)-1,pp->ext)) {

      pp->used = 1;            /* ext isn't blank, entry in use */

      /* read command prototype field */

      rd_p_u_fld(&pag_box,&pag_fld,CMD_COL,sizeof(pp->cmd)-1,pp->cmd);

      rdyesno(&pag_box,&pag_fld,&pp->pause,PAUSE_COL); /* pause after running */
      rdyesno(&pag_box,&pag_fld,&pp->reload,READ_COL); /* reread dir after    */

   } else {            /* blank ext field, no entry */

      *pp->ext = *pp->cmd = '\0';
      pp->used = pp->pause = pp->reload = 0;
   }

   changed = TRUE;             /* assume something changed */
}

#undef NUM_COL
#undef EXT_COL
#undef CMD_COL
#undef PAUSE_COL
#undef READ_COL


/*****************************************************************************
                              D E F _ U D K
 *****************************************************************************/

static int
def_udk() {    /* define the User Defined Keys */

   pag_or_udk(&udk_box,disudkent,rdudkent,NUM_UDK,
              " NUM  KEY  COMMAND PROTOTYPE                       PAUSE READ ");
}

/**************************************************************************
                           D I S U D K E N T
 **************************************************************************/

#define NUM_COL (1)            /* offsets within the UDK dialog box */
#define KEY_COL (5)
#define CMD_COL (11)
#define PAUSE_COL (53)
#define READ_COL (59)

static void
disudkent(ent) /* display UDK entry number ent */
int ent;
{
   int row = ent + 2;
   register UDK_ENT *up = &udk_tbl[ent];

   dbx_goto(&udk_box,row,NUM_COL);
   out_int(ent+1,2,' ');
   dbx_disp(&udk_box,"A-F",row,KEY_COL);
   out_int(ent+1,1+(ent >= 9),' ');
   dbx_goto(&udk_box,row,CMD_COL);
   out_str(up->used ? up->cmd : "",sizeof(up->cmd)-1,' ');
   dbx_disp(&udk_box,up->used ? (up->pause ? "Y" : "N") : " ",row,PAUSE_COL);
   dbx_disp(&udk_box,up->used ? (up->reload ? "Y" : "N") : " ",row,READ_COL);
}


/*****************************************************************************
                              R D U D K E N T
 ****************************************************************************/

static void
rdudkent(ent)  /* read a UDK entry from the user */
int ent;
{
   int row = ent + 2;
   register UDK_ENT *up = &udk_tbl[ent];

   udk_fld.pos = 0;
   udk_fld.row = row;

   /* read the CMD field for this entry, if nothing is read, blank (delete)
      this entry. */

   if (*rd_p_u_fld(&udk_box,&udk_fld,CMD_COL,sizeof(up->cmd)-1,up->cmd)) {

      up->used = 1;            /* cmd isn't blank, entry in use */

      rdyesno(&udk_box,&udk_fld,&up->pause,PAUSE_COL); /* pause after running */
      rdyesno(&udk_box,&udk_fld,&up->reload,READ_COL); /* read dir            */

   } else {            /* blank cmd field, no entry */

      *up->cmd = '\0';
      up->used = up->pause = up->reload = 0;
   }

   changed = TRUE;             /* assume something changed */
}

#undef NUM_COL
#undef KEY_COL
#undef CMD_COL
#undef PAUSE_COL
#undef READ_COL


/***************************************************************************
                          R D _ P _ U _ F L D
 ***************************************************************************/

static char * ALTCALL
rd_p_u_fld(dbp,dfp,col,len,value)      /* read 1 pag or udk field from user */
D_BOX *dbp;
register D_FLD *dfp;
int col, len;
char *value;
{
   char *tmp;

   dfp->col = col;
   dfp->len = len;
   dfp->value = value;
   if (*(tmp = dbx_rdfld(dbp,dfp)))
      strcpy(dfp->value,tmp);
   return(tmp);
}


/****************************************************************************
                               R D Y E S N O
 ****************************************************************************/

static void ALTCALL
rdyesno(dbp,dfp,ynp,col)       /* read a yes/no value into a 0/1 integer */
D_BOX *dbp;
D_FLD *dfp;
unsigned char *ynp;
int col;
{
   char yesno[2];

   *yesno = *ynp ? 'Y' : 'N';          /* convert 0/NZ to Y/N */
   yesno[1] = '\0';

   rd_p_u_fld(dbp,dfp,col,1,yesno);    /* read from user      */
   *ynp = yes(*yesno);                 /* convert Y/N to 0/1  */
}


/*****************************************************************************
                       D E F _ S N O W / N O S N O W
 *****************************************************************************/

static int
def_snow() {   /* enable video snow checking */

   vid_snow = 1;
   changed = TRUE;
}

static int
def_nosnow() { /* disable snow checking */

   vid_snow = 0;
   changed = TRUE;
}


/*****************************************************************************
                            D E F _ R E A D
 *****************************************************************************/

def_read() {   /* read parameters from configuration file */

   FILE *cfg;
   unsigned char filever = 0;

   /* try to open the CFG (configuration) file somewhere in the current
      PATH - if we don't find an existing file assume there isn't one and
      use the default values */

   if ((cfg = pathopen(ovcfg,"rb")) == NULL)   /* try to open config file */
      return;                                  /* must not be one, exit   */

   /* make sure we know how to read this form of config file */

   fread(&filever,1,1,cfg);
   if (filever != CFG_VERSION) {
      show_error(0,0,1,"Obsolete configuration file, defaults used");
      return;
   }

   /* looks okay, read parameters */

   fread(&vid_snow,1,1,cfg);                     /* read video snow flag   */
   fread(monattr,sizeof(monattr),1,cfg);         /* then mono video attr's */
   fread(cgaattr,sizeof(cgaattr),1,cfg);         /* then cga  video attr's */
   fread((char *)pag_tbl,sizeof(pag_tbl),1,cfg); /* then Point-and-Go tbl  */
   fread((char *)udk_tbl,sizeof(udk_tbl),1,cfg); /* then User-Defined-Keys */

   fclose(cfg);                                  /* done reading, close */

   /* attributes have been read, copy them to the in-use attributes */

   strncpy(attribs,vid_mode == 7 ? monattr : cgaattr,sizeof(newattr));
}


/*****************************************************************************
                            D E F _ W R I T E
 *****************************************************************************/

static int
def_write() {  /* write the updated parameters to disk */

   char *sp;
   FILE *cfg;
   register int ch;
   static char *nowrit = " - parameters not written";

   /* try to open the CFG (configuration) file somewhere in the current
      PATH - if we don't find an existing file, ask the user where he
      wants it created */

   if ((cfg = pathopen(ovcfg,"r+b")) == NULL) {
      char cfgmsg[80];

      strcpy(cfgmsg,"Can't find ");
      strcat(cfgmsg,ovcfg);
      strcat(cfgmsg,", enter target directory (ENTER = current, ESC to quit):");

      sp = prompt(NULL,cfgmsg,cw.dirbuf,strlen(cw.dirbuf),MAX_PATHLEN);

      if (strlen(sp)) {
         char cfgbuf[MAX_PATHLEN+MAX_NAMELEN+3];

         strcpy(cfgbuf,sp);                            /* build full pathname */
         if ((ch = cfgbuf[strlen(cfgbuf)-1]) != '\\' && ch != '/' && ch != ':')
            strcat(cfgbuf,"\\");
         strcat(cfgbuf,ovcfg);

         if ((cfg = fopen(cfgbuf,"w+b")) == NULL) {    /* try to open 4 WRITE */
            show_error(0,0,3,cantopen,ovcfg,nowrit);   /* give up if can't opn*/
            return;
         }

      } else                   /* user must have ESCaped out, just exit */
         return;

   } else                      /* pathopen() found it! */

      fseek(cfg,0L,SEEK_CUR);  /* was opened 4 READ, seek so we can write */

   /*** CFG file is now open, write the parameters ***/

   /* now that parms are being written, make video attrib's "permanent" */

   strncpy(vid_mode == 7 ? monattr : cgaattr,attribs,sizeof(newattr));

   fwrite(&cfgver,1,1,cfg);                /* start with config file version */
   fwrite(&vid_snow,1,1,cfg);                      /* then video snow flag   */
   fwrite(monattr,sizeof(monattr),1,cfg);          /* then mono video attr's */
   fwrite(cgaattr,sizeof(cgaattr),1,cfg);          /* then cga  video attr's */
   fwrite((char *)pag_tbl,sizeof(pag_tbl),1,cfg);  /* then Point-and-Go tbl  */
   fwrite((char *)udk_tbl,sizeof(udk_tbl),1,cfg);  /* then User-Defined-Keys */

   fclose(cfg);                                /* done, close */
}


/*****************************************************************************
                            D E F _ M O V E
 *****************************************************************************/

def_move(dir)          /* move the attribute pointer in given direction */
int dir;
{
   register unsigned int fbg, attr = newattr[text_type];

   select_a(0,attr);                   /* always deselect video attribute */

   if (dir == PGUP || dir ==PGDN)      /* maybe deselect text type */
      select_t(0,text_type);

   switch (dir) {

      case UP:                                 /* up arrow of course */

         if (fbg = attr & 15)
            attr = (attr & 0x70) | (fbg - 1);
         else
            attr = (attr & 0x70) | 15;         /* wraps to bottom */
         break;

      case DOWN:                               /* down arrow */

         if ((fbg = attr & 15) < 15)
            attr = (attr & 0x70) | (fbg + 1);
         else
            attr = attr & 0x70;                /* wraps to top */
         break;

      case LEFT:                               /* left arrow */

         if (fbg = (attr >> 4) & 7)
            attr = ((fbg - 1) << 4) | (attr & 15);
         else
            attr = 0x70 | (attr & 15);         /* wraps to right */
         break;

      case RIGHT:                              /* right arrow */

         if ((fbg = (attr >> 4) & 7) < 7)
            attr = ((fbg + 1) << 4) | (attr & 15);
         else
            attr = attr & 15;                  /* wraps to left */
         break;

      case PGUP:                               /* page up - new text type */

         if (text_type)
            --text_type;
         else
            text_type = 6;
         break;

      case PGDN:                               /* page dn - new text type */

         if (text_type < 6)
            ++text_type;
         else
            text_type = 0;
         break;
   }

   if (dir == PGUP || dir ==PGDN)              /* maybe select new text type */
      attr = newattr[text_type];               /* set attribute for new type */

   select_a(1,attr);                   /* show new attribute */
   newattr[text_type] = attr;          /* remember what it is */

   select_t(1,text_type);              /* display name in new attr */

   setvattrib(DIS_NORM);               /* stick with norm for now */
}


/*****************************************************************************
                            S E L E C T _ A
 *****************************************************************************/

static int
select_a(on_off,attr)  /* highlight the current attribute */
register int on_off, attr;
{
   vid_attrib = attr;                  /* gotta use this attribute */

   dbx_disp(&video_box,on_off ? "\x10TEXT\x11" : " TEXT ",  /* (de)select */
            (attr & 15),((attr >> 4) * 6));
}


/*****************************************************************************
                            S E L E C T _ T
 *****************************************************************************/

static int
select_t(on_off,type)  /* highlight the current text type */
register int on_off, type;
{
   vid_attrib = newattr[type];         /* gotta use this attribute */

   /* display pointer, name, pointer */

   dbx_goto(&text_box,type,0);
   disp_char(on_off ? 0x10 : ' ');
   disp_str(def_text[type]);
   disp_char(on_off ? 0x11 : ' ');
}
