/*
 * Copyright 2003-2009 (C) Raster Software Vigo (Sergio Costas)
 * This file is part of FBZX
 *
 * FBZX is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * FBZX is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <iostream>
#include <SDL2/SDL.h>

#include "z80free/Z80free.h"
#include "cargador.hh"
#include "computer.hh"
#include "emulator.hh"
#include "tape.hh"
#include "menus.hh"
#include "llscreen.hh"
#include "llsound.hh"
#include "keyboard.hh"
#include "microdrive.hh"
#include "spk_ay.hh"
#include "mouse.hh"

// shows the settings menu

void print_copy() {
	llscreen->print_string("(C) 2012 Fabio Olimpieri", -1, -1, 13, 0);
	llscreen->print_string("(C) 2003-2021 Raster Software Vigo", -1, -2, 13, 0);
}

// shows the help menu

void help_menu() {
	unsigned char fin;

	llscreen->clear_screen();

	llscreen->print_string("FBZX (4.8.0)", -1, 1, 15, 0);
	llscreen->print_string("Available keys", -1, 2, 14, 0);
	llscreen->print_string("Shift:Caps Shift        Ctrl:Symbol Shift", -1, 4, 11, 0);
	llscreen->print_string("F1: \001\017this help", 14, 6, 12, 0);
	llscreen->print_string("F2: \001\017manage snapshots", 336, 6, 12, 0);
	llscreen->print_string("F3: \001\017manage TAP/TZX", 14, 8, 12, 0);
	llscreen->print_string("F4: \001\017change settings", 336, 8, 12, 0);
	llscreen->print_string("F5: \001\017stop TAPE", 14, 10, 12, 0);
	llscreen->print_string("F6: \001\017play TAPE", 336, 10, 12, 0);
	llscreen->print_string("F7: \001\017manage MICRODRIVE", 14, 12, 12, 0);
	llscreen->print_string("F8: \001\017tools", 336, 12, 12, 0);
	llscreen->print_string("F9: \001\017toggle fullscreen", 14, 14, 12, 0);
	llscreen->print_string("F10: \001\017reset spectrum", 336, 14, 12, 0);
	llscreen->print_string("F11/O: \001\017volume low", 14, 16, 12, 0);
	llscreen->print_string("F12/P: \001\017volume up", 336, 16, 12, 0);
	llscreen->print_string("Shift/F1: \001\017Make screenshot", 14, 16, 12, 0);
	llscreen->print_string("ESC: \001\017exit emulator", 184, 20, 12, 0);

	print_copy();

	fin = 1;
	do {
		unsigned int key = wait_key();
		switch (key) {
		case SDLK_ESCAPE: // to exit the help
			fin = 0;
			break;

		default:
			if (launch_menu(key)) {
				fin = 0;
			}
			break;
		}
	} while (fin);
	llscreen->clear_screen();
}

int launch_menu(unsigned int key_pressed) {
	int retval = 0;
	switch (key_pressed) {
	case SDLK_F2:
		snapshots_menu(); // manage snapshot files
		retval = 1;
		break;

	case SDLK_F3:
		taps_menu(); // manage TAP files
		retval = 1;
		break;

	case SDLK_F4: // settings
		settings_menu();
		retval = 1;
		break;

	case SDLK_F7:
		microdrive_menu(); // shows the microdrive menu
		retval = 1;
		break;

	case SDLK_F8:
		tools_menu();
		retval = 1;
		break;
	}
	return (retval);
}

void settings_menu() {
	unsigned char fin;
	char          texto[41];

	fin = 1;

	texto[0] = 0;

	do {
		llscreen->clear_screen();

		llscreen->print_string("Current settings", -1, 0, 15, 0);
		switch (ordenador->current_mode) {
		case MODE_48K:
			if (ordenador->issue_3) {
				sprintf(texto, "Mode: \001\01648K issue3");
			} else {
				sprintf(texto, "Mode: \001\01648K issue2");
			}
			break;

		case MODE_128K:
			sprintf(texto, "Mode: \001\016Sinclair 128K");
			break;

		case MODE_P2:
			sprintf(texto, "Mode: \001\016Amstrad +2");
			break;

		case MODE_P3:
			sprintf(texto, "Mode: \001\016Amstrad +2A/+3");
			break;

		case MODE_128K_SPA:
			sprintf(texto, "Mode: \001\016Spanish 128K");
			break;
		}

		llscreen->print_string(texto, -1, 2, 15, 0);

		switch (keyboard->joystick) {
		case 0:
			sprintf(texto, "Joystick emulation: \001\016Cursor");
			break;

		case 1:
			sprintf(texto, "Joystick emulation: \001\016Kempston");
			break;

		case 2:
			sprintf(texto, "Joystick emulation: \001\016Sinclair (1)");
			break;

		case 3:
			sprintf(texto, "Joystick emulation: \001\016Sinclair (2)");
			break;
		}
		llscreen->print_string(texto, -1, 3.2, 15, 0);

		if (spk_ay->ay_emul) {
			sprintf(texto, "AY-3-8912 Emulation: \001\014enabled");
		} else {
			sprintf(texto, "AY-3-8912 Emulation: \001\013disabled");
		}

		llscreen->print_string(texto, -1, 4.4, 15, 0);

		if (microdrive->mdr_active) {
			sprintf(texto, "Interface I Emulation: \001\014enabled");
		} else {
			sprintf(texto, "Interface I Emulation: \001\013disabled");
		}

		llscreen->print_string(texto, -1, 5.6, 15, 0);

		if (ordenador->dblscan) {
			sprintf(texto, "Double scan: \001\014enabled");
		} else {
			sprintf(texto, "Double scan: \001\013disabled");
		}

		llscreen->print_string(texto, -1, 6.8, 15, 0);

		if (ordenador->turbo) {
			sprintf(texto, "TURBO mode: \001\014enabled");
		} else {
			sprintf(texto, "TURBO mode: \001\013disabled");
		}
		llscreen->print_string(texto, -1, 8, 15, 0);

		if (ordenador->bw) {
			llscreen->print_string("TV Set: \001\011B\001\012&\001\014W", -1, 9.2, 15, 0);
		} else {
			llscreen->print_string("TV Set: \001\012C\001\014o\001\015l\001\016o\001\013r", -1, 9.2, 15, 0);
		}

		if (mouse->enabled) {
			sprintf(texto, "Kempston Mouse: \001\014enabled");
		} else {
			sprintf(texto, "Kempston Mouse: \001\013disabled");
		}
		llscreen->print_string(texto, -1, 10.4, 15, 0);

		llscreen->print_string("1: \001\01748K issue2", 30, 15, 12, 0);

		llscreen->print_string("2: \001\01748K issue3", 213, 15, 12, 0);

		llscreen->print_string("3: \001\017Sinclair 128K", 426, 15, 12, 0);

		llscreen->print_string("4: \001\017Amstrad +2", 30, 16.5, 12, 0);

		llscreen->print_string("5: \001\017Amstrad +2A/+3", 213, 16.5, 12, 0);

		llscreen->print_string("6: \001\017Spanish 128K", 426, 16.5, 12, 0);

		llscreen->print_string("7: \001\017Cursor", 30, 18, 12, 0);

		llscreen->print_string("8: \001\017Kempston", 213, 18, 12, 0);

		llscreen->print_string("9: \001\017Sinclair (1)", 426, 18, 12, 0);

		llscreen->print_string("0: \001\017Sinclair (2)", 30, 19.5, 12, 0);

		llscreen->print_string("I: \001\017Interface I", 213, 19.5, 12, 0);

		llscreen->print_string("A: \001\017AY emulation", 426, 19.5, 12, 0);

		llscreen->print_string("T: \001\017TURBO mode", 30, 21, 12, 0);

		llscreen->print_string("D: \001\017Double Scan", 213, 21, 12, 0);

		llscreen->print_string("V: \001\017TV Set mode", 426, 21, 12, 0);

		llscreen->print_string("K: \001\017Kempston Mouse", 30, 22.5, 12, 0);

		llscreen->print_string("ESC: \001\017return to emulator", -1, 24, 12, 0);

		print_copy();

		switch (wait_key()) {
		case SDLK_ESCAPE:
		case SDLK_RETURN:
			fin = 0;
			break;

		case SDLK_1:
			ordenador->issue_3      = false;
			ordenador->current_mode = MODE_48K;
			spk_ay->ay_emul         = 0;
			ResetComputer();
			break;

		case SDLK_2:
			ordenador->issue_3      = true;
			ordenador->current_mode = MODE_48K;
			spk_ay->ay_emul         = 0;
			ResetComputer();
			break;

		case SDLK_3:
			ordenador->issue_3      = true;
			ordenador->current_mode = MODE_128K;
			spk_ay->ay_emul         = 1;
			ResetComputer();
			break;

		case SDLK_4:
			ordenador->issue_3      = true;
			ordenador->current_mode = MODE_P2;
			spk_ay->ay_emul         = 1;
			ResetComputer();
			break;

		case SDLK_5:
			ordenador->issue_3      = true;
			ordenador->current_mode = MODE_P3;
			spk_ay->ay_emul         = 1;
			microdrive->mdr_active  = 0;
			ResetComputer();
			break;

		case SDLK_6:
			ordenador->issue_3      = true;
			ordenador->current_mode = MODE_128K_SPA;
			spk_ay->ay_emul         = 1;
			ResetComputer();
			break;

		case SDLK_7:
			keyboard->joystick = JOYSTICK_CURSOR;
			break;

		case SDLK_8:
			keyboard->joystick = JOYSTICK_KEMPSTON;
			mouse->enabled     = false; // Kempston joystick and Kempston mouse are incompatible
			break;

		case SDLK_9:
			keyboard->joystick = JOYSTICK_SINCLAIR1;
			break;

		case SDLK_0:
			keyboard->joystick = JOYSTICK_SINCLAIR2;
			break;

		case SDLK_i:
			if (ordenador->current_mode != MODE_P3) {
				microdrive->mdr_active = 1 - microdrive->mdr_active;
				ResetComputer();
			}
			break;

		case SDLK_d:
			ordenador->dblscan = !ordenador->dblscan;
			break;

		case SDLK_a:
			spk_ay->ay_emul = 1 - spk_ay->ay_emul;
			break;

		case SDLK_v:
			ordenador->bw = !ordenador->bw;
			llscreen->set_paletes(ordenador->bw);
			break;

		case SDLK_t:
			if (ordenador->turbo) {
				ordenador->turbo = false;
			} else {
				ordenador->turbo = true;
			}
			llsound->set_speed(ordenador->turbo);
			break;

		case SDLK_k:
			if (mouse->enabled) {
				mouse->enabled = false;
			} else {
				mouse->enabled = true;
				if (keyboard->joystick == JOYSTICK_KEMPSTON) {
					keyboard->joystick = JOYSTICK_CURSOR; // Kempston joystick and Kempston mouse are incompatible
				}
			}
		}
	} while (fin);

	llscreen->clear_screen();

	if ((ordenador->turbo_play) && (!OOTape->get_pause())) {
		llsound->set_speed(true);
	} else {
		llsound->set_speed(ordenador->turbo);
	}
}

// shows the POKE menu

void do_poke() {
	char string[80];
	int  retorno, address, old_value, new_value;

	llscreen->clear_screen();

	while (1) {
		llscreen->print_string("Type address to POKE", -1, 2, 15, 0);
		llscreen->print_string("(ESC to exit)", -1, 3, 12, 0);

		retorno = ask_value(&address, 5, 65535);

		llscreen->clear_screen();

		if (retorno == 2) {
			return;
		}

		if ((address < 16384) && ((ordenador->current_mode != MODE_P3) || (1 != (ordenador->mport2 & 0x01)))) {
			llscreen->print_string("That address is ROM memory.", -1, 1, 15, 0);
			continue;
		}

		switch (address & 0x0C000) {
		case 0x0000:
			old_value = (*(ordenador->block0 + address));
			break;

		case 0x4000:
			old_value = (*(ordenador->block1 + address));
			break;

		case 0x8000:
			old_value = (*(ordenador->block2 + address));
			break;

		case 0xC000:
			old_value = (*(ordenador->block3 + address));
			break;

		default:
			old_value = 0;
			break;
		}

		llscreen->print_string("Type new value to POKE", -1, 2, 15, 0);
		llscreen->print_string("(ESC to cancel)", -1, 3, 12, 0);
		sprintf(string, "Address: %d; old value: %d\n", address, old_value);
		llscreen->print_string(string, -1, 8, 14, 0);

		retorno = ask_value(&new_value, 5, 255);

		llscreen->clear_screen();

		if (retorno == 2) {
			continue;
		}

		switch (address & 0x0C000) {
		case 0x0000:
			(*(ordenador->block0 + address)) = new_value;
			break;

		case 0x4000:
			(*(ordenador->block1 + address)) = new_value;
			break;

		case 0x8000:
			(*(ordenador->block2 + address)) = new_value;
			break;

		case 0xC000:
			(*(ordenador->block3 + address)) = new_value;
			break;

		default:
			break;
		}

		sprintf(string, "Set address %d from %d to %d\n", address, old_value, new_value);
		llscreen->print_string(string, -1, 8, 14, 0);
	}
}

// shows the tools menu

void tools_menu() {
	unsigned char fin;

	fin = 1;
	do {
		llscreen->clear_screen();

		llscreen->print_string("Tools", -1, 1, 15, 0);

		llscreen->print_string("1: \001\017show keyboard template", 14, 3, 12, 0);
		llscreen->print_string("", 62, 50, 15, 0);

		llscreen->print_string("2: \001\017insert POKEs", 14, 5, 12, 0);

		llscreen->print_string("ESC: \001\017return to emulator", 14, 12, 12, 0);

		print_copy();

		switch (wait_key()) {
		case SDLK_ESCAPE: // to exit the help
			fin = 0;
			break;

		case SDLK_1:
			fin = 0;
			keyboard_menu();
			break;

		case SDLK_2:
			fin = 0;
			do_poke();
			break;

		default:
			break;
		}
	} while (fin);

	llscreen->clear_screen();
}

// shows the SNAPSHOTS menu

void snapshots_menu() {
	unsigned char fin;

	llscreen->clear_screen();

	llscreen->print_string("SNAPSHOTS", -1, 1, 15, 0);

	llscreen->print_string("1: \001\017load a Z80/SNA snapshot", 14, 4, 12, 0);

	if (ordenador->current_mode != MODE_P3) { // not in +3 mode
		llscreen->print_string("2: \001\017make a Z80 snapshot", 14, 6, 12, 0);
	} else {
		llscreen->print_string("Can't make snapshots in +3 mode", 14, 6, 15, 0);
	}

	llscreen->print_string("3: \001\017load a SCR snapshot", 14, 8, 12, 0);

	llscreen->print_string("4: \001\017save a SCR snapshot", 14, 10, 12, 0);

	llscreen->print_string("ESC: \001\017return to emulator", -1, 14, 12, 0);

	print_copy();

	fin = 1;
	do {
		switch (wait_key()) {
		case SDLK_ESCAPE: // to exit the help
			fin = 0;
			break;

		case SDLK_1:
			fin = 0;
			load_z80file();
			break;

		case SDLK_2:
			fin = 0;
			if (ordenador->current_mode != MODE_P3) { // not in +3 mode
				save_z80file();
			}
			break;

		case SDLK_3:
			fin = 0;
			load_scrfile();
			break;

		case SDLK_4:
			fin = 0;
			create_scrfile();
			break;

		default:
			break;
		}
	} while (fin);
	llscreen->clear_screen();
}

// shows the TAPs menu

void taps_menu() {
	unsigned char fin;

	fin = 1;
	do {
		llscreen->clear_screen();

		llscreen->print_string("TAP/TZX files", -1, 1, 15, 0);

		llscreen->print_string("1: \001\017select a TAP/TZX file", 14, 4, 12, 0);

		llscreen->print_string("2: \001\017rewind TAP/TZX file", 320, 4, 12, 0);

		llscreen->print_string("3: \001\017fast/normal speed", 14, 6, 12, 0);

		llscreen->print_string("4: \001\017write protection", 320, 6, 12, 0);

		llscreen->print_string("5: \001\017create empty TAP file", 14, 8, 12, 0);

		llscreen->print_string("6: \001\017create empty TZX file", 320, 8, 12, 0);

		llscreen->print_string("7: \001\017Fast mode when playing tape", 14, 10, 12, 0);

		llscreen->print_string("ESC: \001\017return to emulator", -1, 14, 12, 0);

		llscreen->print_string("Current TAP/TZX file is:", -1, 17, 12, 0);
		llscreen->print_string(ordenador->current_tap, -1, 18, 15, 0);

		print_copy();

		if (ordenador->tape_fast_load) {
			llscreen->print_string("Fast load \001\014enabled", 10, -6, 14, 0);
		} else {
			llscreen->print_string("Fast load \001\012disabled", 10, -6, 14, 0);
		}

		if (ordenador->tape_write) {
			llscreen->print_string("Write \001\014enabled", 390, -6, 14, 0);
		} else {
			llscreen->print_string("Write \001\012disabled", 390, -6, 14, 0);
		}

		if (ordenador->turbo_play) {
			llscreen->print_string("Turbo while playing \001\014enabled", 10, -4, 14, 0);
		} else {
			llscreen->print_string("Turbo while playing \001\012disabled", 10, -4, 14, 0);
		}

		switch (wait_key()) {
		case SDLK_ESCAPE: // to exit the help
			fin = 0;
			break;

		case SDLK_1:
			OOTape->set_pause(true);
			select_tapfile();
			OOTape->rewind();
			break;

		case SDLK_2:
			fin = 0;
			OOTape->set_pause(true);
			OOTape->rewind();
			break;

		case SDLK_3:
			OOTape->set_pause(true);
			ordenador->tape_fast_load = ordenador->tape_fast_load ? false : true;
			break;

		case SDLK_4:
			ordenador->tape_write = ordenador->tape_write ? false : true;
			break;

		case SDLK_5:
			create_tapfile(false);
			break;

		case SDLK_6:
			create_tapfile(true);
			break;

		case SDLK_7:
			ordenador->turbo_play = ordenador->turbo_play ? false : true;
			break;

		default:
			break;
		}
	} while (fin);

	llscreen->clear_screen();
}

// shows a menu to allow user to choose a tape file

void select_tapfile() {
	char *filename;

	llscreen->clear_screen();

	filename = select_file("Choose the TAPE file to load", path_taps, FILETYPE_TAP_TZX);

	if (filename == NULL) { // Aborted
		llscreen->clear_screen();
		return;
	}

	ordenador->tape_write  = false; // by default, can't record
	ordenador->current_tap = filename;
	free(filename);

	if (OOTape->load_file(ordenador->current_tap)) {
		llscreen->print_string("Error: Can't load that file", -1, -4, 10, 0);
		llscreen->print_string("Press any key", -1, -3, 10, 0);
		ordenador->current_tap = "";
		wait_key();
	}

	llscreen->clear_screen();
}

void create_tapfile(bool tzx) {
	int         retorno;
	char        nombre2[1024];
	struct stat tmpstat;

	llscreen->clear_screen();

	llscreen->print_string("(up to 30 characters)", -1, 3, 14, 0);

	llscreen->print_string("File will be saved in:", -1, 19, 12, 0);
	llscreen->print_string(path_taps, 0, 20, 12, 0);

	if (tzx) {
		llscreen->print_string("Choose a name for the TZX file", -1, 2, 14, 0);
		retorno = ask_filename(nombre2, 5, "tzx", path_taps);
	} else {
		llscreen->print_string("Choose a name for the TAP file", -1, 2, 14, 0);
		retorno = ask_filename(nombre2, 5, "tap", path_taps);
	}

	llscreen->clear_screen();

	if (retorno == 2) { // abort
		return;
	}

	if (-1 == stat(nombre2, &tmpstat)) {
		// File not exists. Good.
		FILE *tmp = fopen(nombre2, "wb"); // create for read and write
		if (tmp == NULL) {
			retorno = -2;
		} else {
			fwrite("ZXTape!\032\001\024", 10, 1, tmp); // TZX header
			fclose(tmp);
			retorno = 0;
		}
	} else {
		retorno = -1;
	}

	switch (retorno) {
	case 0:
		ordenador->tape_write  = true; // allow to write
		ordenador->current_tap = nombre2;
		OOTape->load_file(nombre2);
		break;

	case -1:
		llscreen->print_string("File already exists", -1, 5, 10, 0);
		ordenador->current_tap = "";
		ordenador->tape_write  = false;
		wait_key();
		break;

	case -2:
		llscreen->print_string("Can't create file", -1, 5, 10, 0);
		ordenador->current_tap = "";
		ordenador->tape_write  = false;
		wait_key();
		break;
	}
	llscreen->clear_screen();
}

// shows the microdrive menu

void microdrive_menu() {
	unsigned char fin;

	fin = 1;
	do {
		llscreen->clear_screen();

		llscreen->print_string("MICRODRIVE files", -1, 1, 15, 0);

		llscreen->print_string("1: \001\017select a MDR file", 14, 3, 12, 0);

		llscreen->print_string("2: \001\017create a MDR file", 14, 5, 12, 0);

		llscreen->print_string("3: \001\017write protection", 14, 7, 12, 0);

		llscreen->print_string("ESC: \001\017return to emulator", 14, 10, 12, 0);

		llscreen->print_string("Current MDR file is:", -1, 13, 12, 0);
		llscreen->print_string(microdrive->mdr_current_mdr, -1, 14, 12, 0);

		print_copy();

		if (!microdrive->get_protected()) {
			llscreen->print_string("Write enabled", -1, -4, 14, 0);
		} else {
			llscreen->print_string("Write disabled", -1, -4, 14, 0);
		}

		switch (wait_key()) {
		case SDLK_ESCAPE: // to exit the help
			fin = 0;
			break;

		case SDLK_1:
			select_mdrfile();
			break;

		case SDLK_2:
			create_mdrfile();
			break;

		case SDLK_3:
			if (microdrive->get_protected()) {
				microdrive->set_protected(false);
			} else {
				microdrive->set_protected(true);
			}
			break;

		default:
			break;
		}
	} while (fin);

	llscreen->clear_screen();
}

// shows a menu to allow user to choose a microdrive file

void select_mdrfile() {
	char *filename;
	int   retorno;

	llscreen->clear_screen();

	filename = select_file("Choose the MICRODRIVE file to load", path_mdrs, FILETYPE_MDR); // MDR files

	if (filename == NULL) { // Aborted
		llscreen->clear_screen();
		return;
	}

	retorno = microdrive->select_mdrfile(filename);

	free(filename);
	llscreen->clear_screen();

	switch (retorno) {
	case 0: // all right
		break;

	case -1:
		llscreen->print_string("Error: Can't load that file", -1, -3, 10, 0);
		llscreen->print_string("Press any key", -1, -2, 10, 0);
		microdrive->mdr_current_mdr[0] = 0;
		wait_key();
		break;
	}

	llscreen->clear_screen();
}

void create_mdrfile() {
	int  retorno;
	char nombre2[1024];

	llscreen->clear_screen();

	llscreen->print_string("Choose a name for the MDR file", -1, 4, 14, 0);
	llscreen->print_string("(up to 30 characters)", -1, 5, 14, 0);

	llscreen->print_string("MDR file will be saved in:", -1, 10, 12, 0);
	llscreen->print_string(path_mdrs, 0, 11, 12, 0);

	retorno = ask_filename(nombre2, 7, "mdr", path_mdrs);

	llscreen->clear_screen();

	if (retorno == 2) { // abort
		return;
	}

	retorno = microdrive->new_mdrfile(nombre2);

	switch (retorno) {
	case 0:
		break;

	case -1:
		llscreen->print_string("File already exists", -1, 9, 10, 0);
		microdrive->mdr_current_mdr[0] = 0;
		wait_key();
		break;

	case -2:
		llscreen->print_string("Can't create file", -1, 9, 10, 0);
		microdrive->mdr_current_mdr[0] = 0;
		wait_key();
		break;
	}
	llscreen->clear_screen();
}

void create_scrfile() {
	int   retorno;
	char  nombre2[1024];
	FILE *fichero;

	llscreen->clear_screen();

	llscreen->print_string("Choose a name for the SCR file", -1, 4, 14, 0);
	llscreen->print_string("(up to 30 characters)", -1, 5, 14, 0);

	llscreen->print_string("SCR file will be saved in:", -1, 10, 12, 0);
	llscreen->print_string(path_mdrs, 0, 11, 12, 0);

	retorno = ask_filename(nombre2, 7, "scr", path_snaps);

	llscreen->clear_screen();

	if (retorno == 2) { // abort
		return;
	}

	fichero = fopen(nombre2, "r"); // test if it exists
	if (fichero == NULL) {
		retorno = 0;
	} else {
		fclose(fichero);
		retorno = -1;
	}

	if (!retorno) {
		fichero = fopen(nombre2, "wb"); // create for write
		if (fichero == NULL) {
			retorno = -2;
		} else {
			fwrite(ordenador->block1 + 0x04000, 6912, 1, fichero); // save screen
			if (screen->ulaplus) {
				for (int c = 0; c < 64; c++) {
					uint8_t value;
					value = llscreen->get_palete_entry(c);
					fwrite(&value, 1, 1, fichero); // save ULAPlus palete
				}
			}
			fclose(fichero);
			retorno = 0;
		}
	}

	switch (retorno) {
	case -1:
		llscreen->print_string("File already exists", -1, 9, 10, 0);
		wait_key();
		break;

	case -2:
		llscreen->print_string("Can't create file", -1, 9, 10, 0);
		wait_key();
		break;

	default:
		break;
	}
	llscreen->clear_screen();
}

int ask_filename(char *nombre_final, int y_coord, string extension, char *path) {
	int  longitud, retorno;
	char nombre[MAX_FILE_LENGTH + 3], nombre2[MAX_FILE_LENGTH + 12];

	nombre[0] = CURSOR_ELEMENT;
	nombre[1] = 0;
	longitud  = 0;
	retorno   = 0;

	do {
		sprintf(nombre2, " %s.%s ", nombre, extension.c_str());
		llscreen->print_string(nombre2, -1, y_coord, 15, 0);
		switch (wait_key()) {
		case SDLK_BACKSPACE:
			if (longitud > 0) {
				nombre[longitud] = 0;
				longitud--;
				nombre[longitud] = CURSOR_ELEMENT;
			}
			break;

		case SDLK_ESCAPE:
			retorno = 2;
			break;

		case SDLK_RETURN:
			retorno = 1;
			break;

		case SDLK_a:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'a';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_b:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'b';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_c:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'c';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_d:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'd';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_e:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'e';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_f:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'f';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_g:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'g';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_h:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'h';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_i:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'i';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_j:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'j';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_k:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'k';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_l:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'l';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_m:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'm';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_n:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'n';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_o:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'o';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_p:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'p';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_q:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'q';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_r:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'r';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_s:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 's';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_t:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 't';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_u:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'u';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_v:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'v';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_w:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'w';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_x:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'x';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_y:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'y';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_z:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = 'z';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_0:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = '0';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_1:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = '1';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_2:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = '2';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_3:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = '3';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_4:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = '4';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_5:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = '5';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_6:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = '6';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_7:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = '7';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_8:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = '8';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_9:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = '9';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;

		case SDLK_MINUS:
			if (longitud < MAX_FILE_LENGTH) {
				nombre[longitud++]   = '-';
				nombre[longitud]     = CURSOR_ELEMENT;
				nombre[longitud + 1] = 0;
			}
			break;
		}
	} while (!retorno);

	nombre[longitud] = 0; // erase cursor

	longitud = strlen(path);
	if ((path[longitud - 1] != '/') && (longitud > 1)) {
		sprintf(nombre_final, "%s/%s.%s", path, nombre, extension.c_str()); // name
	} else {
		sprintf(nombre_final, "%s%s.%s", path, nombre, extension.c_str());
	}

	return (retorno);
}

int ask_value(int *final_value, int y_coord, int max_value) {
	char nombre2[50];

	int value, tmp, retorno;

	retorno = 0;
	value   = 0;
	do {
		sprintf(nombre2, " %d%c ", value, CURSOR_ELEMENT);
		llscreen->print_string(nombre2, -1, y_coord, 15, 0);
		switch (wait_key()) {
		case SDLK_BACKSPACE:
			value /= 10;
			break;

		case SDLK_ESCAPE:
			retorno = 2;
			break;

		case SDLK_RETURN:
			retorno = 1;
			break;

		case SDLK_0:
			tmp = value * 10;
			if (tmp <= max_value) {
				value = tmp;
			}
			break;

		case SDLK_1:
			tmp = 1 + value * 10;
			if (tmp <= max_value) {
				value = tmp;
			}
			break;

		case SDLK_2:
			tmp = 2 + value * 10;
			if (tmp <= max_value) {
				value = tmp;
			}
			break;

		case SDLK_3:
			tmp = 3 + value * 10;
			if (tmp <= max_value) {
				value = tmp;
			}
			break;

		case SDLK_4:
			tmp = 4 + value * 10;
			if (tmp <= max_value) {
				value = tmp;
			}
			break;

		case SDLK_5:
			tmp = 5 + value * 10;
			if (tmp <= max_value) {
				value = tmp;
			}
			break;

		case SDLK_6:
			tmp = 6 + value * 10;
			if (tmp <= max_value) {
				value = tmp;
			}
			break;

		case SDLK_7:
			tmp = 7 + value * 10;
			if (tmp <= max_value) {
				value = tmp;
			}
			break;

		case SDLK_8:
			tmp = 8 + value * 10;
			if (tmp <= max_value) {
				value = tmp;
			}
			break;

		case SDLK_9:
			tmp = 9 + value * 10;
			if (tmp <= max_value) {
				value = tmp;
			}
			break;
		}
	} while (!retorno);

	*final_value = value;

	return (retorno);
}

// shows a menu to allow user to save a snapshot file

void save_z80file() {
	int  retorno;
	char nombre2[1024];

	llscreen->clear_screen();

	llscreen->print_string("Choose a name for the Z80 snapshot", -1, 4, 14, 0);
	llscreen->print_string("(up to 30 characters)", -1, 5, 14, 0);

	llscreen->print_string("Snapshot will be saved in:", -1, 11, 12, 0);
	llscreen->print_string(path_snaps, 0, 11, 12, 0);

	retorno = ask_filename(nombre2, 7, "z80", path_snaps);

	llscreen->clear_screen();

	if (retorno == 2) { // abort
		return;
	}

	retorno = save_z80(nombre2);
	switch (retorno) {
	case 0:
		break;

	case -1:
		llscreen->print_string("File already exists", -1, 9, 10, 0);
		wait_key();
		break;

	case -2:
		llscreen->print_string("Can't create file", -1, 9, 10, 0);
		wait_key();
		break;
	}
	llscreen->clear_screen();
}

// shows a menu to allow user to load a snapshot file

void load_z80file() {
	char *filename;
	int   retorno;

	llscreen->clear_screen();

	filename = select_file("Choose the Z80 snapshot file to load", path_snaps, FILETYPE_Z80);

	if (filename == NULL) { // Aborted
		llscreen->clear_screen();
		return;
	}

	retorno = load_z80(filename);
	free(filename);
	llscreen->clear_screen();

	switch (retorno) {
	case 0: // all right
		break;

	case -1:
		llscreen->print_string("Error: Can't load that file", -1, -3, 10, 0);
		llscreen->print_string("Press any key", -1, -2, 10, 0);
		wait_key();
		break;

	case -2:
	case -3:
		llscreen->print_string("Error: unsuported snap file", -1, -3, 10, 0);
		llscreen->print_string("Press any key", -1, -2, 10, 0);
		wait_key();
		break;
	}
	llscreen->clear_screen();
}

void load_scrfile() {
	unsigned char value;
	char *        filename;
	int           retorno, loop;
	FILE *        fichero;
	unsigned char paleta_tmp[64];

	llscreen->clear_screen();

	filename = select_file("Choose the SCR snapshot file to load", path_snaps, FILETYPE_SCR);

	if (filename == NULL) { // Aborted
		llscreen->clear_screen();
		return;
	}

	osd->clear_message();
	fichero = fopen(filename, "rb");
	retorno = 0;
	if (!fichero) {
		retorno = -1;
	} else {
		for (loop = 0; loop < 6912; loop++) {
			if (1 == fread(&value, 1, 1, fichero)) {
				*(ordenador->block1 + 0x04000 + loop) = value;
			} else {
				retorno = -1;
				break;
			}
		}
		if (1 == fread(paleta_tmp, 64, 1, fichero)) {
			for (int c = 0; c < 64; c++) {
				llscreen->set_palete_entry(c, paleta_tmp[c], ordenador->bw);
			}
			screen->ulaplus = true;
		} else {
			screen->ulaplus = false;
		}
		fclose(fichero);
	}

	free(filename);
	llscreen->clear_screen();

	switch (retorno) {
	case 0: // all right
		break;

	default:
		llscreen->print_string("Error: Can't load that file", -1, -3, 10, 0);
		llscreen->print_string("Press any key", -1, -2, 10, 0);
		wait_key();
		break;
	}
	llscreen->clear_screen();
}

/* fills a FICHERO chained list with all the files and directories contained in PATH.
 *   If KIND is 0, it returns only Snapshots, if is 1, it returns only TAPE files, and
 *  if is 2, it returns only MDR files */

class fichero *read_directory(char *cpath, enum LOAD_FILE_TYPES kind) {
	class fichero *listhead, *listend;
	struct dirent *entry;
	DIR *          directory;
	struct stat    estado;
	char           path[2049], fichero[2049], extension[5], found;
	int            bucle, length;

	strcpy(path, cpath);
	if ('/' != path[strlen(path) - 1]) {
		strcat(path, "/"); // add the final / to the path
	}
	listhead         = new class fichero();
	listhead->nombre = "..";
	listhead->tipo   = 2;
	listhead->next   = NULL;
	listhead->prev   = NULL;
	listend          = listhead;

	directory = opendir(path);
	if (directory == NULL) {
		return (listhead); // can't access the directory
	}
	do {
		entry = readdir(directory);
		if ((NULL != entry) && (strcmp(entry->d_name, ".")) && (strcmp(entry->d_name, ".."))) {
			strcpy(fichero, path);
			strcat(fichero, entry->d_name);
			stat(fichero, &estado);
			found  = 0; // by default is not a valid file...
			length = strlen(entry->d_name);
			if (length > 3) {
				extension[4] = 0;
				for (bucle = 0; bucle < 4; bucle++) {
					extension[bucle] = entry->d_name[length - 4 + bucle]; // copy the 4 last chars of the file (the extension)
				}
				switch (kind) {
				case FILETYPE_Z80:
					if ((!strcasecmp(extension, ".z80")) || (!strcasecmp(extension, ".sna"))) {
						found = 1; // is a .z80 or SNA file
					}
					break;

				case FILETYPE_TAP_TZX:
					if ((!strcasecmp(extension, ".tap")) || (!strcasecmp(extension, ".tzx"))) {
						found = 1; // is a .tap file
					}
					break;

				case FILETYPE_MDR:
					if (!strcasecmp(extension, ".mdr")) {
						found = 1; // is a .mdr file
					}
					break;

				case FILETYPE_SCR:
					if (!strcasecmp(extension, ".scr")) {
						found = 1; // is a .mdr file
					}
					break;

				default:
					break;
				}
			} else {
				found = 0;
			}

			if ((found || (S_ISDIR(estado.st_mode))) && ('.' != entry->d_name[0])) { // is a directory. We must add it
				class fichero *new_file = new class fichero ();
				class fichero *floop;
				new_file->nombrepath = fichero;
				new_file->nombre     = entry->d_name;
				if (S_ISDIR(estado.st_mode)) {
					new_file->tipo = 1; // a directory
				} else {
					new_file->tipo = 0; // a file
				}
				for (floop = listhead; floop != NULL; floop = floop->next) {
					if (floop->tipo == 2) { // parent directory
						continue;
					}
					// if found a file, and the new entry is a folder, add it before the file
					if (((floop->tipo == 0) && (new_file->tipo == 1)) || ((floop->tipo == new_file->tipo) && (floop->nombre > new_file->nombre))) {
						new_file->prev = floop->prev;
						new_file->next = floop;
						floop->prev    = new_file;
						if (new_file->prev != NULL) {
							new_file->prev->next = new_file;
						}
						new_file = NULL;
						break;
					}
				}
				if (new_file != NULL) { // hasn't been added; append to the end
					listend->next  = new_file;
					new_file->next = NULL;
					new_file->prev = listend;
					listend        = new_file;
				}
			}
		}
	} while (entry != NULL);
	closedir(directory);
	return (listhead);
}

// deletes a filelist tree, freeing the memory used by it

void delete_filelist(class fichero *filelist) {
	class fichero *fl1, *fl2;

	fl1 = fl2 = filelist;

	while (fl1 != NULL) {
		fl2 = fl1->next;
		delete(fl1);
		fl1 = fl2;
	}
}

/* allows user to choose a file from PATH. If KIND=0, only snapshots. If KIND=1, only
 *   TAPE files */

char *select_file(string title, char *path, enum LOAD_FILE_TYPES kind) {
	class fichero *filelist, *fl2;
	unsigned char  fin, read;
	unsigned int   key, first;
	char *         salida;
	int            bucle, numitems, selected, from, longitud, saved_selected;

	salida    = (char *) malloc(4096);
	salida[0] = 0;
	fin       = 1;
	read      = 1;
	selected  = 0;
	from      = 0;
	numitems  = 0;

	filelist = NULL;

	do {
		if (read) {
			filelist = read_directory(path, kind);
			read     = 0;

			fl2      = filelist;
			numitems = 0;
			while (fl2 != NULL) { // counts the number of items
				fl2 = fl2->next;
				numitems++;
			}
			selected = 0;
			from     = 0;
		}

		llscreen->clear_screen();
		llscreen->print_string(title, -1, 2, 15, 0);
		print_files(filelist, from, selected);

		key = wait_key();
		// Jump to the first item with the starting letters or numbers (this browsing directories with lots of files).
		if (((key >= SDLK_a) && (key <= SDLK_z)) || ((key >= SDLK_0) && (key <= SDLK_9))) {
			saved_selected = selected;
			selected       = (selected + 1) % numitems;
			key           -= SDLK_a;
			key           += 0x61;
			fl2            = filelist;
			// Firstly try from selected onward.
			for (bucle = 0; bucle < selected; bucle += 1) {
				fl2 = fl2->next;
			}
			while (fl2 != NULL) {
				first = fl2->nombre[0];
				if (first == key || (key > 0x60 && first == key - 0x20)) {
					break;
				}
				fl2       = fl2->next;
				selected += 1;
			}
			if (fl2 == NULL) {
				// Secondly try the files until selected.
				selected = 0;
				fl2      = filelist;
				while (fl2 != NULL) {
					first = fl2->nombre[0];
					if (first == key || (key > 0x60 && first == key - 0x20)) {
						break;
					}
					fl2       = fl2->next;
					selected += 1;
				}
			}
			if (fl2 == NULL) {
				// We didn't find any file matching the key; then just restore the selected position.
				selected = saved_selected;
			} else {
				if (selected >= from + 23 || selected < from) {
					from = selected;
				}
			}
			key = -1;
		}

		switch (key) {
		case SDLK_ESCAPE: // to exit the help
			fin = 0;
			delete_filelist(filelist);
			break;

		case SDLK_UP:
			if (selected > 0) {
				selected--;
				if (selected < from) {
					from--;
				}
			}
			break;

		case SDLK_DOWN:
			if (selected < (numitems - 1)) {
				selected++;
				if (selected > (from + 23)) { // 23 is the total of items that can be displayed
					from++;
				}
			}
			break;

		case SDLK_PAGEUP:
			for (bucle = 0; bucle < 15; bucle++) {
				if (selected > 0) {
					selected--;
					if (selected < from) {
						from--;
					}
				}
			}
			break;

		case SDLK_PAGEDOWN:
			for (bucle = 0; bucle < 15; bucle++) {
				if (selected < (numitems - 1)) {
					selected++;
					if (selected > (from + 23)) { // 23 is the total of items that can be displayed
						from++;
					}
				}
			}
			break;

		case SDLK_RETURN:
			fl2 = filelist;
			if (selected != 0) {
				for (bucle = 0; bucle < selected; bucle++) {
					fl2 = fl2->next;
				}
			}
			switch (fl2->tipo) {
			case 0: // select file
				strcpy(salida, fl2->nombrepath.c_str());
				delete_filelist(filelist);
				return (salida); // ends returning the filename

				break;

			case 1:                                    // change directory
				strcpy(path, fl2->nombrepath.c_str()); // new path_taps is namepath
				delete_filelist(filelist);             // frees the memory
				read = 1;                              // and redisplay all the files
				break;

			case 2:                        // upper directory
				read = 1;
				delete_filelist(filelist); // frees the memory
				longitud = strlen(path);
				if (longitud < 2) { // there's no upper directory
					break;
				}
				if ('/' == path[longitud - 1]) { // is the char ended in '/' ?
					path[longitud - 1] = 0; // eliminated
					longitud--;
				}
				while ('/' != path[longitud - 1]) {
					longitud--;
					path[longitud] = 0;
				}
				if (longitud > 2) { // it's not the upper directory
					longitud--;
					path[longitud] = 0; // delete the final '/'
				}
				break;

			default:
				break;
			}
			break;

		default:
			break;
		}
	} while (fin);

	return (NULL);
}

void keyboard_menu() {
	llscreen->paint_picture("fbzx/keymap.bmp");
	print_copy();
	wait_key();
	llscreen->clear_screen();
}

// waits for a keystroke and returns its value

unsigned int wait_key() {
	char         fin;
	unsigned int temporal_io = 0;
	SDL_Event    evento;

	fin = 1;

	do {
		llscreen->do_flip();
		if (!SDL_WaitEvent(&evento)) {
			continue;
		}

		if (evento.type != SDL_KEYUP) {
			continue;
		}

		fin = 0;

		temporal_io = (unsigned int) evento.key.keysym.sym;
	} while (fin);

	return (temporal_io);
}

// shows the files from the number FROM, and marks the file number MARK

void print_files(class fichero *filelist, int from, int mark) {
	class fichero *fl2;
	int            bucle, numitems;
	unsigned int   pos;
	char           ink1, ink2;
	string         namefile;

	fl2      = filelist;
	numitems = 0;

	while (fl2 != NULL) { // counts the number of items
		fl2 = fl2->next;
		numitems++;
	}

	ink1 = ink2 = 0;

	fl2 = filelist;
	pos = 3;
	for (bucle = 0; bucle < numitems; bucle++) {
		if (bucle >= from) {
			namefile = fl2->nombre;
			switch (fl2->tipo) {
			case 0: // file
				ink1 = 15;
				ink2 = 0;
				break;

			case 1: // directory
				ink1 = 12;
				ink2 = 4;
				break;

			case 2: // parent directory
				ink1 = 10;
				ink2 = 2;
				break;
			}
			if (bucle == mark) {
				llscreen->print_string(namefile, 10, pos, ink2, 15);
			} else {
				llscreen->print_string(namefile, 10, pos, ink1, 0);
			}
			pos++;
		}
		if ((pos + 1) > llscreen->lines_in_screen) {
			break; // reached bottom part of the rectangle
		}
		fl2 = fl2->next;
	}
}
