/*  Tilem, TI-Linux Emulator
 *  Copyright (C) 2001 Solignac Julien <x1cygnus@xcalc.org>
 *  Portions copyright (C) 2004 Benjamin Moody <benjamin@ecg.mit.edu>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "../../config.h"

#include<sys/types.h>
#include<sys/stat.h>
#include<gtk/gtk.h>
#ifndef __WIN32__
# include<pthread.h>
# include<unistd.h>
#endif
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#ifdef __WIN32__
# include<process.h>
# include<direct.h>
#endif

#ifdef USE_GTK_1_2
#include<gdk_imlib.h>
#endif

#include "main.h"
/* >>> dependencies */
#include "core/Z80.h"
/* dependencies <<< */

#ifdef extlink
#include<ticables.h>
#endif

/* >>> Imported */
#include "tools.h"
#include "symbols.h"
#include "keypad.h"
#include "gui/debug.h"
#include "core/core.h"
#include "gui/screen.h"
#include "core/dep/inter.h"
/* >>> Imported */


/* >>> Global */
struct hardware *hw;

extern struct hardware x7, x2, x3, xp, xs, x4, xz, x5, x6;
struct hwmodel hwmodels[nummodels + 1] = {
	{"TI-73", &x7, "ti73"},
	{"TI-82", &x2, "ti82"},
	{"TI-83", &x3, "ti83"},
	{"TI-83+", &xp, "ti83p"},
	{"TI-83+ SE", &xs, "ti83pse"},
	{"TI-84+", &x4, "ti84p"},
	{"TI-84+ SE", &xz, "ti84pse"},
	{"TI-85", &x5, "ti85"},
	{"TI-86", &x6, "ti86"},
	{"void", NULL, ""}
};

char *romfile=NULL;
char *savfile=NULL;
/* Global <<< */


/* >>> Resources */
static char modelz[nummodels + 1] = {'7', '2', '3', 'p', 's', '4', 'z',
				     '5', '6', '*'};

static char *welcome_msg = 
#ifdef __WIN32__
"You'll need to move your ROM files to the appropriate directories\n"
"within the main TilEm directory.  For example, TI-82 ROM images must\n"
"be placed in the ti82 subdirectory.\n\n";
#else
"You'll need to move your ROM files to the appropriate directories\n"
"within ~/.TilEm/.  For example, TI-82 ROM images must be placed in\n"
"the ti82 subdirectory.\n\n";
#endif

/* Resources <<< */


/* >>> Static */
static void setupconfig(void)
{
	FILE *config;
	char *fname;

	fname = ahome("config.dat");
	if ((config = fopen(fname, "w"))) {
		fprintf(config, magic_token);
		fprintf(config, "# you can modify this file if you're careful\n");

		fprintf(config, "model = *\n");
		fprintf(config, "modulespeed = y\n");
		fprintf(config, "keyboard = y\n");
		fprintf(config, "autosave = y\n");
		fclose(config);
	} else {
		fprintf(stderr, "Error creating my config file ~/.Tilem/config.dat\n");
		free(fname);
		exit(-1);
	}

	free(fname);
}

#ifdef __WIN32__
static void message(const char *s)
{
	MessageBox(NULL, s, "TilEm", 0);
}
#else
#define message(s) fputs(s,stderr);
#endif
/* Static <<< */


int main (int argc, char *argv[])
{
	G_LOCK_EXTERN(running);

	extern byte ctrlspeed, iskeyb, autosave;
	extern struct hardware *hw;
	FILE *config, *test;
	byte readln[100];
	char *p;
	char c, modelid;

	char *fname;
	int i;
	GDir *gdir;

#ifndef __WIN32__
	pthread_t cthread;
#endif

	puts(version);

	g_thread_init(NULL);

#ifndef USE_GTK_1_2
	gdk_threads_init();
#endif

	gtk_init(&argc, &argv);

#ifdef USE_GTK_1_2
	gdk_imlib_init();
#endif

#ifndef MKDIR
# if HAVE_MKDIR
#  if MKDIR_TAKES_ONE_ARG
#   define MKDIR(n, p) mkdir(n)
#  else
#   define MKDIR mkdir
#  endif
# else
#  if HAVE__MKDIR
#   define MKDIR(n, p) _mkdir(n)
#  else
#   define MKDIR(n, p)
#  endif
# endif
#endif

/* >>> First Run */
	fname = ahome("config.dat");
	if (!(config = fopen(fname, "r"))) {
		free(fname);
		puts("Running TilEm for the first time...");
		fname = ahome("");
		MKDIR(fname, S_IRWXU);
		free(fname);
		fname = ahome("data");
		MKDIR(fname, S_IRWXU);
		free(fname);
		fname = ahome("pixmaps");
		MKDIR(fname, S_IRWXU);
		free(fname);
		message(welcome_msg);
		setupconfig();

		fname = ahome("config.dat");
		if (!(config = fopen(fname, "r"))) {
			message("Error opening newly created config file (?)\n");
			exit(-1);
		}
	}
	free(fname);
/* First Run <<< */


/* >>> file format update */
	fgets((char*)readln, 100, config);
	if (strcmp((char*)readln, magic_token)) {
		puts("Running new version of TilEm, you'll have to restart TilEm.");
		fclose(config);
		setupconfig();
		exit(-1);
	}
/* file format update <<< */


/* >>> Read Config */
	ctrlspeed = iskeyb = autosave = 1;
	romfile = savfile = NULL;
	modelid = '*';

	while (fgets((char*)readln, 100, config)) {
		while ((p = strchr(readln, '#')) ||
		       (p = strchr(readln,'\n')) ||
		       (p = strchr(readln,'\r')))
			*p = 0;

		if (sscanf(readln, "model = %c", &c))
			modelid = c;
		else if (sscanf(readln, "modulespeed = %c", &c))
			ctrlspeed = (c == 'y')?1:0;
		else if (sscanf(readln, "keyboard = %c", &c))
			iskeyb = (c == 'y')?1:0;
		else if (sscanf(readln, "autosave = %c", &c))
			autosave = (c == 'y')?1:0;
		else if (sscanf(readln, "romfile = %n%c", &i, &c))
			romfile = strdup(readln+i);
		else if (sscanf(readln, "savfile = %n%c", &i, &c))
			savfile = strdup(readln+i);
		else if (*readln)
			fprintf(stderr,"unknown config option: %s\n",readln);
	}

	fclose(config);

	for (i = 0; i <= nummodels; i++)
		if (modelid == modelz[i]) {
			hw = hwmodels[i].hx;
			i = -1;
			break;
		}

	if (i != -1) {
		message("Unrecognized calculator model.\n");
		setupconfig();
		exit(-1);
	} else if (modelid == '*' || !initmem()) {
		puts("Looking for ROM files...");
		for (i = 0; i < nummodels; i++) {
			snprintf((char*)readln, 100, "x%c.rom", modelz[i]);
			fname = ahome((char*)readln);
			if ((test = fopen(fname, "r"))) {
				fclose(test);
				if (romfile)
					free(romfile);
				if (savfile)
					free(savfile);
				romfile = savfile = NULL;
				hw = hwmodels[i].hx;
				if (initmem()) {
					free(fname);
					i = nummodels+1;
					break;
				}
			}
			free(fname);

			fname = ahome(hwmodels[i].direct);
			MKDIR(fname, S_IRWXU);
			gdir = g_dir_open(fname, 0, NULL);
			while (gdir && (p = next_rom_file(gdir))) {
				if (romfile)
					free(romfile);
				if (savfile)
					free(savfile);
				romfile = savfile = NULL;

				if ((romfile = malloc(strlen(fname)
						      + strlen(p) + 2)) &&
				    (savfile = malloc(strlen(fname)
						      + strlen(p) + 2))) {
					sprintf(romfile, "%s%c%s",
						fname, G_DIR_SEPARATOR, p);
					sprintf(savfile, "%s%c%s",
						fname, G_DIR_SEPARATOR, p);
					strcpy(strrchr(savfile, '.'), ".sav");

					hw = hwmodels[i].hx;
					if (initmem()) {
						i = nummodels+1;
						break;
					}
				}
			}
			free(fname);
			if (gdir)
				g_dir_close(gdir);
		} 
		if (i == nummodels) {
			message("Couldn't find any ROM files.\n");
			exit(-1);
		}
	}
/* Read Config <<< */


	gtk_rc_parse_string("style \"monospaced\" { "
#ifdef USE_GTK_1_2
			    "font = \"-*-courier-medium-r-normal--12-*-*-*-*-*-*-*\""
#else
			    "font_name = \"Courier\""
#endif
			    " } widget \"*monow*\" style \"monospaced\"");

	load_keymaps();

#ifdef USE_GTK_1_2
        fname = ahome("menurc");
	gtk_item_factory_parse_rc(fname);
	free(fname);
#endif

	G_LOCK(running);

#ifdef extlink
	ticables_library_init();
#endif

#ifdef __WIN32__
	_beginthread(&core, 0, NULL);
#else
	pthread_create(&cthread, NULL, &core, (void *) getpid());
#endif

	loadstdsym();
	create_Screen(iskeyb);
	create_debugger();

	G_UNLOCK(running);

	gdk_threads_enter();
	gtk_main();
	gdk_threads_leave();

#ifdef extlink
	ticables_library_exit();
#endif

	cleanmem();

	puts("Thanks for using Tilem");
	return(0);
}
