/******************************************************************************
*           Change Log
*  Date     |  Chnage
*------------------------------------------------------------------------------
* 20-DEC-95 | JRJ    Got rid of some ifdefs because Borland now supports _asm
* 20-Dec-95 | JRJ    Fixed text background color for Borland implementation
* 20-Dec-95 | JRJ    Changed sc_remappalette to call BIOS 0x10 subfunc 0x16
*                    (Borland implementation)
******************************************************************************/

#include "btypes.h"
#include "scdspmsg.h"
#include "color.h"

#ifdef __BORLANDC__
#include <conio.h>
#include <stdio.h>
/* #pragma inline */
#endif

struct rccoord sc_gettextposition();

extern struct videoconfig video;

#ifndef __BORLANDC__
#include "graph.h"
#endif

#define CURSOR_UNDERLINE        0
#define CURSOR_DOUBLE_UNDERLINE 1
#define CURSOR_BLOCK		2

static short cursortype = CURSOR_UNDERLINE;

/****************************************************************************
*                                  scdspmsg
* Inputs:
*       unsigned char row: Row to display string
*	unsigned char col: Column to display string
*	unsigned char fore: Foreground color
*	unsigned char back: Background color
*	char * str: string to display
* Result: void
*
* Effect:
*       Displays the string at the indicated position with the
*	indicated colors.  Updates textposition
****************************************************************************/

void scdspmsg(unsigned char row, unsigned char col,
	unsigned char fore, unsigned char back, char * str)
    {
     char c;
     char a = (back << 4) + (fore & 0xF);
     struct rccoord xy;
     struct rccoord txy;
     xy = sc_gettextposition();

     sc_settextposition(row+1,col+1);

     while(c = *str++)
	{ /* emit each char */
	 /*
	    Write character and attribute at cursor
	 */

	 _asm { /* asm */
		mov bh,0;	/* page */
		mov dh,row;
		mov dl, col;
		mov ah, 0x02;	/* subfunction 02h: Set cursor pos */
		int 0x10;
		mov ah, 0x09;	/* subfunction 09h: Write char & attr */
		mov al, c;	/* character */
		mov bh, 0;	/* page */
		mov bl, a;	/* attribute */
		mov cx, 1;	/* one character */
		int 0x10;	/* video */
	      } /* asm */

	 sc_settextposition(row,++col);
	} /* emit each char */
    }

/****************************************************************************
*                                  scattrib
* Inputs:
*       unsigned char fore: foreground color
*	unsigned char back: background color
*	unsigned char c: Character to draw
*	short cnt: Replication factor
* Result: void
*
* Effect:
*       Draws the character as indicated
****************************************************************************/

void scattrib(unsigned char fore, unsigned char back, unsigned char c,
		 short cnt)
    {
     char a = (back << 4) + (fore & 0xF);

     _asm { /* asm */
	    mov ah,0x09;	/* subfunction 09h */
	    mov al,c;	/* character */
	    mov bh,0;	/* page */
	    mov bl,a;	/* attribute */
	    mov cx,cnt; /* rep characters */
	    int 0x10;	/* video */
	  } /* asm */
   }

/****************************************************************************
*                              sc_setnormalcursor
* Result: void
*
* Effect:
*       Sets a normal (underline or block) cursor, as specified by some
*	means we have not established
****************************************************************************/

void sc_setnormalcursor()
    {
     switch(cursortype)
	{ /* which cursor */
	 case CURSOR_UNDERLINE:
		 sc_settextcursor(SC_CURSOR_UNDERLINE);
		 break;
	 case CURSOR_DOUBLE_UNDERLINE:
		 sc_settextcursor(SC_CURSOR_DOUBLE);
		 break;
	 case CURSOR_BLOCK:
		 sc_settextcursor(SC_CURSOR_BLOCK);
		 break;
	} /* which cursor */
    }

/****************************************************************************
*                                sc_setnocursor
* Result: void
*
* Effect:
*       Turns off text cursor
****************************************************************************/

void sc_setnocursor()
    {
     sc_settextcursor(SC_CURSOR_NONE);
    }

/****************************************************************************
*                                  scscroll
* Inputs:
*       unsigned char numlines: Number of lines to scroll
*	unsigned char color: Color attribute
*	unsigned char y0: upper left y-coordinate
*	unsigned char x0: upper left x-coordinate
*	unsigned char y1: lower right y-coordinate
*	unsigned char x1: lower right x-coordinate
*	unsigned char dir: direction, SCR_UP | SCR_DOWN
* Result: void
*
* Effect:
*       Scrolls the window indicated by the coordinates given
****************************************************************************/

void scscroll(unsigned char numlines, unsigned char color, unsigned char y0, unsigned char x0, unsigned char y1, unsigned char x1, unsigned char dir)
    {
     /*
	ah  0x06 scroll up, 0x07 scroll down
	al  # of lines, 0 to blank entire window
	bh  attribute for blanked area
	ch  upper left y-coordinate
	cl  upper left x-coordinate
	dh  lower right y-coordinate
	dl  lower right x-coordinate
     */

     _asm {
	   mov ah, dir;
	   mov al, numlines;
	   mov bh, color;
	   mov ch, y0;
	   mov cl, x0;
	   mov dh, y1;
	   mov dl, x1;
	   int 0x10;
	  };
    }

/****************************************************************************
*                                   scread
* Inputs:
*       unsigned char * fore: foreground attribute
*	unsigned char * back: background attribute
* Result: unsigned char
*       Character
* Effect:
*       Reads the fore/background attributes of the current cursor position
****************************************************************************/

unsigned char scread(unsigned char * fore, unsigned char * back)
    {
     unsigned char a;
     unsigned char c;

     _asm{
	  mov ah,0x08;
	  mov bh, 0;   /* page */
	  int 0x10;	/* read char and attribute */
	  mov a,ah;
	  mov c,al;
	 };
      *fore = a & 0x0F;
      *back = a >> 4;
      return c;
    }

/****************************************************************************
*                                  sccurset
* Inputs:
*       unsigned char row:
*	unsigned char col:
* Result: void
*
* Effect:
*       Sets the cursor position
****************************************************************************/

void sccurset(unsigned char row, unsigned char col)
    {
     sc_settextposition(row+1, col+1);
    }

/****************************************************************************
*                                  sccurpos
* Inputs:
*       unsigned char * row, unsigned char * col
* Result: void
*
* Effect:
*       Gets the cursor position
****************************************************************************/

void sccurpos(unsigned char * row, unsigned char * col)
    {
     struct rccoord xy;
     xy = sc_gettextposition();
     *row = xy.row - 1;
     *col = xy.col - 1;
    }

/****************************************************************************
*                                  scattribs
* Inputs:
*       unsigned char color: Color to set in rectangle
*	unsigned char y0: Upper left y-coordinate
*	unsigned char x0: Upper left x-coordinate
*	unsigned char y1: Lower right y-coordinate
*	unsigned char x1: Lower right x-coordinate
* Result: void
*
* Effect:
*       Sets attributes in the rectangle without changing the characters
****************************************************************************/

void scattribs(unsigned char color, unsigned char y0, unsigned char x0, unsigned char y1, unsigned char x1)
    {
     unsigned char x;
     unsigned char y;
     unsigned char old_x;
     unsigned char old_y;

     sccurpos(&old_y, &old_x);
     for(x = x0; x < x1; x++)
	for(y = y0; y < y1; y++)
	   { /* fill chars */

	    _asm {
		  mov ah, 0x02;  /* set cursor position */
		  mov bh, 0;     /* page */
		  mov dh, y;	   /* row */
		  mov dl, x;	   /* column */
		  int 0x10;	   /* do it */

		  mov ah, 0x08;  /* read char & attribute */
		  mov bh, 0;	   /* page */
		  int 0x10;	   /* do it */

		  /* ah is attribute */
		  /* al is character */

		  mov ah, 0x09;   /* set char & attribute */
		  mov bh,0;	    /* page */
		  mov bl,color;   /* attribute to set */
		  mov cx,1;	    /* only for one character */
		  int 0x10;	    /* rewrite char with new attribute */
		 }
	   } /* fill chars */

     sccurset(old_y, old_x);
    }

/****************************************************************************
*                                    click
* Result: void
*
* Effect:
*       Makes a "click" on the speaker to indicate a card column has
*	been "punched"
****************************************************************************/

void click()
    {
     /* NYI */
    }

/*
	sc_getvideoconfig - get video card information
*/

void sc_getvideoconfig(struct videoconfig *video)
{

#ifndef __BORLANDC__
	_getvideoconfig(video);
#endif

#ifdef __BORLANDC__
	struct text_info text_info;
	int gdriver,gmode;

	gettextinfo(&text_info);
	detectgraph(&gdriver,&gmode);
	video->numxpixels = 0;		/* Indicating non graphics mode */
	video->numypixels = 0;		/* Indicating non graphics mode */
	video->numtextcols = text_info.screenwidth;
	video->numtextrows = text_info.screenheight;
	video->numcolors = -1;		/* Not used in this program */
	video->bitsperpixel = -1;	/* Not used in this program */
	video->numvideopages = -1;	/* Not used in this program */
	video->mode = -1;		/* Not used in this program */
	video->adapter = gdriver;
	video->monitor = gdriver;
	video->memory = -1;
#endif
}


/*
	Init video card (if necessary)
*/
int sc_init_graphics(void)
{

#ifndef	__BORLANDC__
	return(1);
#endif

#ifdef	__BORLANDC__
	return(1);
#endif

}

/*
	routine to set video mode
*/
short sc_setvideomode(short mode)
{

#ifndef __BORLANDC__
	return(_setvideomode(mode));
#endif

#ifdef	__BORLANDC__
	int gdriver,gmode,grerror;

	detectgraph(&gdriver,&gmode);
	if((grerror = graphresult()) != grOk) {
		fprintf(stderr,"scdspmsg.c: Error %d in detectgraph.\n",
			grerror);
		return(0);
	}
	switch(mode) {
	case SC_C80:
		if(gdriver == HERCMONO || gdriver == EGAMONO)
			return(0);
		break;
	case SC_BW80:
		if(gdriver != HERCMONO && gdriver != EGAMONO)
			return(0);
		break;
	default:
		fprintf(stderr,"sc_setvideomode: unexpected mode: %d\n",
			mode);
		return(0);
	}
	textmode(mode);
	textbackground(BLACK);
	return(1);
#endif

}

/*
	Routine to re-map color pallettes on EGA and VGA type adapters.
*/

short sc_remappalette(short index, long rgb)
{

#ifndef __BORLANDC__
	return _remappalette(index,rgb);
#endif

#ifdef __BORLANDC__

	int r,g,b,color;
	unsigned char do_index, do_color;

	switch(video.adapter) {
	case EGA:
	case VGA:
		color = (EGA_COLOR(RGB_R(rgb)) << 2) |
			(EGA_COLOR(RGB_G(rgb)) << 1) |
			EGA_COLOR(RGB_B(rgb));
		/* setpalette(index,color); */
		do_color = color;
		do_index = index;
		_asm {
			mov ah,0x10;		/* Set palette registers */
			mov al,0x00;		/* set one register  */
			mov bh,do_color;	/* color to use */
			mov bl,do_index;	/* color index */
			int 0x10;		/* just do it */
		}
		/*
		if(graphresult != grOk) {
			return(-1);
		}
		*/
		break;
	case MCGA:
	case IBM8514:
		setrgbpalette(index,
			RGB_R(rgb) << 2,
			RGB_G(rgb) << 2,
			RGB_B(rgb) << 2);
		return(0);
		break;
	default:
		fprintf(stderr,"sc_remappalette: Invalid adapter: %d\n",
			video.adapter);
		return(-1);
	}

	return(0);

#endif
}

/*
	Routine to put text out to console.  This is here because the
	original progam used MicroSoft's _outtext, even though cputs
	probably would have worked OK.
*/
void sc_outtext(char *s)
{

#ifndef __BORLANDC__
	_outtext(s);
#endif

#ifdef __BORLANDC__
	cputs(s);
#endif
}

/*
	Routine to set current text position
*/
void sc_settextposition(short row, short col)
{

#ifndef __BORLANDC__
	_settextposition(row,col);
#endif

#ifdef __BORLANDC__
	gotoxy(col,row);
#endif
}

/*
	Routine to clear the screen
*/
void sc_clearscreen()
{

#ifndef __BORLANDC__
	_clearscreen(_GCLEARSCREEN);
#endif

#ifdef __BORLANDC__
	clrscr();
#endif
}

/*
	Routine to set cursor type
*/
void sc_settextcursor(short cursor)
{

#ifndef __BORLANDC__
	_settextcursor(cursor);
#endif

#ifdef __BORLANDC__
	_setcursortype(cursor);
#endif

}

/*
	Routine to return the location of the cursor
*/
struct rccoord sc_gettextposition()
{

#ifndef __BORLANDC__
	return(_gettextposition());
#endif

#ifdef  __BORLANDC__
	static struct rccoord t;
	t.row = (short) wherex;
	t.col = (short) wherey;
	return(t);
#endif
}

/*
	And, finally, a mouse routine, since we don't want everyone to
	need the library!
*/
void real_mouse(short *m1, short *m2, short *m3, short *m4)
{
	short im1,im2,im3,im4;

	im1 = *m1;
	im2 = *m2;
	im3 = *m3;
	im4 = *m4;

	_asm {
	mov	ax,im1
	mov	bx,im2
	mov	cx,im3
	mov	dx,im4
	int	51
	mov	im1,ax
	mov	im2,bx
	mov	im3,cx
	mov	im4,dx
	}

	*m1 = im1;
	*m2 = im2;
	*m3 = im3;
	*m4 = im4;
}