/*
** SCO emulation of vga lib
**
** Uses vga.h from Linux svgalib
*/

#include "bmv.h"

#ifdef printf
#undef printf
#endif

#ifndef VGA_H
#include <stdio.h>
#include <stdlib.h>

#include "vga.h"
#endif

#ifndef USE_WIN
#define	USE_WIN	1
#endif

#define	VGA_DEBUG	0

#if USE_WIN
#include "windecs.h"
static win_rec *w;
#endif

#ifndef CONSOLE_BS
#include "consdecs.h"
#endif

#ifndef va_start
#include <stdarg.h>
#endif

#define SCOVGA	G640x480x16

/* Shorthands for internal variables and functions */
#define CI	__svgalib_cur_info
#define GM	__svgalib_graph_mem
#define CM	__svgalib_cur_mode
#define VMEM	__svgalib_videomemoryused
#define DREP	__svgalib_driver_report
#define CRITICAL __svgalib_critical
#define COL	__svgalib_cur_color
#define CHIPSET __svgalib_chipset
#define SCREENON __svgalib_screenon
#define MODEX 	__svgalib_modeX
#define MODEFLAGS __svgalib_modeflags
#define infotable __svgalib_infotable

#define MODENAME_LENGTH 20

/* --------------------- Variable definitions shared by library modules */

struct info CI;			/* current video parameters */
int COL;			/* current color            */
int CM  = TEXT;			/* current video mode       */
int SCREENON;			/* screen visible if != 0 */
unsigned char *GM;		/* graphics memory frame */
int MODEX;			/* TRUE after vga_setmodeX() */
int MODEFLAGS;			/* copy of flags of current modeinfo->flags */

static int __svgalib_videomemoryused = -1;

static int lastmodenumber = __GLASTMODE; /* Last defined mode */
static int currentpage;
static int currentlogicalwidth;
static int currentdisplaystart;
static int mouse_type = -1;
static int oktowrite = 1;

static int initialized = 0;	/* flag: initialize() called ?  */
static int did_console_init = 0; /* flag: console_init() called ? */

/* graphics mode information */
struct info {
    int xdim;
    int ydim;
    int colors;
    int xbytes;
    int bytesperpixel;
};

struct info infotable[] = {
	{   80,   25,    16,  160, 0 },		/* VGAlib VGA modes */
	{  320,  200,    16,   40, 0 },
	{  640,  200,    16,   80, 0 },
	{  640,  350,    16,   80, 0 },
	{  640,  480,    16,   80, 0 },
	{  320,  200,   256,  320, 1 },
	{  320,  240,   256,   80, 0 },
	{  320,  400,   256,   80, 0 },
	{  360,  480,   256,   90, 0 },
	{  640,  480,     2,   80, 0 },

	{  640,  480,   256,  640, 1 },		/* VGAlib SVGA modes */
	{  800,  600,   256,  800, 1 },
	{ 1024,  768,   256, 1024, 1 },
	{ 1280, 1024,   256, 1280, 1 },

	{  320,  200, 1<<15,  640, 2 },		/* Hicolor/truecolor modes */
	{  320,  200, 1<<16,  640, 2 },
	{  320,  200, 1<<24,  320 * 3, 3 },
	{  640,  480, 1<<15,  640 * 2, 2 },
	{  640,  480, 1<<16,  640 * 2, 2 },
	{  640,  480, 1<<24,  640 * 3, 3 },
	{  800,  600, 1<<15,  800 * 2, 2 },
	{  800,  600, 1<<16,  800 * 2, 2 },
	{  800,  600, 1<<24,  800 * 3, 3 },
	{ 1024,  768, 1<<15, 1024 * 2, 2 },
	{ 1024,  768, 1<<16, 1024 * 2, 2 },
	{ 1024,  768, 1<<24, 1024 * 3, 3 },
	{ 1280, 1024, 1<<15, 1280 * 2, 2 },
	{ 1280, 1024, 1<<16, 1280 * 2, 2 },
	{ 1280, 1024, 1<<24, 1280 * 3, 3 },

	{  800,  600,    16,  100, 0 },		/* SVGA 16-color modes */
	{ 1024,  768,    16,  128, 0 },
	{ 1280, 1024,    16,  160, 0 },

	{  720,  348,     2,   90, 0 },		/* Hercules emulation mode */

	{  320,  200, 1<<24,  320 * 4, 4 },
	{  640,  480, 1<<24,  640 * 4, 4 },
	{  800,  600, 1<<24,  800 * 4, 4 },
	{ 1024,  768, 1<<24, 1024 * 4, 4 },
	{ 1280, 1024, 1<<24, 1280 * 4, 4 },

	{    0,    0,     0,    0, 0 },	/* 16 user definable modes */
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 },
	{    0,    0,     0,    0, 0 }
};

#define MAX_MODES (sizeof(infotable) / sizeof(struct info))


/* This one won't type an error message ... */
static int __vga_name2number( char *m)
{
	int i;

	for (i = G320x200x16; i <= GLASTMODE; i++) {
		if (strcmp(m, vga_getmodename(i)) == 0)	/* check name */
			return i;
	}
	return -1;
}

#if !USE_WIN
static void repaint_dummy( void )
{
	;
}
#endif

static void initialize( int mode )
{
	vga_modeinfo *modeinfo;

#if !USE_WIN
	if (!did_console_init) {
		if (console_init(repaint_dummy) != 0) {
			fprintf(stderr, "console_init failed\n");
			exit(0);
		}
		did_console_init = 1;
	}
#endif

	initialized = 1;

	modeinfo = vga_getmodeinfo(mode);
	VMEM = modeinfo->linewidth * modeinfo->height;
}

#if USE_WIN
void repaint_handler(char *context, int repaint)
{
	if (repaint) {
		showwindow(-1, -1, -1);
	}
}
#endif

int vga_setmode(int mode)
{
#if VGA_DEBUG
	fprintf(stderr, "setmode, pid %d, mode %d, did_init %d\n", getpid(), mode,
 did_console_init);
#endif

	if (!initialized)
		initialize(mode);
	
	CM       = mode;

	if (mode == TEXT) {
		/* Returning to textmode. */
#if USE_WIN
		if (did_console_init) {
			win_finish(&w);
			did_console_init = 0;
		}
#else
		console_text_mode(0);
		did_console_init = 0;
#endif

	} else if (mode == SCOVGA) {
		/* Setting a graphics mode. */
#if USE_WIN
		if (!did_console_init) {
			if (win_init(&w,NULL,NULL,CONSOLE) != WIN_STAT_OK) {
				fprintf(stderr, "win_init failed\n");
				exit(0);
			}
			win_open(&w, 1, 1, WIN_STD_LEN, WIN_STD_WID,
				WIN_NORMAL, NULL, 0, WIN_NORMAL, WIN_NORMAL,
				FALSE, WIN_NORMAL);
			win_omit(w, repaint_handler, NULL, 1, 1, 1, 1);
			win_update(w);
			did_console_init = 1;
		}
#else
		console_graphics_mode(0);
		did_console_init = 1;
#endif
	}

	CI.xdim = infotable[mode].xdim;
	CI.ydim = infotable[mode].ydim;
	CI.colors = infotable[mode].colors;
	CI.xbytes = infotable[mode].xbytes;
	CI.bytesperpixel = infotable[mode].bytesperpixel;
	MODEX = 0;

	currentpage = -1;
	currentlogicalwidth = CI.xbytes;
	currentdisplaystart = 0;

	return 0;
}

int vga_hasmode(int mode)
{
	return (mode == TEXT || mode == SCOVGA);
}

int vga_setflipchar(int c)
{
	return 0;
}

int vga_clear()
{
	console_clear();
	return 0;
}

int vga_flip()
{
#if VGA_DEBUG
	fprintf(stderr, "flip\n");
#endif
	return 0;
}

int vga_getxdim()
{
	return CI.xdim;
}

int vga_getydim()
{
	return CI.ydim;
}

int vga_getcolors()
{
	return CI.colors;
}

int vga_setpalette(int index, int red, int green, int blue)
{
#if VGA_DEBUG
	fprintf(stderr, "setpal\n");
#endif
	return 0;
}

int vga_getpalette(int index, int *red, int *green, int *blue)
{
#if VGA_DEBUG
	fprintf(stderr, "getpal\n");
#endif
	return 0;
}

int vga_setpalvec(int start, int num, int *pal)
{
#if VGA_DEBUG
	fprintf(stderr, "setpalv\n");
#endif
	return 0;
}

int vga_getpalvec(int start, int num, int *pal)
{
#if VGA_DEBUG
	fprintf(stderr, "getpalv\n");
#endif
	return 0;
}

int vga_screenoff()
{
#if VGA_DEBUG
	fprintf(stderr, "scroff\n");
#endif
	return 0;
}

int vga_screenon()
{
#if VGA_DEBUG
	fprintf(stderr, "scron\n");
#endif
	return 0;
}

int vga_setcolor(int color)
{
	if (CI.colors == 2 && color != 0) color = 15;
	COL = color;
	return 0;
}

int vga_drawpixel(int x, int y)
{
#if VGA_DEBUG
	fprintf(stderr, "drawpix %d %d\n", x, y);
#endif
	return 0;
}

int vga_drawline(int x1, int y1, int x2, int y2)
{
#if VGA_DEBUG
	fprintf(stderr, "drawline\n");
#endif
	return 0;
}

int vga_drawscanline(int line, unsigned char* colors)
{
	if ((CI.colors == 2) || (CI.colors > 256))
		return vga_drawscansegment(colors, 0, line, CI.xbytes);
	else
		return vga_drawscansegment(colors, 0, line, CI.xdim);
}

int vga_drawscansegment(unsigned char* colors, int x, int y, int length)
{
	int i;
	int start_i;
	unsigned char start_color;

	if (length <= 0) return 0;

	start_i = 0;
	start_color = colors[0];
	for (i = 1; i < length; i++) {
		if (colors[i] != start_color) {
			console_box(y, x+start_i, 1, i-start_i, start_color<<4);
			start_i = i;
			start_color = colors[i];
		}
	}
	console_box(y, x+start_i, 1, i-start_i, start_color<<4);

	return 0;
}

int vga_getch()
{
#if VGA_DEBUG
	fprintf(stderr, "getch\n");
#endif
	return 0;
}

int vga_dumpregs()
{
#if VGA_DEBUG
	fprintf(stderr, "dumpregs\n");
#endif
	return 0;
}

vga_modeinfo *vga_getmodeinfo( int mode )
{
	static vga_modeinfo modeinfo;

	if (mode > vga_lastmodenumber())
		return NULL;

	modeinfo.width = infotable[mode].xdim;
	modeinfo.height = infotable[mode].ydim;
	modeinfo.bytesperpixel = infotable[mode].bytesperpixel;
	modeinfo.colors = infotable[mode].colors;
	modeinfo.linewidth = infotable[mode].xbytes;
	modeinfo.flags = 0;

	return &modeinfo;
}

int vga_getdefaultmode()
{
	char *e;
	int m;

	e = getenv("GSVGAMODE");
	if (e != NULL && strcmp(e, "") != 0) {
		m = vga_getmodenumber(e);
		if (m != -1)
			return m;
	}
	return SCOVGA;
}

int vga_getcurrentmode()
{
#if VGA_DEBUG
	fprintf(stderr, "getcurrentmode, returning %d\n", CM);
#endif
	return CM;
}

int vga_getcurrentchipset()
{
	return VGA;
}

char *vga_getmodename( int m )
{
	static char modename[MODENAME_LENGTH];
	int x, y, c;

	if (m <= TEXT || m > GLASTMODE) {
	  modename[0] = '\0';
	  return modename;
	}
	x = __svgalib_infotable[m].xdim;
	y = __svgalib_infotable[m].ydim;
	switch (c = __svgalib_infotable[m].colors) {
	  case 1<<15: sprintf(modename, "G%dx%dx32K", x, y); break;
	  case 1<<16: sprintf(modename, "G%dx%dx64K", x, y); break;
	  case 1<<24: sprintf(modename, "G%dx%dx16M", x, y); break;
	  default   : sprintf(modename, "G%dx%dx%d", x, y, c); break;
	}
	return modename;
}

int vga_getmodenumber( char *m )
{
	int i;
	char s[3];

	i = __vga_name2number(m);
	if (i>0)
	    return i;

	for (i = G320x200x16; i <= GLASTMODE; i++) {
		sprintf(s, "%d", i);
		if (strcmp(m, s) == 0)			/* check number */
			return i;
	}
	if (strcmp(m, "PROMPT") == 0)
		return -1;
	printf("Invalid graphics mode in environment variable.\n");
	return -1;
}

int vga_lastmodenumber(void)
{
	return lastmodenumber;
}

unsigned char *vga_getgraphmem()
{
#if VGA_DEBUG
	fprintf(stderr, "getgrmem\n");
#endif
	return NULL;
}

void vga_setpage( int p )
{
#if VGA_DEBUG
	fprintf(stderr, "setpage\n");
#endif
}

void vga_setreadpage( int p )
{
#if VGA_DEBUG
	fprintf(stderr, "setreadpage\n");
#endif
}

void vga_setwritepage( int p )
{
#if VGA_DEBUG
	fprintf(stderr, "setwritepage\n");
#endif
}

void vga_setlogicalwidth( int w )
{
#if VGA_DEBUG
	fprintf(stderr, "setlogwid\n");
#endif
}

void vga_setdisplaystart( int a )
{
#if VGA_DEBUG
	fprintf(stderr, "setdispstart\n");
#endif
}

void vga_waitretrace()
{
#if VGA_DEBUG
	fprintf(stderr, "waitretrace\n");
#endif
}

int vga_claimvideomemory( int n )
{
#if VGA_DEBUG
	fprintf(stderr, "claimvidmem\n");
#endif
	return 0;
}

void vga_disabledriverreport()
{
#if VGA_DEBUG
	fprintf(stderr, "disabledriverrep\n");
#endif
}

int vga_setmodeX()
{
#if VGA_DEBUG
	fprintf(stderr, "setmodeX\n");
#endif
	return 0;
}

int vga_init()	/* Used to return void in svgalib <= 1.12. */
{
	vga_hasmode(TEXT);	/* Force driver message and initialization. */
	return 0;
}

int vga_getmousetype()
{
	return mouse_type;
}

int vga_getmonitortype()
{
	return MON1024_43I;
}

void vga_setmousesupport( int s )
{
#if VGA_DEBUG
	fprintf(stderr, "getmousesup\n");
#endif
}

void vga_lockvc()
{
#if VGA_DEBUG
	fprintf(stderr, "lockvc\n");
#endif
}

void vga_unlockvc()
{
#if VGA_DEBUG
	fprintf(stderr, "unlockvc\n");
#endif
}

int vga_getkey()
{
#if VGA_DEBUG
	fprintf(stderr, "getkey\n");
#endif
	return 0;
}

void vga_runinbackground( int s )
{
}

int vga_oktowrite()
{
#if VGA_DEBUG
	fprintf(stderr, "oktowrite\n");
#endif
	return oktowrite;
}

void vga_copytoplanar256( unsigned char *virtualp, int pitch,
	int voffset, int vpitch, int w, int h )
{
#if VGA_DEBUG
	fprintf(stderr, "copytoplanar256\n");
#endif
}

void vga_copytoplanar16( unsigned char *virtualp, int pitch,
	int voffset, int vpitch, int w, int h )
{
#if VGA_DEBUG
	fprintf(stderr, "copytoplanar16\n");
#endif
}

void vga_copytoplane( unsigned char *virtualp, int pitch,
	int voffset, int vpitch, int w, int h, int plane )
{
#if VGA_DEBUG
	fprintf(stderr, "copytoplane\n");
#endif
}

void vga_setlinearaddressing()
{
#if VGA_DEBUG
	fprintf(stderr, "setlinearad\n");
#endif
}

void vga_safety_fork(void (*shutdown_routine)(void))
{
#if VGA_DEBUG
	fprintf(stderr, "safetyfork\n");
#endif
}

void vga_setchipset( int c )
{
#if VGA_DEBUG
	fprintf(stderr, "setchipset\n");
#endif
}

void vga_setchipsetandfeatures( int c, int par1, int par2 )
{
#if VGA_DEBUG
	fprintf(stderr, "setchipsetandfeat\n");
#endif
}

void vga_gettextfont( void *font )
{
#if VGA_DEBUG
	fprintf(stderr, "gettextfont\n");
#endif
}

void vga_puttextfont( void *font )
{
#if VGA_DEBUG
	fprintf(stderr, "puttextfont\n");
#endif
}

void vga_settextmoderegs( void *regs )
{
#if VGA_DEBUG
	fprintf(stderr, "settextmodereg\n");
#endif
}

void vga_gettextmoderegs( void *regs )
{
#if VGA_DEBUG
	fprintf(stderr, "gettextmodereg\n");
#endif
}

int vga_white()
{
	switch (CI.colors) {
	case     2:
	case    16:
	case   256: return 15;
	case 1<<15: return 32767;
	case 1<<16: return 65535;
	case 1<<24: return (1<<24)-1;
	}
	return CI.colors-1;
}

int vga_setegacolor( int c )
{
#if VGA_DEBUG
	fprintf(stderr, "setegacolor\n");
#endif
	return 0;
}

int vga_setrgbcolor( int r, int g, int b )
{
#if VGA_DEBUG
	fprintf(stderr, "setrgbcolor\n");
#endif
	return 0;
}

void vga_bitblt( int srcaddr, int destaddr, int w, int h, int pitch )
{
#if VGA_DEBUG
	fprintf(stderr, "bitblt\n");
#endif
}

void vga_imageblt( void *srcaddr, int destaddr, int w, int h, int pitch )
{
#if VGA_DEBUG
	fprintf(stderr, "imageblt\n");
#endif
}

void vga_fillblt( int destaddr, int w, int h, int pitch, int c )
{
#if VGA_DEBUG
	fprintf(stderr, "fillblt\n");
#endif
}

void vga_hlinelistblt( int ymin, int n, int *xmin, int *xmax, int pitch, int c )
{
#if VGA_DEBUG
	fprintf(stderr, "hlinelistblt\n");
#endif
}

int mouse_pixel_x = -1;
int mouse_pixel_y = -1;

int vgasco_getchar(void)
{
#if USE_WIN
	int code;
	int ch;
	char read_ch;
#if MOUSE
	int old_ctl, old_buttons, new_buttons, msrow, mscol;
	event *ev;
#endif

#if MOUSE
	old_ctl =
	  msctl(MS_CURSOR_ON|MS_BUTTON_ON|MS_TRACK_ON|MS_KEY_ON|MS_STAT, NULL);
#endif

	ch = '\0';
	mouse_pixel_x = mouse_pixel_y = -1;

	while (ch == '\0') {
          code = win_read_key(WIN_REC_NULL, 0, 0, 0, 0, &read_ch);

#if VGA_DEBUG
          printf("code %d ch %c\n", code, ch); fflush(stdout);
#endif

          switch (code) {
	  case MENU_KERR:
	    ch = read_ch;
	    break;

	  case MENU_KUP:
	  case MENU_KPREV_FIELD:
	    ch = 'k';
	    break;

	  case MENU_KDOWN:
	  case MENU_KNEXT_FIELD:
	    ch = 'j';
	    break;

	  case MENU_KLEFT:
	  case MENU_KDEL_BACK:
	  case MENU_KDEL_WORD_BACK:
	    ch = 'h';
	    break;

	  case MENU_KRIGHT:
	  case MENU_KDEL_FORW:
	  case MENU_KDEL_WORD_FORW:
	    ch = 'l';
	    break;

	  case MENU_KPAGE_UP:
	    ch = 'p';
	    break;

	  case MENU_KPAGE_DOWN:
	    ch = 'n';
	    break;

	  case MENU_KENTER:
	    ch = '\n';
	    break;
	  case MENU_KSPACE:
	    ch = ' ';
	    break;
	  case MENU_KTAB:
	    ch = '\t';
	    break;

	  case MENU_KLEAVE:
	  case MENU_KABORT:
	  case MENU_KABORT_SCREEN:
	  case MENU_KWRITE_SCREEN:
	  case MENU_KABORT_MODULE:
	    ch = 'q';
	    break;

	  case MENU_KBEG_LINE:
	  case MENU_KDEL_LINE_BACK:
	  case MENU_KDEL_LINE:
	    ch = 'H';
	    break;

	  case MENU_KEND_LINE:
	  case MENU_KDEL_LINE_FORW:
	    ch = 'L';
	    break;

	  case MENU_KREPAINT:
	  case MENU_KRESTORE:
	    win_update(w);
	    ch = ' ';
	    break;

	  case MENU_KMOUSE:
	    win_get_mouse(WIN_REC_NULL,
	      &old_buttons, &new_buttons, &msrow, &mscol);
	    if (old_buttons && !new_buttons) {
	      ev = kb_get_ms_event();
	      mouse_pixel_x = ev->ev_ms_pix_col;
	      mouse_pixel_y = ev->ev_ms_pix_row;
	      if (old_buttons & MS_LEFT_BUTTON_MASK) {
		ch = '-';
	      } else if (old_buttons & MS_MIDDLE_BUTTON_MASK) {
		ch = ' ';
	      } else if (old_buttons & MS_RIGHT_BUTTON_MASK) {
		ch = '+';
	      }
	    }
	    break;

	  case MENU_KTOGGLE_INS:
	  case MENU_KHELP:
	  case MENU_KESCAPE:
	  case MENU_KNULL:
	  case MENU_KCSI:
	  case MENU_KKEYPAD:
	  case MENU_KFUNC:
	  case MENU_KTIMEOUT:
	  case MENU_KAPP_DEFINED:
	  case MENU_KPICKLIST:
	  default:
	    break;
	  }
	}

#if MOUSE
	msctl((long)old_ctl, NULL);
#endif
#if VGA_DEBUG
	printf("Returning ch: %c\n", ch); fflush(stdout);
#endif
	return ch;
#else
	static int last_ch = 0;
	int ch;
	ch = getchar();
	if ((ch == '\n' || ch == '\r') && last_ch == '\n') ch = getchar();
	if (ch == '\r') ch = '\n';
	last_ch = ch;
	return ch;
#endif
}

void vgasco_printf(const char *format, ...)
{
#if !USE_WIN
  static int row = 0;
#endif
  va_list ap;
  va_start(ap, format);
  if (did_console_init) {
#if USE_WIN
    vwprintf(WIN_NULL_INDEX, format, ap);
    win_update(WIN_REC_NULL);
    win_flush(WIN_REC_NULL);
#else
    char buf[1024];
    int pos, i, len;
    buf[0] = '\0';
    vsprintf(buf, format, ap);
    len = strlen(buf);
    console_setcolor(7);
    i = 0;
    while (i < len) {
      pos = i;
      while (i < len && buf[i] != '\n' && buf[i] != '\r') i++;
      if (i > pos) {
        row++;
        if (row >= 24) row = 1;
        console_gotorc(row, 1);
        console_putstr(&buf[pos], i - pos);
      }
      while (i < len && (buf[i] == '\n' || buf[i] == '\r')) i++;
    }
#endif
  } else {
    vprintf(format, ap);
  }
  va_end(ap);
}

#if !USE_WIN
int ms_set_pix_location(int cy, int cx)
{
  /* not implemented for now */
}
#endif
