#include "main.h" //!!!
#include "atari_drive_emulator.h"
#include "log.h"
#include "utils.h"
#include "sd_direct/spi.h"
#include "rom_location.h"
#include "printf.h"
#include "menu.h"

unsigned char freezer_rom_present;
unsigned char sd_present;
unsigned char sel_profile;
#ifndef NO_FLASH
unsigned int romstart;
#endif

void loadosrom()
{
	if (!sd_present) return;
	if (file_size(files[5]) == 0x4000)
	{
		loadromfile(files[5],0x4000, os_addr());
	}
	else if (file_size(files[5]) ==0x2800)
	{
		loadromfile(files[5],0x2800, os_addr()+0x1800);
		memset8(os_addr(),0xff,0x1000);
	}
	else if (file_size(files[5]) ==0x2000)
	{
		loadromfile(files[5],0x2000, basic_addr());
	}
}

#ifdef USB
struct usb_host usb_porta;
#endif
#ifdef USB2
struct usb_host usb_portb;
#endif

void test_ram()
{
	int i;
	unsigned int volatile * addr = DIR_INIT_MEM;
	int k;
	for (k=0;k<DIR_INIT_MEMSIZE/4;++k)
	{
		addr[k] = k&0xffff;
	}
	int ok = 1;
	for (k=0;k<DIR_INIT_MEMSIZE/4;++k)
	{
		unsigned int val = addr[k];
		if (val != (k&0xffff))
		{
			ok = 0;
		}
	}

	int j =0;
	if (ok)
	{
		while(1)
		{
			++j;
			if (j&1)
				*atari_colbk = 0xc8;
			else
				*atari_colbk = 0x00;
		}
	}
	else
	{
		while(1)
		{
			++j;
			if (j&1)
				*atari_colbk = 0x38;
			else
				*atari_colbk = 0x00;
		}
	}
}

int init_sd()
{
	if (SimpleFile_OK == dir_init((void *)DIR_INIT_MEM, DIR_INIT_MEMSIZE))
	{
		//for(;;);
		#ifdef USB
			usb_log_init(files[7]);
		#endif

		//test_ram();

		return 1;
	}
	return 0;
}

/*static const unsigned char BitReverseTable256[] = 
{
	  0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 
	    0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 
	      0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 
	        0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 
		  0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 
		    0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
		      0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 
		        0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
			  0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
			    0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 
			      0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
			        0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
				  0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 
				    0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
				      0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 
				        0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};*/

#ifdef RPD_SUPPORT
int flash_rpd(struct SimpleFile* file)
{
	int len;
	int readlen;
	int loc;
	int p;

	len = file_size(file);
	loc = 0;

	clearscreen();
	debug_pos = 0;
	debug_adjust = 0;
	printf("Flashing core");

	debug_pos = 80;

	printf("DO NOT POWER OFF");

	debug_pos = 160;

	while (len>0)
	{
		int chunk = len;
		int i = 0;
		if (chunk>262144)
		{
			chunk = 262144;
		}
		len = len-chunk;

		enum SimpleFileStatus ok;
		file_seek(file,loc);
		ok = file_read(file, SCRATCH_MEM, chunk, &readlen);
		if (ok != SimpleFile_OK) {
			LOG("cannot read rpd data\n");
			return 0;
		}

		// Byte swap it!
		for (i=0;i!=chunk;++i)
		{
			unsigned char in = ((unsigned char *)SCRATCH_MEM)[i];
			unsigned char res = 0;
			if (in&1)
				res=res|128;
			if (in&2)
				res=res|64;
			if (in&4)
				res=res|32;
			if (in&8)
				res=res|16;
			if (in&16)
				res=res|8;
			if (in&32)
				res=res|4;
			if (in&64)
				res=res|2;
			if (in&128)
				res=res|1;

			((unsigned char *)SCRATCH_MEM)[i] = res;
		}

		// Flash it!
		//printf("Erase    %x %x",loc,chunk);
		printf(".E.");
		eraseFlash(loc,chunk); // Clear at last 256kB
		//printf("Write    ");
		printf(".W.");
		writeFlash(loc,chunk,SCRATCH_MEM);
		//printf("Verify    ");
		printf(".V.");
		readFlash(loc, chunk, CARTRIDGE_MEM);

		for (i=0;i!=chunk;++i)
		{
			unsigned char in = ((unsigned char *)SCRATCH_MEM)[i];
			unsigned char inb = ((unsigned char *)CARTRIDGE_MEM)[i];
			if (in!=inb)
			{
				printf("FAIL:%02x %02x %d ", in, inb, i);
				break;
			}
		}

		loc = loc+chunk;
	}
	printf("Done    ");
	wait_us(1000000);

/*	printf("   VERIFY  ");
	len = file_size(file);
	loc = 0;
	while (len>0)
	{
		int chunk = len;
		int i = 0;
		if (chunk>262144)
		{
			chunk = 262144;
		}
		len = len-chunk;

		enum SimpleFileStatus ok;
		file_seek(file,loc);
		ok = file_read(file, SCRATCH_MEM, chunk, &readlen);
		if (ok != SimpleFile_OK) {
			LOG("cannot read rpd data\n");
			return 0;
		}

		// Byte swap it!
		for (i=0;i!=chunk;++i)
		{
			unsigned char in = ((unsigned char *)SCRATCH_MEM)[i];
			unsigned char res = 0;
			if (in&1)
				res=res|128;
			if (in&2)
				res=res|64;
			if (in&4)
				res=res|32;
			if (in&8)
				res=res|16;
			if (in&16)
				res=res|8;
			if (in&32)
				res=res|4;
			if (in&64)
				res=res|2;
			if (in&128)
				res=res|1;

			((unsigned char *)SCRATCH_MEM)[i] = res;
		}

		// Flash it!
		printf("Verify    %x %x",loc,chunk);
		readFlash(loc, chunk, CARTRIDGE_MEM);

		for (i=0;i!=chunk;++i)
		{
			unsigned char in = ((unsigned char *)SCRATCH_MEM)[i];
			unsigned char inb = ((unsigned char *)CARTRIDGE_MEM)[i];
			if (in!=inb)
			{
				printf("FAIL:%02x %02x %d ", in, inb, i);
				break;
			}
		}

		loc = loc+chunk;
	}

	debug_pos=400;
	printf("HERE");

	//file_seek(file,0);
	//file_read(file, SCRATCH_MEM, 256, &readlen);
	readFlash(0, 256, SCRATCH_MEM);
	for (p=0;p!=256;++p)
	{
		unsigned char in = ((unsigned char *)SCRATCH_MEM)[p];
		printf("%02x",in);
	}
	for (;;);*/
}
#endif

void load_roms(int profile)
{
	struct SimpleDirEntry * entries = dir_entries(ROM_DIR);

	// TODO profile shifts settings, basic rom, os rom address

	//memory map of flash
	//0x200000: settings (32KB!)
	//0x208000: basic rom (32KB)
	//0x210000: os rom (64KB - 4x16KB)
	//0x220000: freezer rom (64KB)
	//0x230000: ?? (64KB)

#ifndef NO_FLASH
	if (profile == 4)
	{
#endif
		if (sd_present)
		{
			if (SimpleFile_OK == file_open_name_in_dir(entries, "ataribas.rom", files[5]))
			{
				loadosrom();
			}
			if (SimpleFile_OK == file_open_name_in_dir(entries, "atarixl.rom", files[5]))
			{
				loadosrom();
			}
			if (SimpleFile_OK == file_open_name_in_dir(entries, "freezer.rom", files[6]))
			{
				enum SimpleFileStatus ok;
				int len;
				ok = file_read(files[6], FREEZER_ROM_MEM, 0x10000, &len);
				if (ok == SimpleFile_OK && len == 0x10000) {
					LOG("freezer rom loaded\n");
					freezer_rom_present = 1;
				} else {
					LOG("loading freezer rom failed\n");
					freezer_rom_present = 0;
				}
			}
		}
#ifndef NO_FLASH
	}
	else
	{
		readFlash(romstart + 0x08000 + (profile<<13),0x2000,basic_addr());
		readFlash(romstart + 0x10000 + (profile<<14),0x4000,os_addr());
		readFlash(romstart + 0x20000,0x10000,FREEZER_ROM_MEM);
		freezer_rom_present = 1;
	}
#endif

	set_freezer_enable(freezer_rom_present);
}

void mainmenu()
{
	*atari_colbk = 0xb8;
#ifdef USB
	usb_init(&usb_porta,0);
#endif
#ifdef USB2
	usb_init(&usb_portb,1);
#endif
	*atari_colbk = 0x38;
	freezer_rom_present = 0;

	sd_present = !get_sd_detect();
	if (sd_present)
	{
		if (init_sd())
		{
			*atari_colbk = 0x18;
		}
		else
		{
			*atari_colbk = 0x0f;
			sd_present = 0;
			//for(;;);
			//printf("DIR init failed\n");
		}
	}

#ifndef NO_FLASH
	// Find rom settings location
	init_romstart();
#endif

	// default to flash
	load_roms(0);
	load_settings(0);

	// override if present on sd (do we really want this?)
	load_roms(4);
	load_settings(4);

	sel_profile = 1;

	init_drive_emulator();
	reboot(1);
	run_drive_emulator();
}

static char const * ramXL[] = 
{
	"64K",
	"128K",
	"320K(Compy)",
	"320K(Rambo)",
	"576K(Compy)",
	"576K(Rambo)",
	"1MB",
	"4MB"
};

static char const * ram800[] = 
{
	"8K",
	"16K",
	"32K",
	"48K",
	"52K"
	//TODO
};

static char const * key_types[] = 
{
	"ISO",
	"ANSI"
};

static char const * systemname[] = 
{
	"XL/XE",
	"400/800"
};

void menuPrintDrive(void * menuData, void * itemData)
{
	int i = (int)itemData;

	char buffer[20];
	describe_disk(i,&buffer[0]);
	printf("Drive %d:%s %s", i+1, file_name(files[i]), &buffer[0]);
}

void menuPrintCart(void * menuData, void * itemData)
{
	printf("Cart: %s", get_cart_select() ? file_name(files[4]) : "NONE");
}

void menuDrive(void * menuData, struct joystick_status * joy, int drive)
{
	if (!joy || joy->x_>0)
	{
		// Choose new disk
		filter = filter_disks;
		file_selector(files[drive]);
		set_drive_status(drive,files[drive]);
	}
	else if(joy->x_<0)
	{
		// Remove disk
		file_init(files[drive]);
		set_drive_status(drive,0);
	}
	else if (joy->fire_)
	{
		{
			// Swap files
			struct SimpleFile * temp = files[drive];
			files[drive] = files[0];
			files[0] = temp;
		}

		{
			// Swap disks
			struct SimpleFile * temp = get_drive_status(drive);
			set_drive_status(drive, get_drive_status(0));
			set_drive_status(0,temp);
		}
	}
}

int menuCart(void * menuData, struct joystick_status * joy)
{
	if (joy->x_>0) {
		fil_type = fil_type_car;
		filter = filter_specified;
		file_selector(files[4]);
		unsigned char mode = load_car(files[4]);
		set_cart_select(mode);
		if (mode) {
			return 1; 
		}
	}
	else if (joy->x_<0) {
		file_init(files[4]);
		set_cart_select(0);
	}
	return 0;
}

void menuDevicesHotkeys(void * menuData, unsigned char keyPressed)
{
	switch (keyPressed)
	{
	case '1':
	case '2':
	case '3':
	case '4':
		menuDrive(0,0,keyPressed-'1'); //TODO
		break;
	case 'C':
		menuCart(0,0); //TODO
		break;
#ifdef DEBUG_SUPPORT		
	case 'D':
		debug_menu();
		break;
#endif
	}
}

#ifdef USBSETTINGS
void menuRotateUSB(void * menuData, struct joystick_status * joy)
{
	rotate_usb_sticks();
}

void menuPrintUsb(void * menuData, void * itemData)
{
	usb_devices(debug_pos);
}
#endif

#ifdef DEBUG_SUPPORT
struct EditNumberState
{
	unsigned char col;
	unsigned char mask;
	unsigned char defaultShift;
};

struct DebugMenuData
{
	struct EditNumberState state[2];
};

void initDebugMenuData(struct DebugMenuData * menuData2)
{
	menuData2->state[0].col = 0;
	menuData2->state[0].mask = 0x3;
	menuData2->state[0].defaultShift = 12;
	menuData2->state[1].col = 0;
	menuData2->state[1].mask = 0x1;
	menuData2->state[1].defaultShift = 4;
}

void menuDisplayEditNumber(unsigned int num, struct EditNumberState * state)
{
	int shift = state->defaultShift;
	int i=0;
	int adj = debug_adjust;

	printf("0x");
	while(shift>=0)
	{
		int val = num;
		val = (val>> shift)&0xf;
		
		if (state->col == i)
			debug_adjust = adj^128;
		else
			debug_adjust = adj;
		printf("%1x",val);
		shift = shift-4;
		i=i+1;
	}

	debug_adjust = adj;
}

void menuPrintDebugAddress(void * menuData, void * itemData)
{
	printf("Addr:");
	struct DebugMenuData * menuData2 = (struct DebugMenuData *)(menuData);
	menuDisplayEditNumber(get_debug_addr(),&menuData2->state[0]);
}
void menuPrintDebugData(void * menuData, void * itemData)
{
	printf("Data:");
	struct DebugMenuData * menuData2 = (struct DebugMenuData *)(menuData);
	menuDisplayEditNumber(get_debug_data(),&menuData2->state[1]);
}
void menuPrintDebugMode(void * menuData, void * itemData)
{
	printf("Mode:");
	if (get_debug_read_mode())
		printf("Read ");
	if (get_debug_write_mode())
		printf("Write ");
	if (get_debug_data_match())
		printf("Match ");
}

bool hexDigitToNumber(unsigned char digit, int *val)
{
	if (digit>='0' && digit<='9')
	{
		*val = digit-'0';
		return true;
	}
	else if (digit>='A' && digit<='F')
	{
		*val = 10 + digit-'A';
		return true;
	}
	return false;
}

bool menuEditNumber(struct EditNumberState * state, struct joystick_status * joy, unsigned int * data)
{
	unsigned int val = 0;
	unsigned int mask = 0;
	int i;
	int shift = state->defaultShift;
	bool res = false;
	if (hexDigitToNumber(joy->keyPressed_,&val))
	{
		//key pressed, store the number in the current location
		for (i=0;i!=state->col;++i)
			shift = shift-4;

		mask = 0xf;
		val = val<<shift;
		mask = mask<<shift;

		*data = ((*data)&~mask) | val;

		state->col = state->col+1;
		res = true;
	}
	else if (joy->keyPressed_==-1)
	{
		// delete pressed, move back one place
		state->col = state->col-1;
	}

	state->col = state->col & state->mask; // sanitize col

	return res;
}

void menuDebugAddress(void * menuData, struct joystick_status * joy, int j)
{
	int i;
	struct DebugMenuData * menuData2 = (struct DebugMenuData *)(menuData);
	
	unsigned int addr = get_debug_addr();
	if (menuEditNumber(&menuData2->state[j],joy,&addr))
		set_debug_addr(addr);
}
void menuDebugData(void * menuData, struct joystick_status * joy, int j)
{
	int i;
	struct DebugMenuData * menuData2 = (struct DebugMenuData *)(menuData);

	unsigned int data = get_debug_data();

	if (menuEditNumber(&menuData2->state[j],joy,&data))
		set_debug_data(data);
}
void menuDebugHotkeys(void * menuData, unsigned char keyPressed)
{
	switch (keyPressed)
	{
	case 'R':
		set_debug_read_mode(!get_debug_read_mode());
		break;
	case 'W':
		set_debug_write_mode(!get_debug_write_mode());
		break;
	case 'M':
		set_debug_data_match(!get_debug_data_match());
		break;
	}
}

int debug_menu()
{
	struct MenuEntry entries[] = 
	{
		{&menuPrintDebugAddress,0,&menuDebugAddress,MENU_FLAG_KEYPRESS},
		{&menuPrintDebugData,1,&menuDebugData,MENU_FLAG_KEYPRESS},
		{&menuPrintDebugMode,0,0,MENU_FLAG_KEYPRESS},
		{0,0,0,0}, //blank line
		{0,"Exit",0,MENU_FLAG_EXIT},
		{0,0,0,MENU_FLAG_FINAL} //blank line
	};

	struct DebugMenuData menuData;
	initDebugMenuData(&menuData);
	return display_menu("Debug",&entries[0], &menuDebugHotkeys, &menuData);
}
#endif

int devices_menu()
{
	struct MenuEntry entries[] = 
	{
		{&menuPrintDrive,0,&menuDrive,MENU_FLAG_MOVE|MENU_FLAG_FIRE|MENU_FLAG_SD},
		{&menuPrintDrive,1,&menuDrive,MENU_FLAG_MOVE|MENU_FLAG_FIRE|MENU_FLAG_SD},
		{&menuPrintDrive,2,&menuDrive,MENU_FLAG_MOVE|MENU_FLAG_FIRE|MENU_FLAG_SD},
		{&menuPrintDrive,3,&menuDrive,MENU_FLAG_MOVE|MENU_FLAG_FIRE|MENU_FLAG_SD},
		{&menuPrintCart,0,&menuCart,MENU_FLAG_MOVE|MENU_FLAG_SD|MENU_FLAG_MAYEXIT},
#ifdef USBSETTINGS
		{0,"Rotate USB joysticks",&menuRotateUSB,MENU_FLAG_FIRE}, 
#endif
		{0,0,0,0}, //blank line
#ifdef DEBUG_SUPPORT
		{0,"Debug",&debug_menu,MENU_FLAG_FIRE},
		{0,0,0,0}, //blank line
#endif
		{0,"Exit",0,MENU_FLAG_EXIT},
		{0,0,0,0}, //blank line
#ifdef USBSETTINGS
		{&menuPrintUsb,0,0,MENU_FLAG_FINAL}
#else
		{0,0,0,MENU_FLAG_FINAL} //blank line
#endif
	};

	return display_menu("Devices",&entries[0], &menuDevicesHotkeys, 0);
}

char const * const * ram;
int max_ram_select;
void set_system()
{
	if (get_atari800mode() == 1)
	{
		ram = ram800;
		max_ram_select = MAX_RAM_SELECT_800;
	}
	else
	{
		ram = ramXL;
		max_ram_select = MAX_RAM_SELECT_XL;
	}
}

struct MenuData
{
	int video_mode;
	int tv;
	int scanlines;
	int csync;
#ifdef PLL_SUPPORT
	int resolution;
	int scaler;
#endif

#ifndef NO_FLASH
	int flashid1;
	int flashid2;
	int sectorSize;
#endif
};

void updateMenuDataVideoMode(struct MenuData * menuData2)
{
	menuData2->video_mode = get_video();
	menuData2->tv = get_tv();
	menuData2->scanlines = get_scanlines();
	menuData2->csync = get_csync();
#ifdef PLL_SUPPORT
	menuData2->resolution = get_resolution();
	menuData2->scaler = get_scaler();
#endif
}

void updateMenuDataFlashInfo(struct MenuData * menuData2)
{
#ifndef NO_FLASH
	readFlashId(&menuData2->flashid1,&menuData2->flashid2);
	menuData2->sectorSize = flashSectorSize();
#endif
}

void menuPrintProfile(void * menuData, void * itemData)
{
	printf("Profile:%d",sel_profile);
}


void menuProfileLoad(void * menuData)
{
	load_roms(sel_profile-1);
	load_settings(sel_profile-1);

	struct MenuData * menuData2 = (struct MenuData *)menuData;
	updateMenuDataVideoMode(menuData2);

	set_system();
}

void menuProfile(void * menuData, struct joystick_status * joy)
{
	sel_profile += joy->x_;
	if (sel_profile > 4)
		sel_profile = 4;
	if (sel_profile < 1)
		sel_profile = 1;

	if (joy->fire_)
	{
		menuProfileLoad(menuData);
	}
}

void menuPrintCpu(void * menuData, void * itemData)
{
	printf("CPU:%dx%s", get_turbo_6502(), get_turbo_6502_vblank_only() ? " VB only" : "");
}

void menuCpu(void * menuData, struct joystick_status * joy)
{
	int turbo = get_turbo_6502();
	if (joy->fire_) set_turbo_6502_vblank_only(!get_turbo_6502_vblank_only());
	if (joy->x_==1) turbo<<=1;
	if (joy->x_==-1) turbo>>=1;
	if (turbo>32) turbo = 32;
	if (turbo<1) turbo = 1;
	set_turbo_6502(turbo);
}

void menuPrintDriveTurbo(void * menuData, void * itemData)
{
	printf("Drive Turbo:%s", get_turbo_drive_str());
}

void menuDriveTurbo(void * menuData, struct joystick_status * joy)
{
	int turbo = get_turbo_drive();
	turbo+=joy->x_;
	if (turbo<0) turbo = 0;
	if (turbo>7) turbo = 7;
	set_turbo_drive(turbo);
}

void menuPrintSystem(void * menuData, void * itemData)
{
	printf("System:%s %s", ram[get_ram_select()], systemname[get_atari800mode()]);
}

void menuSystem(void * menuData, struct joystick_status * joy)
{
	int ram_select = get_ram_select();
	ram_select+=joy->x_;

	if (joy->fire_)
	{
		set_atari800mode(!get_atari800mode());
		set_system();
	}

	if (ram_select<0) ram_select = 0;
	if (ram_select>max_ram_select) ram_select = max_ram_select;
	set_ram_select(ram_select);
}

void menuPrintOS(void * menuData, void * itemData)
{
	printf("ROM:%s", file_name(files[5]));
}

void menuOS(void * menuData, struct joystick_status * joy)
{
	fil_type = fil_type_rom;
	filter = filter_specified;
	file_selector(files[5]);
	loadosrom();
}

void menuPrintKeyboard(void * menuData, void * itemData)
{
	printf("Keyboard:%s", key_types[get_key_type()]);
}

void menuKeyboard(void * menuData, struct joystick_status * joy)
{
	set_key_type(!get_key_type());
}

#ifndef NO_VIDEO_MODE
void menuPrintVideoMode(void * menuData, void * itemData)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;
	printf("Mode:%s", get_video_mode(menuData2->video_mode));
}

void menuVideoMode(void * menuData, struct joystick_status * joy)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;
	menuData2->video_mode = menuData2->video_mode + joy->x_;
	if (menuData2->video_mode > MAX_VIDEO_MODE)
		menuData2->video_mode = MAX_VIDEO_MODE;
	if (menuData2->video_mode < 0)
		menuData2->video_mode = 0;
}
#endif

void menuPrintTVStandard(void * menuData, void * itemData)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;
	printf("TV standard:%s", get_tv_standard(menuData2->tv));
}

void menuTVStandard(void * menuData, struct joystick_status * joy)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;
	menuData2->tv = !menuData2->tv;
}

#ifdef PLL_SUPPORT
void menuPrintScaler(void * menuData, void * itemData)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;
	printf("Scaler:");
	if (menuData2->scaler)
		printf("Polyphasic");
	else
		printf("Area");
}

void menuScaler(void * menuData, struct joystick_status * joy)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;
	menuData2->scaler = !menuData2->scaler;
}

void menuPrintResolution(void * menuData, void * itemData)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;

	readFlash(romstart+0x30000,2048,SCRATCH_MEM);
	uint8_t * addr = SCRATCH_MEM;
	int mode = menuData2->resolution;
	if (menuData2->tv == TV_NTSC)
		mode = mode+4;
	addr = addr + (mode<<8);

	printf("Resolution:%s", addr); /*get_resolution(menuData2->resolution));*/
}

void menuResolution(void * menuData, struct joystick_status * joy)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;
	menuData2->resolution = menuData2->resolution + joy->x_;
	if (menuData2->resolution > 3)
		menuData2->resolution = 3;
	if (menuData2->resolution < 0)
		menuData2->resolution = 0;
}
#endif

void menuApplyVideo(void * menuData, struct joystick_status * joy)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;
	set_video(menuData2->video_mode);
	set_tv(menuData2->tv);
	set_scanlines(menuData2->scanlines);
	set_csync(menuData2->csync);
#ifdef PLL_SUPPORT
	set_resolution(menuData2->resolution);
	set_scaler(menuData2->scaler);
	if (get_video()>=VIDEO_HDMI && get_video()<VIDEO_COMPOSITE)
	{
		int mode = menuData2->resolution;
		if (get_tv()==TV_NTSC)
			mode = mode+4;

		set_scaler_mode(mode);
	}
	else
	{
		if (get_tv()==TV_PAL)
			set_pll(MODE_PAL_ORIG);
		else
			set_pll(MODE_NTSC_ORIG);

	}
#endif
}

#ifndef NO_VIDEO_MODE
void menuPrintScanlines(void * menuData, void * itemData)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;
	printf("Scanlines:%d", menuData2->scanlines);
}

void menuScanlines(void * menuData, struct joystick_status * joy)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;
	menuData2->scanlines = !menuData2->scanlines;
}

void menuPrintCompositeSync(void * menuData, void * itemData)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;
	printf("Composite sync:%d", menuData2->csync);
}

void menuCompositeSync(void * menuData, struct joystick_status * joy)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;
	menuData2->csync = !menuData2->csync;
}
#endif

void menuSettingsHotKeys(void * menuData, unsigned char keyPressed)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;

#ifdef VIDEO_TV_ONLY
	int apply = 1;
	switch(keyPressed)
	{
	case 'P': // PAL
		menuData2->tv = TV_PAL;
		break;
	case 'N': // NTSC
		menuData2->tv = TV_NTSC;
		break;
	case '1':
	case '2':
	case '3':
	case '4':
		sel_profile = keyPressed - '0';

		menuProfileLoad(menuData);
		break;
	default:
		apply = 0;
	}

	if (apply==1)
	{
		menuApplyVideo(menuData,0);
	}
#endif

#ifndef NO_VIDEO_MODE
	int apply = 1;
	switch(keyPressed)
	{
	case 'P': // PAL
		menuData2->tv = TV_PAL;
		break;
	case 'N': // NTSC
		menuData2->tv = TV_NTSC;
		break;

	case 'R': // RGB
		menuData2->video_mode = VIDEO_RGB;
		break;
	case 'A': // scAndouble (S taken for svideo, C taken for composite)
		menuData2->video_mode = VIDEO_SCANDOUBLE;
		break;
	case 'D': // DVI
		menuData2->video_mode = VIDEO_DVI;
		break;
	case 'H': // HDMI
		menuData2->video_mode = VIDEO_HDMI;
		break;
	case 'V': // VGA
		menuData2->video_mode = VIDEO_VGA;
		break;
	case 'S': // Svideo
		menuData2->video_mode = VIDEO_SVIDEO;
		break;
	case 'C': // Composite
		menuData2->video_mode = VIDEO_COMPOSITE;
		break;
	case 'Z': // Composite sync toggle
		menuData2->csync  = !menuData2->csync;
		break;
	case 'X': // Scanlines toggle
		menuData2->scanlines  = !menuData2->scanlines;
		break;
	case '1':
	case '2':
	case '3':
	case '4':
		sel_profile = keyPressed - '0';

		menuProfileLoad(menuData);
		break;
	default:
		apply = 0;
	}

	if (menuData2->video_mode > MAX_VIDEO_MODE)
		menuData2->video_mode = MAX_VIDEO_MODE;
	if (apply==1)
	{
		menuApplyVideo(menuData,0);
	}
#endif
}

#ifndef NO_FLASH
void menuSaveFlash(void * menuData, struct joystick_status * joy)
{
	save_settings(sel_profile-1);
}
#endif

void menuSaveSD(void * menuData, struct joystick_status * joy)
{
	save_settings(4);
}

#ifdef RPD_SUPPORT
void menuProgramRBD(void * menuData, struct joystick_status * joy)
{
	fil_type = fil_type_rpd;
	filter = filter_specified;
	file_selector(files[4]);
	flash_rpd(files[4]);
}
#endif

void menuStatus1(void * menuData, struct joystick_status * joy)
{
#ifndef NO_VID2I2C
	printf("Board:%d %s %s%s%s",*zpu_board,"Date:YYYYMMDD Core:XX",isHDMIConnected() ? "HDMI " : "",isVGAConnected() ? "VGA ":"",sd_present ? "SD ":"");
#else
	printf("Board:%d %s %s",*zpu_board,"Date:YYYYMMDD Core:XX",sd_present ? "SD ":"");
#endif
}

#ifndef NO_FLASH
void menuStatus2(void * menuData, struct joystick_status * joy)
{
	struct MenuData * menuData2 = (struct MenuData *)menuData;
	printf("SPI:%08x/%08x/%d",menuData2->flashid1,menuData2->flashid2,menuData2->sectorSize);
}
#endif

int settings_menu()
{
	struct MenuEntry entries[] = 
	{
		{&menuPrintProfile,0,&menuProfile,MENU_FLAG_MOVE|MENU_FLAG_FIRE},
		{0,0,0,0}, //blank line
		{&menuPrintCpu,0,&menuCpu,MENU_FLAG_MOVE|MENU_FLAG_FIRE},
		{&menuPrintDriveTurbo,0,&menuDriveTurbo,MENU_FLAG_MOVE},
		{&menuPrintSystem,0,&menuSystem,MENU_FLAG_MOVE|MENU_FLAG_FIRE},
		{&menuPrintOS,0,&menuOS,MENU_FLAG_FIRE},
		{&menuPrintKeyboard,0,&menuKeyboard,MENU_FLAG_FIRE},
		{0,0,0,0}, //blank line
#ifndef NO_VIDEO_MODE
		{&menuPrintVideoMode,0,&menuVideoMode,MENU_FLAG_MOVE},
		{&menuPrintTVStandard,0,&menuTVStandard,MENU_FLAG_FIRE},
		{&menuPrintScanlines,0,&menuScanlines,MENU_FLAG_FIRE},
		{&menuPrintCompositeSync,0,&menuCompositeSync,MENU_FLAG_FIRE},
#ifdef PLL_SUPPORT
		{&menuPrintScaler,0,&menuScaler,MENU_FLAG_FIRE},
		{&menuPrintResolution,0,&menuResolution,MENU_FLAG_MOVE},
#endif
		{0,"Apply video",&menuApplyVideo,MENU_FLAG_FIRE},
		{0,0,0,0}, //blank line
#endif
#ifdef VIDEO_TV_ONLY
		{&menuPrintTVStandard,0,&menuTVStandard,MENU_FLAG_FIRE},
		{0,"Apply video",&menuApplyVideo,MENU_FLAG_FIRE},
		{0,0,0,0}, //blank line
#endif
#ifndef NO_FLASH
		{0,"Save Flash",&menuSaveFlash,MENU_FLAG_FIRE},
#endif
		{0,"Save SD",&menuSaveSD,MENU_FLAG_FIRE|MENU_FLAG_SD}, 
#ifdef RPD_SUPPORT
		{0,"Program RBD",&menuProgramRBD,MENU_FLAG_FIRE|MENU_FLAG_SD}, 
#endif
		{0,0,0,0}, //blank line
#ifndef NO_FLASH
		{0,"Exit",0,MENU_FLAG_EXIT},
#else
		{0,"Exit",0,MENU_FLAG_FINAL|MENU_FLAG_EXIT},
#endif
		{0,0,0,0}, //blank line
#ifndef NO_FLASH
		{&menuStatus1,0,0,0},
		{&menuStatus2,0,0,MENU_FLAG_FINAL},
#else
		{&menuStatus1,0,0,MENU_FLAG_FINAL},
#endif
	};

	set_system(); // sets up ram variable!
	struct MenuData menuData;
	updateMenuDataVideoMode(&menuData);
	updateMenuDataFlashInfo(&menuData);

	display_menu("Settings",&entries[0], &menuSettingsHotKeys, &menuData);
	return 0;

/*		case 9:
		case 10:
			{
				if (joy.fire_)
				{
					fil_type = fil_type_mem;
					filter = filter_specified;
					file_selector(files[6]);
					if (row == 9)
					{
						freeze_load(files[6]);
					}
					else if (row == 10)
					{
						freeze_save(files[6]);
					}
				}
			}
			break;*/
}

void update_keys()
{
	#ifdef LINUX_BUILD
		check_keys();
	#endif
	#ifdef USB
		usb_poll(&usb_porta);
	#endif
	#ifdef USB2
		usb_poll(&usb_portb);
	#endif
}

void actions()
{
	int sd_really_present;

	update_keys();

	sd_really_present = !get_sd_detect();
	if (sd_present==0 && sd_really_present==1)
	{
		if (init_sd())
		{
			init_drive_emulator();
		}
		else
		{
			sd_really_present = 0;
		}
	}
	if (sd_present==1 && sd_really_present==0)
	{
		int i;
		init_drive_emulator();
		for (i=0; i!=NUM_FILES; ++i)
		{
			file_init(files[i]);
		}
	}
	sd_present = sd_really_present;


	// Show some activity!
	//*atari_colbk = *atari_random;
	
	// Hot keys
	if (get_hotkey_softboot())
	{
		reboot(0);	
	}
	else if (get_hotkey_coldboot())
	{
		reboot(1);	

		do
		{
			update_keys();
		}
		while (get_hotkey_coldboot());
	}
	else if (get_hotkey_settings())
	{
		set_pause_6502(1);
		set_freezer_enable(0);
		freeze();
		debug_pos = 0;	
		int do_reboot = settings_menu();
		debug_pos = -1;
		restore();
		if (do_reboot)
			reboot(1);
		else {
			set_freezer_enable(freezer_rom_present);
			set_pause_6502(0);
		}
	}
	else if (get_hotkey_fileselect())
	{
/*#ifdef USB
		set_pause_6502(1);
		set_freezer_enable(0);
		freeze();

		debug_pos = 0;	
		printf("Hello USB");
		debug_pos = 80;
		usb_init();
		while (1)
		{
			usb_poll();
			if (debug_pos>1000)
			{
				debug_pos = 80;
			}
		}

		debug_pos = -1;
		restore();
		set_freezer_enable(freezer_rom_present);
		set_pause_6502(0);
#else*/
		set_pause_6502(1);
		set_freezer_enable(0);
		freeze();
		debug_pos = 0;	
		int do_reboot = devices_menu();
		debug_pos = -1;
		restore();
		if (do_reboot)
			reboot(1);
		else {
			set_freezer_enable(freezer_rom_present);
			set_pause_6502(0);
		}
	}
}




