/*
 *  CopyRight 1995. Nicholas Poljakov all rights reserved.
 */
#include <dos.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <conio.h>

#define BORDER 1
#define REV_VID 0x70
#define NORM_VID 0x1E
#define MAX_FRAME 31
#define BKSP 8
#define F1 59
#define F2 60
#define F3 61
#define F4 62
#define F5 63
#define F6 64
#define F7 65
#define F8 66
#define F9 67
#define F10 68
#define HM  71   /* Home key     */
#define UP  72   /* Up Arrow     */
#define PU  73   /* Page Up      */
#define LT  75   /* Left Arrow   */
#define RT  77   /* Right Arrow  */
#define END 79   /* End key      */
#define DN  80   /* Down Arrow   */
#define PD  81   /* Page Down    */
#define ESC '\033'
#define DIR 0x10

#define ROWS1 19
#define ROWS2 23
#define ROWS  25
#define COLS 78
#define L_W 20
#define M_W 36
#define R_W 20
#define SCRNSIZE ((ROWS)*(COLS+2)*2)
#define LAST (24 * 80)*2

#define M0C  4     /* Files maping col.s */
#define M0L  14    /* Files maping rows  */
#define M0F (((80 * 5) + 9)) * 2
#define INTR 18*2

extern unsigned int attr1b;
extern unsigned int *ptrs;
extern int size;
extern unsigned char row, col;
extern int adapter;
extern unsigned char far *videomem;
extern int offset;
extern int sw;
extern char *path;
extern char file[12];
extern char tpname[31];
extern char luname[8];
extern char mode_name[8];
extern char rcv_file[12];
extern char dta[128];

extern char far *vid_mem;
extern char far *sv;
extern short cur_ln;

extern struct menu_frame {
    int startx, endx, starty, endy;
    unsigned char *p;
    char **menu;
    char *keys;
    int border;
    int count;
    unsigned char attrib;
    int active;
    int curx, cury;
    char *header;
    unsigned char shd;
    } frame[MAX_FRAME];

extern char p_dcl[21];
extern unsigned char dr_ind[80];
extern char c_pt[60];
extern int drive_ind[10];

int pulldown(num)
int num;
{
    int choice;

    if (frame[num].active == 0) {
        save_video(num);
        frame[num].active = 1;
        if (frame[num].border) {
            draw_border(num);
        }
    }
    display_menu(num);
    sfs(sv,vid_mem);
    return get_resp(num);
}

make_menu(num, menu, keys, count, x, y, border, attrib, shi)
int  num;
char **menu;
char *keys;
int count;
int x, y;
int border;
unsigned char attrib;
unsigned char shi;
{
    register int i, len;
    int  dl;
    int endx, endy, choice, vmode;
    unsigned char *p;

    if (num > MAX_FRAME) {
        printf("Too many menus");
        exit(0);
    }

    if (shi) {
       dl = 1;
    }
    else
       dl = 0;
    len = 0;
    for (i = 0; i < count; i++) {
        if (strlen(menu[i]) > len) {
            len = strlen(menu[i]);
        }
    }
    endy = len + 2 + y;
    endx = count + 1 + x;

    if ((p = malloc(((endx-x+2+dl)*(endy-y+2+dl)) * 2)) == NULL) {
	 printf("Allocation corrupted...\n");
	 exit (0);
    }

    frame[num].startx = x;
    frame[num].endx = endx;
    frame[num].starty = y;
    frame[num].endy = endy;
    frame[num].p = p;
    frame[num].menu = (char **)menu;
    frame[num].border = border;
    frame[num].keys = keys;
    frame[num].count = count;
    frame[num].attrib = attrib;
    frame[num].active = 0;
    frame[num].shd = shi;

    return 1;
}

int display_menu(int num)
{
    char **m;
    register int i, x;

    x = frame[num].startx + 1;
    m = frame[num].menu;
    for (i = 0; i < frame[num].count; i++, x++) {
        if (m[i] != NULL) {
            write_string(x, frame[num].starty + 1, m[i], frame[num].attrib);
        }
    }
}

 draw_border(num)
int num;
{
    register int i;
    char far *v, far *t;

    v = vid_mem;
    t = v;
    for (i = frame[num].startx+1; i < frame[num].endx; i++) {
        v += (i*160) + frame[num].starty * 2;
        *v++ = 179;
	v = t;
	v += (i*160) + frame[num].endy * 2;
	*v++ = 179;
	v = t;
    }
    for (i = frame[num].starty+1; i < frame[num].endy; i++) {
        v += (frame[num].startx * 160) + i * 2;
        *v++ = 196;
	v = t;
	v += (frame[num].endx * 160) + i * 2;
	*v++ = 196;
	v = t;
    }
    write_char(frame[num].startx,frame[num].starty, 218, frame[num].attrib);
    write_char(frame[num].startx,frame[num].endy, 191, frame[num].attrib);
    write_char(frame[num].endx,frame[num].starty, 192, frame[num].attrib);
    write_char(frame[num].endx,frame[num].endy, 217, frame[num].attrib);
}

get_resp(num)
int num;
{
    union inkey{
        char ch[2];
        int i;
        } c;
    int arrow_choice, key_choice;
    int x, y;

    arrow_choice = 0;
    x = frame[num].startx + 1;
    y = frame[num].starty + 1;

    goto_xy(x, y);
    write_string(x, y, frame[num].menu[0], REV_VID);

    for (;;) {
    c.ch[0] = getch();
    if (c.ch[0] == 0) {
        c.ch[1] = getch();
    }

    goto_xy(arrow_choice, y);
    write_string(x + arrow_choice, y, frame[num].menu[arrow_choice], frame[num].attrib);
    if (c.ch[0]) {
        key_choice = is_in(frame[num].keys, tolower(c.ch[0]));
        if (key_choice) {
            return  key_choice - 1;
        }
        switch (c.ch[0]) {
            case '\r' : return arrow_choice;
            case ' '  : arrow_choice++;
                        break;
	    case ESC: return -1;
         }
    }
    else
            {
		switch (c.ch[1]) {
                    case 72 : arrow_choice--;
                              break;
                    case 80 : arrow_choice++;
                              break;
                    case LT : return -2;
                    case RT : return -3;
                 }

            }
    if (arrow_choice == frame[num].count) {
        arrow_choice = 0;
    }
    if (arrow_choice < 0) {
        arrow_choice = frame[num].count - 1;
    }
    goto_xy(x + arrow_choice, y);
    write_string(x + arrow_choice, y, frame[num].menu[arrow_choice], REV_VID);
    }
}

write_string(x, y, p, attrib)
int x, y;
char *p;
unsigned char attrib;
{
    register int i, j;
    char far *v;
    char _near *t1;
    char _near *t2;
    char _near *t3;
    char _near *t4;

    v = vid_mem;
    v += (x*160) + y*2;
    t1 = FP_OFF( v );
    t2 = FP_SEG( v );
    t3 = FP_OFF( p );
    t4 = FP_SEG( p );
    _asm
         {
            mov  ax, word ptr t4[0]
            mov  es, ax
            mov  di, word ptr t3[0]
            cld
            mov  al, 0
            mov  cx, 100
      repne scasb       /* seek End of String */
            jz   Found
            mov  cx, 80 /* default length of string */
            jmp short Move
     Found:
            mov  ax, 100
            xchg ax, cx
	    sub  cx, ax /* length of string */
	    dec  cx
	    and  cx, cx
	    jz	 WrtExit
     Move:
            push ds
            push di
            push si
            mov  ax, word ptr t4[0]
            mov  ds, ax
            mov  si, word ptr t3[0]
            mov  ax, word ptr t2[0]
            mov  es, ax
            mov  di, word ptr t1[0]
            mov  ah, byte ptr attrib[0]
     MvCycl:
            lodsb
            stosw
            loop MvCycl;
            pop  si
            pop  di
	    pop  ds
     WrtExit:
         }
  /*
    for (i = y; *p; i++) {
        *v++ = *p++;
	*v++ = attrib;
    }
   */
}
write_n(x, y, p, attrib, n)
int x, y;
char *p;
unsigned char attrib;
unsigned int n;
{
    register int i, j;
    char far *v;
    char _near *t1;
    char _near *t2;
    char _near *t3;
    char _near *t4;

    v = vid_mem;
    v += (x*160) + y*2;
    t1 = FP_OFF( v );
    t2 = FP_SEG( v );
    t3 = FP_OFF( p );
    t4 = FP_SEG( p );
    _asm
         {
            mov  cx, word ptr n[0]
     Move:
            push ds
            push di
            push si
            mov  ax, word ptr t4[0]
            mov  ds, ax
            mov  si, word ptr t3[0]
            mov  ax, word ptr t2[0]
            mov  es, ax
            mov  di, word ptr t1[0]
            mov  ah, byte ptr attrib[0]
     MvCycl:
            lodsb
            stosw
            loop MvCycl;
            pop  si
            pop  di
            pop  ds
         }
}

write_char(x, y, ch, attrib)
int x, y;
char ch;
int attrib;
{
    register int i, j;
    char far *v;

    v = vid_mem;
    v += (x*160) + y*2;
    *v++ = ch;
    *v = attrib;
}

save_video(num)
int num;
{
    register int i, j;
    int  dl;
    char far *v, far *t;
    char far *v1;
    char far *t1;
    char *buf_ptr;

    if (frame[num].shd) {
       dl = 1; /* for shandow */
    }
    else
       dl = 0;
    buf_ptr = frame[num].p;
    v = sv; /* save buffer */
    v++;
    v1 = vid_mem;
    for (i = frame[num].starty; i < frame[num].endy + 1 + dl; i++) {
        for (j = frame[num].startx; j < frame[num].endx + 1+ dl; j++) {
            t = (v + (j*160) + i*2);
            t1 = (v1 + (j*160) + i*2);
            *buf_ptr++ = *t1++;
            *buf_ptr++ = *t1;
	    if ((i == frame[num].endy+1)||(j == frame[num].endx+1)) {
		if ((i == (frame[num].starty))||(j == frame[num].startx)) {
		}
		else
                   *t = 0x07;
            }
	    else
		{
                   *(t - 1) = ' ';
                   *t = frame[num].attrib;
		}
        }
    }
    sfs(vid_mem, sv);
}

int restore_video(int num)
{
    register int i, j;
    int  dl;
    char far *v, far *t;
    char *buf_ptr;

    if (!frame[num].active) {
        return 0;
    }
    if (frame[num].shd) {
       dl = 1; /* for shandow */
    }
    else
       dl = 0;
    buf_ptr = frame[num].p;
    v = sv;
    t = v;
    for (i = frame[num].starty; i < frame[num].endy + 1 + dl; i++) {
        for (j = frame[num].startx; j < frame[num].endx + 1 + dl; j++) {
            v = t;
            v += (j*160) + i*2;
            *v++ = *buf_ptr++;
            *v = *buf_ptr++;
         }
    }
    frame[num].active = 0;
    sfs(vid_mem, sv);
}

 cls(int ind)
{
    union REGS r;
    char far *t;
    register int i;

    r.h.ah = 6;
    r.h.al = 0;
    r.h.ch = 0;
    r.h.cl = 0;
    r.h.dh = 24;
    r.h.dl = 79;
    r.h.bh = 7;
    int86(0x10, &r, &r);
    if (ind == 1) {
       t = vid_mem;
       t++;
       for (i = 0; i < 2000; i++) {
           *t =  0x31;
           t++;
           *t = 176;
           t ++;
       }
    }
}

 goto_xy(x, y)
int x, y;
{
    union REGS r;

    r.h.ah = 2;
    r.h.dl = y;
    r.h.dh = x;
    r.h.bh = 0;
    int86(0x10, &r, &r);
}

video_mode()
{
    union REGS r;

    r.h.ah = 15;
    return int86(0x10, &r, &r) & 255;
}

is_in(s, c)
char *s, c;
{
    register int i;

    for (i = 0; *s; i++) {
        if (*s++ == c) {
            return i + 1;
        }
    }
    return 0;
}
