/*
 *
 * Pyldin-601 emulator version 3.1 for Linux,MSDOS,Win32
 * Copyright (c) Sasha Chukov & Yura Kuznetsov, 2000-2004
 *
 */

#include <kos.h>
#include <stdlib.h>
#include <assert.h>
#include <zlib/zlib.h>

#include "screen.h"
#include "keyboard.h"
#include "timer.h"

#define SCREEN_WIDTH	320
#define SCREEN_DEPTH	2

#define PIXEL_ON		(0x3f<<5) //0xffff
#define PIXEL_OFF		0x0

#define VPIXEL_ON		(0x1f<<5) //
#define KBD_COLOR		0xffff //((0x3f<<5) | 0x1f)

#include "virtkbd.xbm"
#include "vmenu.xbm"

int vkbdEnable = 0;
int redrawVMenu = 0;
int clearVScr = 0;

byte vregs[16];
byte *vMem;

byte m601a = 0;
short txt260 = -1;
short grf260 = -1;

byte resolution, vMode = 0, old_vMode = 0;

byte font[2048];
word *vscr;		//videomem start

void setupScr(int mode)
{
	vMode = mode & 0x20;
//	if (vMode!=old_vMode) ClrLines(0,37119);
	old_vMode = vMode;
	resolution = mode & 0x02;
	clearVScr = 1;
	redrawVMenu = 1;
//	palette = (mode & 0x18)>>3;
//	colorMode = mode & 0x04;
}

void drawVMenu(void)
{
	int ofj = 216*320;
	int ifj = 0;
	for (int j = 0; j < vmenu_height; j++) {
		for (int i = 0; i < (vmenu_width>>3); i++) {
			unsigned char c = vmenu_bits[ifj+i];
			for (int x = 0; x < 8; x++) {
				vscr[ofj+i*8+x] = (c & 0x1)?0:0x3ef;
				c >>= 1;
			}
		}
		ofj += 320;
		ifj += (vmenu_width>>3);
	}
}

void clearScr(void)
{
	memset((char *)vscr, 0, 320*240*2);
}

void refreshScr()
{
	byte *src = vMem;
	byte *crsr = vMem;
	dword c, v, j, i, ofj, ofi;

	if (clearVScr) {
		clearScr();
		clearVScr = 0;
	}

	byte cur_start = vregs[0x0a] & 0x1f;
	byte cur_start1 = vregs[0x0a];
	byte cB_1 = vregs[0x0a] & 0x60;
	byte cur_end = vregs[0x0b] & 0x1f;

	if (cur_end > 7) cur_end = 7;
	if ((cur_start > cur_end) || (cur_start1 == 0x20)
			|| (curBlink > 25 && cB_1 != 0)) {
		cur_start = 8;
		cur_end = 7;
	}
	if (curBlink > 50) curBlink = 0;

	if (vMode == 0) {
		src += (word)((vregs[0x0c] << 8) + vregs[0x0d]);
		crsr += (word)((vregs[0x0e] << 8) + vregs[0x0f] + txt260);
		byte rHor = vregs[0x01];
		byte rVer = vregs[0x06];
		if (rHor > 42) rHor=42;
		if (rVer > 29) rVer=29;

		// для коррекции вывода 27 строки при BIOS 2.60
		// if (txt260 == 1 && rVer > 26) rVer=29;

		ofj = 0;
		if (vkbdEnable == 0) { //no virtual keyboard on screen
			for (j = 0; j < rVer; j++) {
			    for (i = 0; i < rHor; i++) {
					ofi=ofj+i*8;
					c = *src++;
					c = ((c<<1) | (c>>7)) & 0xff;
					c = c * 8;
					if (i<40) 
					for (v = 0; v < 8; v++) {
						byte t1 = font[c+v];
						if (crsr == src) if (v>=cur_start && v<=cur_end) t1^=0xff;
						for (int z=0; z<8; z++) {
							vscr[ofi+z] = (t1 & 0x80)?PIXEL_ON:PIXEL_OFF;
							t1 <<= 1;
						}
						ofi += SCREEN_WIDTH;
					}
					if (src >= vMem + 0xffff) src = vMem + 0xf000;
			    }
			    ofj += SCREEN_WIDTH*8;
			}
		} else {
			int vkbd_y = 0;
			int vkbd_yt = 0;
			for (j = 0; j < rVer; j++) {
			    for (i = 0; i < rHor; i++) {
					ofi=ofj+i*8;
					vkbd_yt = vkbd_y+i;
					c = *src++;
					c = ((c<<1) | (c>>7)) & 0xff;
					c = c * 8;
					if (i<40) 
					for (v = 0; v < 8; v++) {
						byte t1 = font[c+v];
						byte vt1 = virtkbd_pict_bits[vkbd_yt];
						if (crsr == src) if (v>=cur_start && v<=cur_end) t1^=0xff;
						for (int z=0; z<8; z++) {
							vscr[ofi+z] = ((t1 & 0x80)?VPIXEL_ON:PIXEL_OFF) | ((vt1 & 0x1)?0:KBD_COLOR);
							t1 <<= 1;
							vt1 >>= 1;
						}
						ofi += SCREEN_WIDTH;
						vkbd_yt += (virtkbd_pict_width>>3);
					}
					if (src >= vMem + 0xffff) src = vMem + 0xf000;
			    }
			    ofj += SCREEN_WIDTH*8;
				vkbd_y += (virtkbd_pict_width>>3)*8;
			}
		}
	} else {
		src += (word)(((vregs[0x0c] << 8) + vregs[0x0d]) << 3);
		crsr += (word)(((vregs[0x0e] << 8) + vregs[0x0f] + grf260) << 3);
		byte rHor = vregs[0x01];
		byte rVer = vregs[0x06];
		if (rHor > 48) rHor=48;
		if (rVer > 28) rVer=28;

		ofj = 0;

		if (vkbdEnable == 0) {
/* drawing without virtual keyboard */
		for (j = 0; j < rVer; j++) {
		    for (i = 0; i < rHor; i++) {
				ofi=ofj+i*8;
				if (src >= vMem + 0xfff8) src = vMem;
				if (crsr != src) {
				    for (v = 0; v < 8; v++) {
						byte t1 = *src++;
						for (int z = 0; z < 8; z++) {
							vscr[ofi+z] = (t1 & 0x80)?PIXEL_ON:PIXEL_OFF;
							t1 <<= 1;
						}
						//if (enable320 == 0) if (i==39) t1=0;
						ofi += SCREEN_WIDTH;
				    }
				} else {
				    for (v = 0; v < cur_start; v++) {
						byte t1 = *src++;
						for (int z = 0; z < 8; z++) {
							vscr[ofi+z] = (t1 & 0x80)?PIXEL_ON:PIXEL_OFF;
							t1 <<= 1;
						}
						//if (enable320 == 0) if (i==39) t1=0;
						ofi += SCREEN_WIDTH;
					}
					for (v = cur_start; v <= cur_end; v++) {
						byte t1 = *src++ ^ 0xff;
						for (int z = 0; z < 8; z++) {
							vscr[ofi+z] = (t1 & 0x80)?PIXEL_ON:PIXEL_OFF;
							t1 <<= 1;
						}
						//if (enable320 == 0) if (i==39) t1=0;
						ofi += SCREEN_WIDTH;
					}
					for (v = cur_end+1; v < 8; v++) {
						byte t1 = *src++;
						for (int z = 0; z < 8; z++) {
							vscr[ofi+z] = (t1 & 0x80)?PIXEL_ON:PIXEL_OFF;
							t1 <<= 1;
						}
						//if (enable320 == 0) if (i==39) t1=0;
						ofi += SCREEN_WIDTH;
					}
				}		
			}
		    ofj += SCREEN_WIDTH*8;
		}
/* end drawing without virtual keyboard */
		} else {
/* drawing with virtual keyboard */
		int vkbd_y = 0;
		int vkbd_yt = 0;
		for (j = 0; j < rVer; j++) {
		    for (i = 0; i < rHor; i++) {
				ofi=ofj+i*8;
				vkbd_yt = vkbd_y+i;
				if (src >= vMem + 0xfff8) src = vMem;
				if (crsr != src) {
				    for (v = 0; v < 8; v++) {
						byte t1 = *src++;
						byte vt1 = virtkbd_pict_bits[vkbd_yt];
						for (int z = 0; z < 8; z++) {
							vscr[ofi+z] = ((t1 & 0x80)?PIXEL_ON:PIXEL_OFF) | ((vt1 & 0x1)?0:KBD_COLOR);
							t1 <<= 1;
							vt1 >>= 1;
						}
						//if (enable320 == 0) if (i==39) t1=0;
						ofi += SCREEN_WIDTH;
						vkbd_yt += (virtkbd_pict_width>>3);
				    }
				} else {
				    for (v = 0; v < cur_start; v++) {
						byte t1 = *src++;
						byte vt1 = virtkbd_pict_bits[vkbd_yt];
						for (int z = 0; z < 8; z++) {
							vscr[ofi+z] = ((t1 & 0x80)?PIXEL_ON:PIXEL_OFF) | ((vt1 & 0x1)?0:KBD_COLOR);
							t1 <<= 1;
							vt1 >>= 1;
						}
						//if (enable320 == 0) if (i==39) t1=0;
						ofi += SCREEN_WIDTH;
						vkbd_yt += (virtkbd_pict_width>>3);
					}
					for (v = cur_start; v <= cur_end; v++) {
						byte t1 = *src++ ^ 0xff;
						byte vt1 = virtkbd_pict_bits[vkbd_yt];
						for (int z = 0; z < 8; z++) {
							vscr[ofi+z] = ((t1 & 0x80)?PIXEL_ON:PIXEL_OFF) | ((vt1 & 0x1)?0:KBD_COLOR);
							t1 <<= 1;
							vt1 >>= 1;
						}
						//if (enable320 == 0) if (i==39) t1=0;
						ofi += SCREEN_WIDTH;
						vkbd_yt += (virtkbd_pict_width>>3);
					}
					for (v = cur_end+1; v < 8; v++) {
						byte t1 = *src++;
						byte vt1 = virtkbd_pict_bits[vkbd_yt];
						for (int z = 0; z < 8; z++) {
							vscr[ofi+z] = ((t1 & 0x80)?PIXEL_ON:PIXEL_OFF) | ((vt1 & 0x1)?0:KBD_COLOR);
							t1 <<= 1;
							vt1 >>= 1;
						}
						//if (enable320 == 0) if (i==39) t1=0;
						ofi += SCREEN_WIDTH;
						vkbd_yt += (virtkbd_pict_width>>3);
					}
				}		
			}
		    ofj += SCREEN_WIDTH*8;
			vkbd_y += (virtkbd_pict_width>>3)*8;
		}
/* end drawing with virtual keyboard */
		}

	}
	if (redrawVMenu) {
		redrawVMenu = 0;
		drawVMenu();
	}
}

int loadTextFont(char *name)
{
	gzFile inf = gzopen(name, "rb");
	if (inf == 0) return -1;
	gzread(inf, font, 2048);
	gzclose(inf);
	return 0;
}
