/*
  
Title:	MsgEd
  
File:	Screen.c
  
Author:	Jim Nutt
	
Copr:	1987 by Jim Nutt
  
Description:
	
	Screen handling functions for MsgEd.  also a few string handlers.
  
	if you need to port this... remember, msged uses a 1 based coordinate
	system (i.e. top left is (1,1) NOT (0,0)).  anything that is dependent
	on zortech c, quick c or turbo c will complain when you try to compile
	this thing under any other compiler...

*/

#if (defined(__LARGE__) || defined(M_I86LM)) && !defined(__ZTC__)
#define USEFOSSIL 1
#else
#define USEFOSSIL 0
#endif

#ifdef __TURBOC__
#pragma warn -pro
#endif

#include <dos.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#ifndef MK_FP
#include "mkfp.h"
#endif
#include "screen.h"

#if USEFOSSIL
#include "vfossil.h"

static void vfossil_init ();
static void vfossil_open ();
static void vfossil_close ();

static int (pascal *vfossil_funcs[20]) () = {
   NULL, NULL, NULL,
   NULL, NULL, NULL,
   NULL, NULL, NULL,
   NULL, NULL, NULL,
   NULL, NULL, NULL,
   NULL, NULL, NULL,
   NULL, NULL
};
#endif

#define FALSE 0
#define TRUE !FALSE
#define TEXTLEN 128

int int86(int intnum,union REGS *i, union REGS *o);
int int86x(int intnum,union REGS *i, union REGS *o,struct SREGS *s);

int normfore = 7, normback = 0;
int statfore = 0, statback = 0;
int maxx;		/* maximum screen columns */
int maxy;		/* maximum screen rows */
int videomethod;        /* how to write to the screen */
unsigned int vbase;     /* where screen memory is located */

static char s[TEXTLEN];

static unsigned int far *screen = NULL;
static unsigned int cx = 1;
static unsigned int cy = 1;
static int desqview = 0;

#if USEFOSSIL

static struct FOSSIL_DATA {
        int     length;
        char    mode;
        char    maxcolors;
        int     maxx;
        int     maxy;
        int     fill1;
        int     fill2;
        long    fill3;
} fossil_data;

static unsigned char scroll_fill [2];
#endif

static union {
	struct {
		unsigned int foreground:3;
		unsigned int intensity:1;
		unsigned int background:3;
		unsigned int blink:1;
	}       colorbits;
	unsigned char attribute;
}       current_color;

void    video_init()
{
        union REGS r;
        struct SREGS sr;
        int vmode = 0;

        if (videomethod == FOSSIL) {
#if !USEFOSSIL
                fputs("fossil video only supported by the big version\n",stderr);
                exit(255);
#else
                vfossil_init ();                /* Start Video FOSSIL */
                fossil_data.length = 2 * sizeof (fossil_data);
                VioGetMode (&fossil_data,0);    /* Get mode info      */
                maxx = fossil_data.maxx;        /* Maximum 'X' value  */
                maxy = fossil_data.maxy;        /* Maximum 'Y' value  */
#endif
        }
        else {
                r.h.ah = 0x0f;
                int86(0x10,&r,&r);
                vmode = r.h.al;
                if (maxx == 0)
                        maxx = (int) r.h.ah;

                if (maxy == 0) {
                        r.x.ax = 0x1130;
                        r.x.dx = maxy;
                        int86(0x10,&r,&r);
                        maxy = (r.x.dx == 0) ? 25 : (r.x.dx + 1);
                }

                if (videomethod == DIRECT) {
                        if (vbase == 0)
                                if (vmode == 0x07)
                                        vbase = 0xb000;
                                else
                                        vbase = 0xb800;

                        r.h.ah = 0xfe;
                        sr.es = vbase;
                        r.x.di = 0;
                        int86x(0x10,&r,&r,&sr);
                        desqview = (vbase != sr.es);
                        vbase = sr.es;

                        screen = (unsigned int far *) MK_FP(vbase,r.x.di);
                }
        }
}

void    video_end()
{
        if (videomethod == FOSSIL) {
#if USEFOSSIL
                vfossil_close ();
#endif
        }
}

void    video_update()
{
        if (videomethod == FOSSIL) {
#if USEFOSSIL
                VioSetCurPos (cy - 1, cx - 1, 0);
#endif

        }
	else {
                union REGS r;

        	r.h.ah = 2;
        	r.h.bh = 0;
                r.h.dh = (char) cy - 1;
                r.h.dl = (char) cx - 1;
                int86(0x10, &r, &r);
        }
}

void    scrollup(x1, y1, x2, y2, lines)
	int     x1, y1, x2, y2, lines;

{
        y2 = min(y2,maxy) - 1;
        y1 = min(y1,maxy) - 1;
        x1 = min(x1,maxx) - 1;
        x2 = min(x2,maxx) - 1;

        if (videomethod == FOSSIL) {
#if USEFOSSIL
                scroll_fill [0] = ' ';
                scroll_fill [1] = current_color.attribute;
                if (lines == 0)
                        lines = -1;

                VioScrollUp (y1,x1,y2,x2,lines,scroll_fill,0);
#endif
        }
        else {
                union REGS      r;

        	r.h.ah = 6;
        	r.h.al = (char) lines;
                r.h.ch = (char) y1;
                r.h.cl = (char) x1;
                r.h.dh = (char) y2;
                r.h.dl = (char) x2;
        	r.h.bh = current_color.attribute;
                int86(0x10, &r, &r);
        }
}

void    scrolldown(x1, y1, x2, y2, lines)
	int     x1, y1, x2, y2, lines;

{
        y2 = min(y2,maxy) - 1;
        y1 = min(y1,maxy) - 1;
        x1 = min(x1,maxx) - 1;
        x2 = min(x2,maxx) - 1;

        if (videomethod == FOSSIL) {
#if USEFOSSIL
                scroll_fill [0] = ' ';
                scroll_fill [1] = current_color.attribute;

                VioScrollDn (y1,x1,y2,x2,lines,scroll_fill,0);
#endif
        }
        else {
        	union REGS      r;

        	r.h.ah = 7;
        	r.h.al = (char) lines;
                r.h.ch = (char) y1;
                r.h.cl = (char) x1;
                r.h.dh = (char) y2;
                r.h.dl = (char) x2;
                r.h.bh = current_color.attribute;
                int86(0x10, &r, &r);
        }
}

void    bputc(unsigned char c)
{
        union REGS r;
        unsigned int d = 0;

        d = (c & 0xff) | (current_color.attribute << 8);

        if (videomethod == DIRECT) {
                *(screen + ((((cy - 1) * maxx) + (cx - 1)))) = d;
        }
#if USEFOSSIL
        else if (videomethod == FOSSIL) {
                unsigned int far *cell_ptr = &d;
                VioWrtCellStr (cell_ptr, 2, cy - 1, cx - 1, 0);
        }
#endif
        else {                
                video_update();
                r.h.ah = 0x9;
                r.h.bh = 0;
                r.h.al = c;
                r.h.bl = current_color.attribute;
                r.x.cx = 1;
                int86(0x10,&r,&r);
        }


        if (++cx > maxx) {
                cx = 1;
                if (++cy > maxy)
                        cy = 1;
        }
}

void    gotoxy(int x, int y)
{
        cx = min(x,maxx);
        cy = min(y,maxy);
}

int     wherex()
{
        return (cx);
}

int     wherey()
{
        return(cy);
}

int     getkey()
{
        union REGS r;

#if USEFOSSIL
        if (videomethod == FOSSIL) {
                r.h.ah = 0x0e;
                int86 (0x14,&r,&r);
        }
        else
#endif
                {
                r.h.ah = 0;
                int86(0x16,&r,&r);
        }
        if (r.h.al)                     /* Must use FOSSIL keymap,   */
                r.h.ah = 0;             /* No scan code if have char */
        return(r.x.ax);
}

void    bputs(char *s)
{
	if (s == NULL)
                return;

        if (videomethod != FOSSIL) {
		while ((*s) && (wherex() <= maxx))
                        if (*s != '\n') {
                                bputc(*s);
                                s++;
                        }
                        else
                                break;
        }
#if USEFOSSIL
        else {
                char *e;
                int  l;
                int a = current_color.attribute;

                if ((e = strchr(s,'\n')) == NULL)
                        e = strchr(s,'\0');
                if ((l = e - s) < 1)
                        return;
                VioWrtCharStrAtt(s,l,cy - 1,cx - 1,&a,0);
                cx += l;
        }
#endif
}

void    cls()
{
        scrollup(1, 1, maxx, maxy, 0);
        gotoxy(1, 1);
}

void    clrwnd(x1, y1, x2, y2)
	int     x1, y1, x2, y2;

{
        scrollup(x1, y1, x2, y2, 0);
        gotoxy(x1,y1);
}

void    clreol()
{
        clrwnd(cx,cy,maxx,cy);
}

int     bgets(char *s1, int c)
{
	int     ch;
	int     x1;
	char   *t;
	static  insert = OFF;
	int	y = wherey();
	int     x = wherex();

	memset(s, 0, sizeof s);
	strcpy(s, s1);
	t = s + strlen(s);
	*t = '\0';
	bputs(s);

	while (TRUE) {		/* endless loop */
		video_update();
		switch (ch = getkey()) {

		case UP:
		case DOWN:
		case PGUP:
		case PGDN:
		case ENTER:
			strcpy(s1, s);
			return (ch);

		case WORDRT:
			break;

		case WORDLT:
			break;

		case ABORT:
			memset(s, 0, sizeof s);
			t = s;
			gotoxy(x, y);
			clreol();
			break;

		case GOBOL:
			t = s;
			gotoxy(x, y);
			break;

		case GOEOL:
			t = s + strlen(s);
			gotoxy(x + strlen(s), y);
			break;

                case RUBOUT:
		case BKSPC:
			if (x == wherex())
				break;
			t--;
			memmove(t, (t + 1), strlen(t) + 1);
			gotoxy(wherex() - 1, y);
			x1 = wherex();
			bputs(t);
			bputc(' ');
			gotoxy(x1, y);
			break;

		case LEFT:
			if (t == s)
				break;
			t--;
			gotoxy(wherex() - 1, y);
			break;

		case RIGHT:
			if (t >= (s + strlen(s)))
				break;
			t++;
			gotoxy(wherex() + 1, y);
			break;

		case DELCHR:
			memmove(t, t + 1, strlen(t) + 1);
			x1 = wherex();
			bputs(t);
			bputc(' ');
			gotoxy(x1, y);
			break;

		case INSERT:
			insert = !insert;
			break;

		default:
                        if (strlen(s) == c)
				break;
			if (insert) {
				x1 = wherex();
				t++;
				strins(s, (char) (ch & 0xff), (x1 - x + 1));
				gotoxy(x, y);
				bputs(s);
				gotoxy(x1 + 1, y);
			}
			else {
				*t++ = (char) (ch & 0xFF);
				bputc((char) (ch & 0xff));
			}
			video_update();
			break;
		}
	}
}

int     getnum(int l, int h, int value)
{
	int     i, x;
        char    s[TEXTLEN];

	i = value;
	x = wherex();
	do {
		clreol();
                memset(s, 0, sizeof(s));
		itoa(i, s, 10);
		gotoxy(x, wherey());
                bgets(s, TEXTLEN/2);
		i = atoi(s);
	} while ((i < l) || (i > h));
	return (i);
}

void    intense(int flag)
{
        static unsigned int oldfore = 0;
        static unsigned int oldback = 0;

        if (flag) {
                oldfore = current_color.colorbits.foreground;
                oldback = current_color.colorbits.background;
        }

        if (!flag & !oldfore)
                oldfore = normfore;

        if (!flag & !oldback)
                oldback = normback;

        if ((statfore == 0) || (statback == 0)) {
                current_color.colorbits.intensity = flag & 1;
	}
	else if (flag) {
		foreground(statfore);
		background(statback);
	}
	else {
                foreground(oldfore);
                background(oldback);
	}
}

void    blink(int flag)
{
		current_color.colorbits.blink = flag & 1;
}

void    foreground(int color)
{
	current_color.colorbits.foreground = color & 7;
	if (color > 7)
		current_color.colorbits.intensity = 1;
	else
		current_color.colorbits.intensity = 0;
}

void    background(int color)
{
		current_color.colorbits.background = color & 7;
}

int     bprintf(char *f,...)
{
	va_list params;
	int     i;

	va_start(params, f);
	i = vsprintf(s, f, params);
	bputs(s);
	return (i);
}

void    strins(char *l, char c, int x)
{
	int     i = strlen(l);

	x--;

	memmove((l + x + 1), (l + x), (i - x));
	*(l + x) = c;
}

void    strdel(char *l, int x)
{
	int     i = strlen(l);

	x--;

	memmove((l + x), (l + x + 1), (i - x + 1));
	*(l + i) = 0;
}

#if USEFOSSIL

VFOSSIL v;

static void vfossil_init ()
{
   char far *q;
   union REGS r;
   struct SREGS s;

   v.vfossil_size = sizeof (VFOSSIL);
   q = (char far *) &v;

   r.h.ah = 0x81;
   r.h.al = 0;

   segread (&s);
   s.es = FP_SEG (q);
   r.x.di = FP_OFF (q);
   int86x (0x14, &r, &r, &s);

   if (r.x.ax == 0x1954)
      {
      /* There is a VFOSSIL out there, so set it up for use */
      vfossil_open ();
      }
  else
      {
      fputs ("No Video FOSSIL installed, aborting....\n\n",stderr);
      exit (255);
      }
}

CURSOR _cursor;

void vfossil_cursor (st)
int st;
{
   CURSOR far *q;

   if (vfossil_funcs[9])
      {
      q = (CURSOR far *) &_cursor;
      /* We can make the cursor go away */
      VioGetCurType (q, 0);
      _cursor.cur_attr = st ? 0 : -1;
      VioSetCurType (q, 0);
      }
}

static void vfossil_open ()
{
   char far *q;
   union REGS r;
   struct SREGS s;

   segread (&s);
   r.h.ah = 0x81;
   r.h.al = 1;
   r.x.cx = 80;
   q = (char far *) vfossil_funcs;
   r.x.di = FP_OFF (q);
   s.es = FP_SEG (q);
   int86x (0x14, &r, &r, &s);
   if ((r.x.ax != 0x1954) || (r.x.bx < 14))
      {
      fputs ("Unable to initialize Video FOSSIL, aborting....\n\n",stderr);
      exit (255);
      }
}

static void vfossil_close ()
{
   union REGS r;

   vfossil_cursor (1);

   r.h.ah = 0x81;
   r.h.al = 2;

   int86 (0x14, &r, &r);

}
#endif
