#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <libtext.h>
#include <go32.h>
#include <dpmi.h>
#include <sys/nearptr.h>
#include <stdlib.h>
#include "aalib.h"
#include "aaint.h"
int __use_nearptr_hack;
struct aa_driver dos_d;
static int mode;
static int direction;
#define addmode(mode,x,y)  { \
   nmodes++; \
   lastmode=mode; \
   if(width) { \
   if(abs(p->width-x)+abs(p->height-y)<xd) bestmode=mode,xd=abs(p->width-x)+abs(p->height-y);\
   } \
   if(abs(recwidth-x)+abs(recheight-y)<xd1) recmode=mode,xd1=abs(recwidth-x)+abs(recheight-y);\
   }

static int dos_init(__AA_CONST struct aa_hardware_params *p,__AA_CONST  void *none, struct aa_hardware_params *dest, void **params)
{
    int i, x, y, nmodes = 0;
    int bestmode = -1;
    int recmode = -1;
    int lastmode = 0;
    int noprint = 1;
    int width = 0, height = 0;
    int recwidth = 80, recheight = 50;
    int xd = 1000;
    int xd1 = 1000;
    static aa_font font;
    static char *data,*fdata;
    static struct aa_hardware_params def = {
     NULL, AA_DIM_MASK | AA_REVERSE_MASK | AA_NORMAL_MASK | AA_BOLD_MASK | AA_ALL,
     40, 10,
     137, 60,
     80, 50,
     290, 215,
    };
    char modes[60];
    *dest=def;
    if (p->width || p->height) {
	if (p->width)
	    width = p->width;
	else
	    width = 80;
	if (p->height)
	    width = p->height;
	else
	    height = 80;
    }
    if (p->recwidth)
	recwidth = p->recwidth;
    if (p->recheight)
	recwidth = p->recheight;
    memset(modes, 0, 53);
    TxInit();
  again:;
    if (!noprint)
	printf("Please select internal resolution\n\n");
    if (!noprint)
	printf("VGA modes\n");
    for (i = 0;; i++) {
	if (!noprint && i == 45)
	    printf("\n\nVESA modes\n");
	TxGetModeInfo(i, &x, &y);
	if (x < 0)
	    break;
	if (x) {
	    if (aa_validmode(x, y, p)) {
		if (!noprint)
		    printf("%2i (= %03ix%03i),\t", i, x * 2, y * 2);
		modes[i] = 1;
		addmode(i, x, y);
	    }
	}
    }
    if (aa_validmode(80, 25, p)) {
	if (!noprint)
	    printf("\n\n50 - MDA\t51 - Dual monitor mode\t");
	modes[50] = 1,
	    modes[51] = 1;
	addmode(50, 80, 25);
	addmode(51, 80, 25);
    }
    if (aa_validmode(160, 25, p)) {
	if (!noprint)
	    printf("52 - Dual monitor mode plus");
	modes[52] = 1;
	addmode(51, 160, 25);
    }
    if (!noprint)
	printf("\n");
    mode = 1;
    if (!xd)
	mode = bestmode;
    else {
	if (nmodes == 1)
	    mode = lastmode;
	else {
	    if (noprint) {
		if (!nmodes)
		    return 0;
		noprint = 0;
		goto again;
	    }
	    printf("\b\b\nSelect resolution (press enter to set default resolution): ");
	    do {
		char c[256];
		gets(c);
		mode = -1;
		sscanf(c, "%i", &mode);
		if (mode == -1) {
		    if (recmode >= 0)
			mode = recmode;
		    else
			mode = 11;
		    break;
		}
	    } while (mode < 0 || mode >= 53 || !modes[mode]);
	}
    }
    if (mode == 52) {
	printf("1-MDA is at the left\t2-MDA is at the right\n");
	do {
	    scanf("%i", &direction);
	} while (direction < 1 || direction > 2);
    }
    if (mode < 50) {
	if (TxSetMode(mode) == -1) {
	    printf("Inicialization failed\n");
	    return 0;
	}
	font.height = GetFontHeight();
	font.data = fdata = malloc(font.height * 256);
	font.name = "Font used by your vgacard";
	font.shortname = "current";
	data = malloc(0x10000);
	TxGetFont(data);
	for (i = 0; i < 256; i++) {
	    int y;
	    for (y = 0; y < font.height; y++)
		fdata[i * font.height + y] = data[i * 32 + y];
	}
	free(data);
	aa_registerfont(&font);
	dest->font = &font;
    } else {
	dest->font = &aa_font14;
	dest->supported = AA_NORMAL_MASK | AA_REVERSE_MASK | AA_BOLD_MASK | AA_EXTENDED;
	if (mode > 50)
	    TxSetMode(7);
    }
    if (mode == 52)
	dest->mmwidth = 290 * 2;
    aa_recommendlowkbd("dos");
    return 1;
}
static void dos_uninit(aa_context * c)
{
    if (mode != 50)
	TxUninit();
}
static void dos_getsize(aa_context * c, int *width, int *height)
{
    if (mode < 50) {
	*width = /*info.screenwidtah */ TxMaxx() + 1;
	*height = /*info.screenheight */ TxMaxy() + 1;
    } else {
	*width = 80;
	*height = 25;
	if (mode == 52)
	    (*width) *= 2;
    }
}

static void mymovedata(char *c1, int d, int l)
{
    if (!__use_nearptr_hack) {
	movedata(_my_ds(), (int) c1, _dos_ds, d, l);
    } else {
/*__djgpp_nearptr_enable();*/
	memcpy(__djgpp_conventional_base + (char *) d, c1, l);
/*__djgpp_nearptr_disable();*/

    }
}

static void dos_flush(aa_context * c)
{				/*ugly..but better than previous one :) */
    int x, end = aa_scrwidth(c) * aa_scrheight(c);
    char buffer[aa_scrwidth(c) * aa_scrheight(c) * 2], *pos;
    unsigned char data[] =
    {0x07, 0x08, 0x0f, 0x0f, 0x70, 0x17};
    /*pos=__djgpp_conventional_base+0xB8000; */
    pos = buffer;
    for (x = 0; x < end; x++) {
	*(pos++) = c->textbuffer[x];
	/*if (c->attrbuffer[x] < 7) */
	*(pos++) = data[c->attrbuffer[x]];
	/*else
	   *(pos++)=0x27; */
    }
    if (mode == 52) {
	for (x = 0; x < end; x += 160) {
	    if (direction == 2) {
		mymovedata(&buffer[x * 2], 0xb8000 + x, 160),
		    mymovedata(&buffer[x * 2 + 160], 0xb0000 + x, 160);
	    } else {
		mymovedata(&buffer[x * 2], 0xb0000 + x, 160),
		    mymovedata(&buffer[x * 2 + 160], 0xb8000 + x, 160);
	    }
	}
    } else {
	if (mode != 50)
	    mymovedata(&buffer[0], 0xb8000, aa_scrwidth(c) * aa_scrheight(c) * 2);
	if (mode >= 50)
	    mymovedata(&buffer[0], 0xb0000, aa_scrwidth(c) * aa_scrheight(c) * 2);
    }
    /*dosmemput(buffer,aa_scrwidth(c)*aa_scrheight(c)*2,0xB8000); */
}

static void mono_gotoxy(int x, int y)
{
	unsigned short addr=y*TxScreenSizex()+x;
	asm ("
		movw	%0,%%bx
		movb	%%bh,%%ah
		movb	$0x0e,%%al
		movw	$0x3b4,%%dx
		outw	%%ax,%%dx
		incb	%%al
		movb	%%bl,%%ah
		outw	%%ax,%%dx
		"
		:
		:"r"(addr)
		:"%eax","%ebx","%edx"
	);
}

static void dos_gotoxy(aa_context * c, int x, int y)
{
    if (mode == 52) {
      if(x<80) {
        if(direction==2) TxGotoxy(x,y),mono_gotoxy(255,255);
        if(direction==1) TxGotoxy(255,255),mono_gotoxy(x,y);
      } else {
        if(direction==1) TxGotoxy(x-80,y),mono_gotoxy(255,255);
        if(direction==2) TxGotoxy(255,255),mono_gotoxy(x-80,y);
      }
    } else {
    if (mode != 50)
	TxGotoxy(x, y);
    if (mode>=50) mono_gotoxy(x,y);
    }
}

static void dos_cursor(aa_context *c,int mode1)
{
   if(!mode1) {
   if(mode!=50) TxGotoxy(255,255);
   if(mode>=50) mono_gotoxy(255,255);
   } else dos_gotoxy(c,c->cursorx,c->cursory);
#if 0
   if(!mode) {
    TxSetCursor(22,24);
   } else {
    TxSetCursor(1,0);
   }
#endif
}
__AA_CONST struct aa_driver dos_d =
{
    "dos", "dos pc driver 1.0",
    dos_init,
    dos_uninit,
    dos_getsize,
    NULL,
    NULL,
    dos_gotoxy,
    dos_flush,
    dos_cursor
};
