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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <zlib.h>

#include <SDL/SDL.h>
#include <SDL/SDL_thread.h>

#include "pyldin.h"
#include "mc6800.h"
#include "screen.h"
#include "keyboard.h"
#include "floppy.h"
#include "wave.h"


//#define DATADIR	"/usr/share/pyldin"
#define DATADIR	"share"

char *datadir = DATADIR;

#define MAX_LOADSTRING 100

static SDL_Surface *screen;

//
int	hideScreen = 0;
// timer
int	tick50 = 0;
int	fRef = 0;
int	curBlink = 0;
// 
static Uint32 delaytrash = 0;
//floppy
static char	*filename[4];

static char emuldir[256];

struct dirent **namelist;
int namecount = 0;
int wantDisk;

static void showDisks(int disk)
{
	char *files[50];
	int i = 0;

	wantDisk = disk;

	hideScreen = 1;
	clearScr();
	drawString(0,0,"Select floppy image:", 0xffff, 0);
	drawString(0,28,"Select", 0xffff, 0);
	drawString(0,29,"Cancel", 0xffff, 0);
	
	namecount = scandir(DATADIR"/Floppy", &namelist, 0, alphasort);
	for (i = 2; i < namecount; i++) {
	    drawString(0, i + 1, namelist[i]->d_name, 0xffff, 0);
	}
}

static void hideDisks()
{
	int i;
	for (i = 0; i < namecount; i++) {
	    free(namelist[i]);
	}
	free(namelist);
	hideScreen = 0;
}

static int insertDisk(int y)
{
	y /= 8;
	
	y -= 1;

	if (y >= namecount) return 0;
	
	if (y < 2) return 0;

	if (filename[wantDisk] == NULL) filename[wantDisk] = new char[128];
	else {
		unloadDiskImage(filename[wantDisk], wantDisk);
	}
	///strcpy(filename[wantDisk], namelist[y]->d_name);
	sprintf(filename[wantDisk], DATADIR"/Floppy/%s", namelist[y]->d_name);
	fprintf(stderr, "Loading image: %s ... ", filename[wantDisk]);
	if (loadDiskImage(filename[wantDisk], wantDisk) < 0) {
		delete filename[wantDisk];
		filename[wantDisk] = NULL;
		fprintf(stderr, "Failed\n");
	} else {
		fprintf(stderr, "Ok\n");
	}
/*
	if (GetOpenFileName(&ofn)) {
		if (filename[disk] == NULL) filename[disk] = new char[MAX_PATH];
		else {
			unloadDiskImage(filename[disk], disk);
		}
		WChar2Char(ofn.lpstrFile, filename[disk]);
		if (loadDiskImage(filename[disk], disk) < 0) {
			delete filename[disk];
			filename[disk] = NULL;
		}
	} else {
		if (filename[disk] != NULL) {
			unloadDiskImage(filename[disk], disk);
			delete filename[disk];
			filename[disk] = NULL;
		}
	}
 */
}

static char *romName[] = {
	"str$08.roz",
	"str$09.roz",
	"str$0a.roz",
	"str$0b.roz",
	"str$0c.roz",
	"str$0d.roz",
	"str$0e.roz",
	"str$0f.roz"
};

static int LoadRom(char *name, int p, mc6800 *pyl)
{
	char ftemp[256];
	char namp[9];
	namp[8] = 0;

	sprintf(ftemp, "%s/Rom/%s", datadir, name);

	gzFile fi = gzopen(ftemp, "rb");
	if (fi) {
	  while ( gzread(fi, pyl->getRomPtr(p), 8192) == 8192 && p < 16) {
	    memcpy(namp, pyl->getRomPtr(p)+2, 8);
	    fprintf(stderr, "%s as page %d\n", namp, p);
	  }
	  gzclose(fi);
	}
	p++;
	return p;
}

int PyldinThread(void *data)
{
	char ftemp[256];
	mc6800 *pyl = new mc6800();

	fprintf(stderr, "Loading main rom... ");
	sprintf(ftemp, "%s/Bios/bios.roz", datadir);
	gzFile fi = gzopen(ftemp, "rb");
	if (fi) {
		byte *m = pyl->getRomPtr(-1); gzread(fi, m, 4096);
		gzclose(fi); fprintf(stderr, "Ok\r\n");
	} else { fprintf(stderr, "Failed!\r\n"); return 1; }

	fprintf(stderr, "Loading font rom... ");
	sprintf(ftemp, "%s/Bios/video.roz", datadir);
	if (loadTextFont(ftemp) == 0) fprintf(stderr, "Ok\r\n");
	else { fprintf(stderr, "Failed!\r\n"); return 1; }

	int j = 8;
	int i;
	for (i = 0; i < 8; i++)
		j = LoadRom(romName[i], j, pyl);

	for (i = 0; i < 4; i++) {
		filename[i] = NULL;
	}

	fprintf(stderr, "Trying load system disk image... ");
	filename[FLOPPY_A] = new char[255];
	sprintf(filename[FLOPPY_A], "%s/Floppy/system.imz", datadir);
	if (loadDiskImage(filename[FLOPPY_A], FLOPPY_A) < 0) {
		delete filename[FLOPPY_A];
		filename[FLOPPY_A] = NULL;
		fprintf(stderr, "failed!\r\n");
	} else fprintf(stderr, "Ok\r\n");

	// sound initialization
	Speaker_Init();

	pyl->reset();

	vkbdEnable = 0;
	redrawVMenu = 1;
	exitRequested = 0;
	IRQrequest = 0;
	hideScreen = 0;

	int counter = 0;		//
	int vcounter = 0;		//
	int scounter = 0;		// syncro counter
	int takt;

	Uint32 clock_old = SDL_GetTicks();
	Uint32 delay = 0;

	do {

		takt = pyl->step();	//

		vcounter += takt;
		scounter += takt;

		if (vcounter >= 20000) {

			tick50 = 0x80;
			curBlink++;
			IRQrequest = 1;

			SDL_Flip( screen );
			if ( ! hideScreen ) refreshScr();

			memcpy( screen->pixels, vscr, 320 * 240 * 2);

			Uint32 clock_new = SDL_GetTicks();
			if (clock_new - clock_old < 20) {
				delay += 50;
			} else if (clock_new - clock_old > 20) {
				if (delay > 0) delay -= 5;
			}

			clock_old = clock_new;

			vcounter = 0;
			Speaker_Clear(pyl->global_takts); //flush sound
		}

		if (resetRequested == 1) {
			pyl->reset();
			resetRequested = 0;
		}

		for (int tempd = delay; tempd > 0; tempd--) {
			for (int j=0; j < 9; j++) {
				delaytrash++;
			}
		}

	} while( exitRequested == 0);	//


	for (i = 0; i < 4; i++) {
		if (filename[i] != NULL) unloadDiskImage(filename[i], i);
		filename[i] = NULL;
	}

	delete pyl;
	Speaker_Finish();
	return 0;
}

int main(int argc, char *argv[])
{
    SDL_Init(SDL_INIT_VIDEO);
    screen=SDL_SetVideoMode(320,240,16,SDL_HWSURFACE|SDL_DOUBLEBUF);
    SDL_WM_SetCaption("PYLDIN Emulator v3.1", "pyldin");
    vscr = (word *) malloc(320*240*2);
    SDL_Thread *thread = SDL_CreateThread(PyldinThread, NULL);
    if (thread == NULL) {
	fprintf(stderr, "Couldn't create thread: %s\n", SDL_GetError());
	exit(1);
    }

    int done = 0;

    while(!done){
	SDL_Event event;

	while(SDL_PollEvent(&event) > 0){
	
	    switch(event.type) {
	    case SDL_QUIT:
		done=1;
		break;
	    case SDL_KEYDOWN: {
		SDLKey sdlkey=event.key.keysym.sym;
		int k=0;
		switch(sdlkey){
		case SDLK_UP:		jkeybDown(0x48); break;
		case SDLK_DOWN:		jkeybDown(0x50); break;
		case SDLK_LEFT:		jkeybDown(0x4b); break;
		case SDLK_RIGHT:	jkeybDown(0x4d); break;
		case SDLK_ESCAPE:	jkeybDown(0x01); break;
		
		case SDLK_F1:		jkeybDown(0x3b); break;
		case SDLK_F2:		jkeybDown(0x3c); break;
		case SDLK_F3:		jkeybDown(0x3d); break;
		case SDLK_F4:		jkeybDown(0x3e); break;
		case SDLK_F5:		jkeybDown(0x3f); break;
		case SDLK_F6:		jkeybDown(0x40); break;
		case SDLK_F7:		jkeybDown(0x41); break;
		case SDLK_F8:		jkeybDown(0x42); break;
		case SDLK_F9:		jkeybDown(0x43); break;
		case SDLK_F10:		jkeybDown(0x44); break;
		case SDLK_F11:		jkeybDown(0x57); break;
		case SDLK_F12:		jkeybDown(0x58); break;
		
		case SDLK_HOME:		jkeybDown(0x47); break;
		case SDLK_END:		jkeybDown(0x4f); break;
		case SDLK_INSERT:	jkeybDown(0x52); break;
		
		case SDLK_1:		jkeybDown(0x02); break;
		case SDLK_2:		jkeybDown(0x03); break;
		case SDLK_3:		jkeybDown(0x04); break;
		case SDLK_4:		jkeybDown(0x05); break;
		case SDLK_5:		jkeybDown(0x06); break;
		case SDLK_6:		jkeybDown(0x07); break;
		case SDLK_7:		jkeybDown(0x08); break;
		case SDLK_8:		jkeybDown(0x09); break;
		case SDLK_9:		jkeybDown(0x0a); break;
		case SDLK_0:		jkeybDown(0x0b); break;
		case SDLK_MINUS:	jkeybDown(0x0c); break;
		case SDLK_EQUALS:	jkeybDown(0x0d); break;
		case SDLK_BACKSLASH:	jkeybDown(0x2b); break;
		case SDLK_BACKSPACE:	jkeybDown(0x0e); break;
		case SDLK_LSUPER:	jkeybDown(0x46); break;

		case SDLK_TAB:		jkeybDown(0x0f); break;
		case SDLK_q:		jkeybDown(0x10); break;
		case SDLK_w:		jkeybDown(0x11); break;
		case SDLK_e:		jkeybDown(0x12); break;
		case SDLK_r:		jkeybDown(0x13); break;
		case SDLK_t:		jkeybDown(0x14); break;
		case SDLK_y:		jkeybDown(0x15); break;
		case SDLK_u:		jkeybDown(0x16); break;
		case SDLK_i:		jkeybDown(0x17); break;
		case SDLK_o:		jkeybDown(0x18); break;
		case SDLK_p:		jkeybDown(0x19); break;
		case SDLK_BACKQUOTE:	jkeybDown(0x29); break;
		case SDLK_RETURN:	jkeybDown(0x1c); break;

		case SDLK_a:		jkeybDown(0x1e); break;
		case SDLK_s:		jkeybDown(0x1f); break;
		case SDLK_d:		jkeybDown(0x20); break;
		case SDLK_f:		jkeybDown(0x21); break;
		case SDLK_g:		jkeybDown(0x22); break;
		case SDLK_h:		jkeybDown(0x23); break;
		case SDLK_j:		jkeybDown(0x24); break;
		case SDLK_k:		jkeybDown(0x25); break;
		case SDLK_l:		jkeybDown(0x26); break;
		case SDLK_SEMICOLON:	jkeybDown(0x27); break;
		case SDLK_QUOTE:	jkeybDown(0x28); break;
		case SDLK_LEFTBRACKET:	jkeybDown(0x1a); break;
		case SDLK_RIGHTBRACKET:	jkeybDown(0x1b); break;

		case SDLK_z:		jkeybDown(0x2c); break;
		case SDLK_x:		jkeybDown(0x2d); break;
		case SDLK_c:		jkeybDown(0x2e); break;
		case SDLK_v:		jkeybDown(0x2f); break;
		case SDLK_b:		jkeybDown(0x30); break;
		case SDLK_n:		jkeybDown(0x31); break;
		case SDLK_m:		jkeybDown(0x32); break;
		case SDLK_COMMA:	jkeybDown(0x33); break;
		case SDLK_PERIOD:	jkeybDown(0x34); break;
		case SDLK_SLASH:	jkeybDown(0x35); break;

		case SDLK_SPACE:	jkeybDown(0x39); break;

		case SDLK_CAPSLOCK:	jkeybDown(0x3a); break;
		
		case SDLK_LCTRL:	flagKey|=1; break;
		case SDLK_LSHIFT:	flagKey|=2; break;
		case SDLK_RCTRL:	flagKey|=1; break;
		case SDLK_RSHIFT:	flagKey|=2; break;

		default:
		    k = (int)sdlkey;
		}
//		key(k, 0);
		}; break;
	    case SDL_KEYUP: {
		SDLKey sdlkey=event.key.keysym.sym;
		int k=0;
		switch(sdlkey){

		case SDLK_LCTRL:	flagKey&=~1; break;
		case SDLK_LSHIFT:	flagKey&=~2; break;
		case SDLK_RCTRL:	flagKey&=~1; break;
		case SDLK_RSHIFT:	flagKey&=~2; break;

		default:
		    jkeybUp();
		}
		}; break;
	    case SDL_MOUSEBUTTONDOWN: {
		int x = event.button.x;
		int y = event.button.y;
		if (hideScreen) {
			if (insertDisk(y)) {
			    hideDisks();
			    redrawVMenu = 1;
			    clearVScr = 1;
			}
		} else {

		//fprintf(stderr, "x=%d, y=%d\n", x, y);

		    if (vkbdEnable) vkeybDown(x, y);
		    if (y > 216) {
			if (x > 5 && x < 21) {
			    //power off
			    done = 1;
			} else if (x > 33 && x < 50 && vkbdEnable == 0) {
			    showDisks(FLOPPY_A);
			} else if (x > 63 && x < 80 && vkbdEnable == 0) {
			    showDisks(FLOPPY_B);
			} else if (x > 274 && x < 300) {
			    vkbdEnable = vkbdEnable?0:1;
			    //if (vkbdEnable == 0) 
			    redrawVMenu = 1;
			    clearVScr = 1;
			}
		    }
		}
		}; break;
	    case SDL_MOUSEBUTTONUP:
		if (vkbdEnable) vkeybUp();
	    default:
		break;
	    }
	}
    }

    exitRequested=1;
    SDL_WaitThread(thread, NULL);

    SDL_Quit();
    return 0;
}



