/*
 * Configuration parameters and routines
 */

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <popt.h>
#include "Configuration.h"
#include "config.h"
#include "utils.h"

// Options
int disctype = -1;
char *model = NULL, *model_args = NULL;

// Lists
#define MAX_ROMS 16
int num_roms = 0;
int romslots[MAX_ROMS];
char *roms[MAX_ROMS];

int num_rams = 0;
int ramslots[MAX_ROMS];

#define MAX_MODULES 16
int num_modules = 0;
char *modules[MAX_MODULES], *modules_args[MAX_MODULES];

int use_sound = 1;
int fullscreen = 0;

int no_dflt_config = 0;

#define MAX_CONFIGS 16
int num_configs = 0;
char *configs[MAX_CONFIGS];

#define MAX_DISCLOADS 16
int num_discloads = 0;
struct discload discloads[MAX_DISCLOADS];

/**** Configuration file processing ****/
void ReadConfigFile (char *fname)
{
	FILE *f;
	
	f = fopen (fname, "r");
	if (!f)
		{ warning ("Unable to open config file `%s'", fname); return; }
	printf ("Process configfile %s\n", fname);
	fclose (f);
}

/*** Process command-line options ***/
int tmp_value;
static void parse_loaddisc (char *str);

static struct poptOption optionsTable[] =
{
	{ "config", 'c', POPT_ARG_STRING, NULL, 'c',
		"Read in a config file.", "<configfile>" },
	{ "no-config", 0, POPT_ARG_NONE, &no_dflt_config, 1,
		"Don't read any default config files.", NULL },
	{ "model", 'm', POPT_ARG_STRING, NULL, 'm',
		"Select a model emulation module to use.", "<model>" },
	{ "model-args", 'a', POPT_ARG_STRING, NULL, 'a',
		"Give arguments to model code. (`-m <model> -a help' for help).",
		"<args>" },
	{ "load-module", 'l', POPT_ARG_STRING, NULL, 'l',
		"Add a loadable emulation module.", "<module>" },
	{ "dont-load-module", 0, POPT_ARG_STRING, NULL, 2,
		"Override a config default to load a module.", "<module>" },
	{ "coproc", '2', POPT_ARG_STRING, NULL, '2',
		"Select a 2nd processor emulation module (`none' to override a "
		"default).", "<2ndproc>" },
	{ "rom", 'r', POPT_ARG_STRING, NULL, 'r',
		"Add a sideways ROM.", "<socket>:<rom>" },
	{ "ram", 'R', POPT_ARG_INT, &tmp_value, 'R',
		"Set a sideways socket as sideways RAM.", "<socket>" },
	{ "disc-8271", '8', POPT_ARG_NONE, NULL, '8',
		"Select 8271 disc emulation.", NULL },
	{ "disc-1770", '7', POPT_ARG_NONE, NULL, '7',
		"Select 1770 disc emulation.", NULL },
	{ "disc-none", 'n', POPT_ARG_NONE, NULL, 'n',
		"Select no disc emulation.", NULL },
	{ "no-sound", 's', POPT_ARG_NONE, &use_sound, 0,
		"Disable sound emulation (for speed or compatibility).", NULL },
	{ "fullscreen", 'f', POPT_ARG_NONE, &fullscreen, 1,
		"Display in full-screen mode.", NULL },
	{ "load-disc", 'd', POPT_ARG_STRING, NULL, 'd',
		"Load a disc image file.", "<drvnum>[W]:<image>[:<spt>]" },
	POPT_AUTOHELP
	{ NULL, 0, 0, NULL, 0, NULL, NULL }
};

void prelimProcessOpt (int argc, char *argv[])
{
	poptContext optCon;
	char c;
	
	optCon = poptGetContext (NULL, argc, argv, optionsTable, 0);
	poptSetOtherOptionHelp (optCon, "[<model>]");
	
	// Handle config-file and help options
	while ((c = poptGetNextOpt (optCon)) >= 0)
	{
		switch (c)
		{
			case 'c':
			// Config file
			if (num_configs == MAX_CONFIGS)
				{ error ("MAX_CONFIGS exceeded"); break; }
			configs[num_configs++] = poptGetOptArg (optCon);
			break;
		}
	}
	poptFreeContext (optCon);
}

static void processOptions (int argc, char *argv[])
{
	char c;
	poptContext optCon;
	int i;
	char *m;
	
	// Read config-files
	if (!no_dflt_config)
	{
		struct stat sb;
		char buf[256], *s;
		
		if (!stat (DEF_CONFIG_GLOBAL, &sb))
			ReadConfigFile (DEF_CONFIG_GLOBAL);
		if ((s = getenv ("HOME")))
		{
			sprintf (buf, "%s/" DEF_CONFIG_HOME, s);
			if (!stat (buf, &sb))
				ReadConfigFile (buf);
		}
	}
	for (i = 0; i < num_configs; i++)
		ReadConfigFile (configs[i]);
	
	// Process other options
	//poptResetContext (optCon);
	optCon = poptGetContext (NULL, argc, argv, optionsTable, 0);
	while ((c = poptGetNextOpt (optCon)) >= 0)
	{
		switch (c)
		{
			case 'm':
			// Select model
			model = poptGetOptArg (optCon);
			break;
			
			case 'a':
			// Give model args
			model_args = poptGetOptArg (optCon);
			break;
			
			case 'l':
			// Load module
			if (num_modules == MAX_MODULES)
				{ error ("MAX_MODULES exceeded"); break; }
			modules[num_modules] = poptGetOptArg (optCon);
			modules_args[num_modules++] = "";
			break;
			
			case 2:
			// dont-load-module
			m = poptGetOptArg (optCon);
			for (i = 0; i < num_modules; i++)
				if (!strcmp (modules[i], m))
					modules[i] = NULL;
			break;
			
			case '2':
			// 2nd proc module
			
			break;
			
			case 'r':
			// Load ROM
			// Process into socket:rom
			if (num_roms == MAX_ROMS)
				{ error ("MAX_ROMS exceeded"); break; }
			m = poptGetOptArg (optCon);
			for (i = 0; m[i] != 0 && m[i] != ':'; i++)
				;
			if (m[i] == 0)
				error ("Must specify <socket>:<rom> for a ROM");
			else
			{
				m[i] = 0;
				romslots[num_roms] = strtoul (m, NULL, 0);
				roms[num_roms++] = m+i+1;
			}
			break;
			
			case 'R':
			// Set sideways-RAM
			if (num_rams == MAX_ROMS)
				{ error ("MAX_ROMS for RAM exceeded"); break; }
			ramslots[num_rams++] = tmp_value;
			break;
			
			case '7':
			disctype = 2;
			break;
			
			case '8':
			disctype = 1;
			break;
			
			case 'n':
			disctype = 0;
			break;
			
			case 'd':
			// Load disc image
			parse_loaddisc (poptGetOptArg (optCon));
			break;
		}
	}
	if (c < -1)
	{
		fprintf (stderr, "%s: %s\n",
			poptBadOption (optCon, POPT_BADOPTION_NOALIAS),
			poptStrerror (c));
		poptPrintUsage (optCon, stderr, 0);
		exit (1);
	}
	
	m = poptGetArg (optCon);
	if (m != NULL) model = m;
}

static void parse_loaddisc (char *str)
{
	int drvabsnum;
	char *fname;
	char *c;
	int spt = 10, ro = 1;
	
	if (num_discloads == MAX_DISCLOADS)
	{
		error ("Too many discload options: maximum %d", num_discloads);
	}
	
	drvabsnum = strtoul (str, &c, 0);
	if (*c == 'w' || *c == 'W')
		ro = 0;
	while (*c && *c != ':')
		c++;
	if (!*c || !*(++c))
	{
		error ("Invalid disc-load specification: '%s'", str);
		return;
	}
	
	fname = c;
	while (*c && *c != ':')
		c++;
	if (*c == ':')
	{
		// SPT
		*c = 0;
		c++;
		spt = strtoul (c, NULL, 0);
	}
	
	discloads[num_discloads].ro = ro; discloads[num_discloads].spt = spt;
	discloads[num_discloads].drv = drvabsnum; discloads[num_discloads++].fname = strdup (fname);
}

/* get setup */
void getEmulSetup (int argc, char *argv[])
{
	// command-line options
	processOptions (argc, argv);
	// defaults
	if (disctype == -1) disctype = 0;
	if (model == NULL) model = "ModelB";
}

/* End of file. */
