#ifndef AUTOBUILD
// autobuild does not create lang.h, but defines LANG_{RUS,ENG} directly
#include "lang.h"
#endif

#include "system/kolibri.h"
#include "system/stdlib.h"
#include "system/string.h"
#include "z80/z80.h"
#include "48.h"

#include "system/msgbox.c"

///=============================

#define TYPE_NO		0
#define TYPE_SNA	1
#define TYPE_Z80	2

#define SCREEN_LEN	3*3*256*192*3

char WND_CAPTION[] = {"e80 v0.5.1"};

extern char KOL_PARAM[256];
extern char KOL_PATH[256];

char szBackup[256];
char szScreen[256];

int fila[5][5];
int main_tecla, hay_tecla;
int SSCS = 0;

int debug=0, scanl=0;
int frame_counter;
int target_cycle;
Z80Regs spectrumZ80;

char *screen;
unsigned screen_w, screen_h;
#define  screen_a_w   512
#define  screen_a_h   384
int flash = 0;
unsigned time = 0;

///=============================

#include "keyboard.c"

///=============================

int get_ext(char *filename)
{

return TYPE_SNA;
}

///=============================

void memory_print(Z80Regs *regs, char *filename)
{
kol_struct70 file;

file.p00 = 2;
file.p04 = 0;
file.p08 = 0;
file.p12 = 64*1024;
file.p16 = (unsigned)(regs->RAM);
file.p20 = 0;
file.p21 = filename;

kol_file_70(&file);
}


///=============================

void all_print(Z80Regs *regs, char *filename)
{
kol_struct70 file;

file.p00 = 2;
file.p04 = 0;
file.p08 = 0;
file.p12 = sizeof (Z80Regs);
file.p16 = (unsigned)regs;
file.p20 = 0;
file.p21 = filename;

kol_file_70(&file);
}

///=============================

void screen_print(Z80Regs *regs)
{

kol_struct70 file;

char palette[]=
	{
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0xB0, 0x00, 0x00, 0xB0, 0x00, 0x00, 
	0x00, 0x00, 0xB0, 0x00, 0x00, 0xB0, 
	0xB0, 0x00, 0xB0, 0xB0, 0x00, 0xB0,
	0x00, 0xB0, 0x00, 0x00, 0xB0, 0x00,
	0xB0, 0xB0, 0x00, 0xB0, 0xB0, 0x00, 
	0x00, 0xB0, 0xB0, 0x00, 0xB0, 0xB0,
	0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0,

	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 
	0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 
	0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
	0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00,
	0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 
	0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
	};

char *scr;
char *atr;

char a, c, s;
int i, j, k, l, m;
unsigned bri;
char *color;
char *addr;
int n = 0;
int z = 0;
int x, y;

scr = malloc(6144);
atr = malloc(768);

memcpy(scr, regs->RAM + 0x4000 , 6144);
memcpy(atr, regs->RAM + 0x5800 , 768);

for (j = 0; j < 3 ; j++)
for (i = 0; i < 8; i++)
for (k = 0; k < 8; k++)
for (l = 0; l < 32; l++)
	{
	c = scr[j*2048 + k*256 + i*32 + l];
	for (m = 0; m < 8; m++)
		{
		s = (c & 128) >> 7;
		a = atr[j*256 + i*32 + l];

		if ( (a & 64) == 64 )
			bri = 8;
		else 
			bri = 0;

		if ( 0 == s )
			{
			if (!(flash && (128 == (a&128))))
				color = &palette[6*(bri+((a>>3)&7))];
			else
				color = &palette[6*(bri+(a&7))];

				addr = screen + 2*screen_a_w*3*z + 2*3*n;

				for (y = 0; y < 2; y++)
					memcpy( addr + y*screen_a_w*3, 
						color, 6);
			}
		else
			{
			if (!(flash && (128 == (a&128))))
				color = &palette[6*(bri+(a&7))];
			else
				color = &palette[6*(bri+((a>>3)&7))];
				
				addr = screen + 2*screen_a_w*3*z + 2*3*n;

				for (y = 0; y < 2; y++)
					memcpy( addr + y*screen_a_w*3, 
						color, 6);
			}

		n++;
		if (256 == n)
			{
			n = 0;
			z++;
			}

		c <<= 1;
		}
	}

if ( 33 < (kol_time_tick() - time))
{
if (0 == flash)
	flash = 1;
else 
	flash = 0;
time = kol_time_tick();
}

free(scr);
free(atr);

}

///=============================

void memory_load_z80(Z80Regs *regs, char *filename)
{
char header[30];
kol_struct70 file;

file.p00 = 0;
file.p04 = 0;
file.p08 = 0;
file.p12 = 30;
file.p16 = (unsigned) header;
file.p20 = 0;
file.p21 = filename;
}

///=============================

void memory_load_sna(Z80Regs *regs, char *filename)
{
char buffer[27];
kol_struct70 file;

file.p00 = 0;
file.p04 = 0;
file.p08 = 0;
file.p12 = 27;
file.p16 = (unsigned) buffer;
file.p20 = 0;
file.p21 = filename;

kol_file_70(&file);

regs->I = buffer[ 0];
regs->HLs.B.l = buffer[ 1];
regs->HLs.B.h = buffer[ 2];
regs->DEs.B.l = buffer[ 3];
regs->DEs.B.h = buffer[ 4];
regs->BCs.B.l = buffer[ 5];
regs->BCs.B.h = buffer[ 6];
regs->AFs.B.l = buffer[ 7];
regs->AFs.B.h = buffer[ 8];
regs->HL.B.l  = buffer[ 9];
regs->HL.B.h  = buffer[10];
regs->DE.B.l  = buffer[11];
regs->DE.B.h  = buffer[12];
regs->BC.B.l  = buffer[13];
regs->BC.B.h  = buffer[14];
regs->IY.B.l = buffer[15];
regs->IY.B.h = buffer[16];
regs->IX.B.l = buffer[17];
regs->IX.B.h = buffer[18];
regs->IFF1 = regs->IFF2 = (buffer[19]&0x04) >>2;
regs->R.W  = buffer[20];
regs->AF.B.l = buffer[21];
regs->AF.B.h = buffer[22];
regs->SP.B.l =buffer[23];
regs->SP.B.h =buffer[24];
regs->IM = buffer[25];
regs->BorderColor = buffer[26]; 

file.p00 = 0;
file.p04 = 27;
file.p08 = 0;
file.p12 = 0x4000*3;
file.p16 = (unsigned) regs->RAM+16384;
file.p20 = 0;
file.p21 = filename;

kol_file_70(&file);

regs->PC.B.l = Z80MemRead(regs->SP.W, regs);
regs->SP.W++;
regs->PC.B.h = Z80MemRead(regs->SP.W, regs);
regs->SP.W++; 

}


///=============================

void memory_save_sna(Z80Regs *regs, char *filename)
{
char buffer[27];
unsigned char sptmpl, sptmph;
kol_struct70 file;

buffer[ 0] = regs->I;
buffer[ 1] = regs->HLs.B.l;
buffer[ 2] = regs->HLs.B.h;
buffer[ 3] = regs->DEs.B.l;
buffer[ 4] = regs->DEs.B.h;
buffer[ 5] = regs->BCs.B.l;
buffer[ 6] = regs->BCs.B.h;
buffer[ 7] = regs->AFs.B.l;
buffer[ 8] = regs->AFs.B.h;
buffer[ 9] = regs->HL.B.l;
buffer[10] = regs->HL.B.h;
buffer[11] = regs->DE.B.l;
buffer[12] = regs->DE.B.h;
buffer[13] = regs->BC.B.l;
buffer[14] = regs->BC.B.h;
buffer[15] = regs->IY.B.l;
buffer[16] = regs->IY.B.h;
buffer[17] = regs->IX.B.l;
buffer[18] = regs->IX.B.h;
buffer[19] = regs->IFF1 << 2;
buffer[20] = regs->R.W & 0xFF;
buffer[21] = regs->AF.B.l;
buffer[22] = regs->AF.B.h;

sptmpl = Z80MemRead( regs->SP.W-1, regs );
sptmph = Z80MemRead( regs->SP.W-2, regs );

Z80MemWrite( --(regs->SP.W), regs->PC.B.h, regs);
Z80MemWrite( --(regs->SP.W), regs->PC.B.l, regs);

buffer[23] = regs->SP.B.l;
buffer[24] = regs->SP.B.h;
buffer[25] = regs->IM;
buffer[26] = regs->BorderColor; 

file.p00 = 2;
file.p04 = 0;
file.p08 = 0;
file.p12 = 27;
file.p16 = (unsigned) buffer;
file.p20 = 0;
file.p21 = filename;

kol_file_70(&file);

file.p00 = 3;
file.p04 = 27;
file.p08 = 0;
file.p12 = 0x4000*3;
file.p16 = (unsigned) regs->RAM+16384;
file.p20 = 0;
file.p21 = filename;

kol_file_70(&file);

regs->SP.W += 2;
Z80MemWrite( regs->SP.W-1, sptmpl, regs );
Z80MemWrite( regs->SP.W-2, sptmph, regs );

}


///=============================

void memory_save_scr(Z80Regs *regs, char *filename)
{
kol_struct70 file;


file.p00 = 2;
file.p04 = 0x4000;
file.p08 = 0;
file.p12 = 6912;
file.p16 = (unsigned) regs->RAM+16384;
file.p20 = 0;
file.p21 = filename;

kol_file_70(&file);

}


///=============================

void wnd_draw()
{
kol_paint_start();
kol_wnd_define( (screen_w-540)/2, (screen_h-440)/2, 540, 440,  0x34b0b0b0, 0x34b0b0b0, WND_CAPTION);
screen_print(&spectrumZ80);
kol_paint_image((540 - screen_a_w)/2-5, 
		(440 - screen_a_h-kol_skin_height())/2, 
		screen_a_w, screen_a_h, screen);
kol_paint_end();
}

///=============================

void kol_main()
{

unsigned event;
unsigned key;

for (event = strlen(KOL_PATH); event > 0; --event)
	if ( '/' == KOL_PATH[event] )
		{
		KOL_PATH[event+1]=0;
		break;
		}

strcpy(szBackup, KOL_PATH);
strcpy(szScreen, KOL_PATH);
strcat(szBackup, "backup.sna");
strcat(szScreen, "screen.scr");

kol_screen_get_size(&screen_w, &screen_h);

screen = malloc(SCREEN_LEN);
spectrumZ80.RAM = (char*) malloc(64*1024);
memcpy(spectrumZ80.RAM, BIOS48, 16*1024);

Z80Reset( &spectrumZ80, 69888 );
Z80FlagTables();

fila[1][1] = fila[1][2] = fila[2][2] = fila[3][2] = fila[4][2] =
 fila[4][1] = fila[3][1] = fila[2][1] = 0xFF;

debug = 0;

if (KOL_PARAM != NULL)
	{
	int type = get_ext(KOL_PARAM);
	
	if (TYPE_SNA == type)
		memory_load_sna(&spectrumZ80, KOL_PARAM);
	}

hay_tecla = main_tecla = 0;
//keyboard_process(0);

kol_key_mode_set(1);

for (;;)
	{

//	event = kol_event_check();
	event = kol_event_wait_time(5);

	switch (event)
		{

		case 1:
			wnd_draw();
			break;

		case 2:
			key = (kol_key_get()>>8)&0xff;
			
			switch (key)
				{
				case 60: // F2
					if ( IDOK == MessageBox("Save snapshot?", 
									WND_CAPTION, MB_OKCANCEL) )
						memory_save_sna(&spectrumZ80, 
									szBackup);
					break;

				case 61: // F3
					if ( IDOK == MessageBox("Load snapshot?", 
									WND_CAPTION, MB_OKCANCEL) )
						memory_load_sna(&spectrumZ80, 
									szBackup);
					break;

				case 62: // F4
					if ( IDOK == MessageBox("Save screenshot?", 
									WND_CAPTION, MB_OKCANCEL) )
						memory_save_scr(&spectrumZ80, 
									szScreen);
					break;

				case 88: // F12 Reset
					if ( IDOK == MessageBox("Reset?", 
									WND_CAPTION, MB_OKCANCEL) )
						{
						Z80Reset( &spectrumZ80, 69888 );
						Z80FlagTables();
						fila[1][1] = fila[1][2] = 
						fila[2][2] = fila[3][2] = 
						fila[4][2] = fila[4][1] = 
						fila[3][1] = fila[2][1] = 0xFF;
						}
					break;

				default:
					keyboard_process(key);
				};

			break;

		case 3:
			if ( 1 == (kol_btn_get() & 0xff00)>>8 )
				{
				free(screen);
				free(spectrumZ80.RAM);
				kol_exit();
				}
			break;

		default:
			if (0 == debug)
				{

				Z80Run( &spectrumZ80, 224*64 ); 
				for( scanl=0; scanl<192; scanl++ )
					Z80Run( &spectrumZ80, 224 ); 

				Z80Run( &spectrumZ80, 224*56 ); 

				if( target_cycle < 2 || frame_counter == 0 )
					{
					screen_print(&spectrumZ80);
					kol_screen_wait_rr();
					kol_paint_image((540 - screen_a_w)/2-5, 
							(440 - screen_a_h-kol_skin_height())/2, 
							screen_a_w, screen_a_h, screen);
					}

				while( target_cycle == 0 ) 
					{
					target_cycle--;
					frame_counter++;
					}
				}
			break;

		};

	}

}

///=============================