/*  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<gdk/gdkkeysyms.h>
#include<gtk/gtk.h>
#include<stdlib.h>
#include<stdio.h>

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

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


/* >>> Imported */
#include "../core/dep/inter.h"
#include "../tools.h"
#include "commands.h"
#include "changehw.h"
#include "linkset.h"
#include "outils.h"
#include "menus.h"
#include "files.h"
byte *x6_getlcd();
/* Imported <<< */


/* >>> Globals */
byte lcdshow = 1, lcdactive = 1; 
/* Globals <<< */


/* >>> Private */
static void invokeemu(void);
/* Private <<< */


/* >>> Resources */
#define		rHeight		0x40
#define		iHeight		rHeight * 2

#define NGRAYS 64
/* 4 level greyscale
 * min: 000000 max: B5BDBD
 * using (e^(x) - 1) / (e - 1) */
static guchar iris[3 * NGRAYS];
/* = {
	0x00, 0x3F, 0x7E, 0xBD,
	0x00, 0x3F, 0x7E, 0xBD,
	0x00, 0x3C, 0x78, 0xB5
};*/

static GtkItemFactoryEntry screenmenu[] = {
			{"/Load file...", "F12", create_loaddlg, 0, NULL, NULL},
			{"/Debugger...", "F11", invokeemu, 0, NULL, NULL},
			{"/Hardware...", NULL, changehw, 0, NULL, NULL},
#ifdef extlink
			{"/Linking...", NULL, changelink, 0, NULL, NULL},
#endif
			{"/---", NULL, NULL, 0, "<Separator>", NULL},
			{"/Toggle autosave", NULL, toggle_autosave, 0, NULL, NULL},
			{"/Toggle window", NULL, togglescr, 0, NULL, NULL},
			{"/Toggle speed", NULL, toggle_speed, 0, NULL, NULL},
			{"/Reset", NULL, initstat, 0, NULL, NULL},
			{"/Reload state", NULL, revertstat, 0, NULL, NULL},
			{"/---", NULL, NULL, 0, "<Separator>", NULL},
			{"/Quit without saving", "<control>Q", exit_emulator, 0, NULL, NULL},
			{"/Exit and save state", "<alt>X", exit_emulator, 1, NULL, NULL}
};

G_LOCK_DEFINE_STATIC(greylcd);
static guchar *greylcd;		/* 24-bit color image of the LCD (scaled up 2x) */
static byte *savelcd;		/* 8-bit table of LCD "voltage" levels */
static byte rWidth;
static word iWidth;
/* Resources <<< */



/* >>> Static */
static void invokeemu(void)
{
	extern word Z80_Trace;
/*	extern char statmess[40];

	strcpy(statmess, "Invoked by user");*/
	Z80_Trace = 1;
}


void lcfresh(void)
{
	extern byte *lcdbuf;
	/* static int ise = 0;
	   static int nse = 0; */

	unsigned char xln, yln;
	int i;
	guchar *greyptr, *cindex;
	unsigned long t;
	byte *lcdptr;
	FILE *rfile;
	char *fname;

	if ((!savelcd) || (!lcdshow)) return;

/* variables lcdactive & lcdshow are of same thread (core) thus no locking is needed */	
	if (!(lcdactive)) {
		G_LOCK(greylcd);
		fname = ashare("tilem.bin");
		if ((rfile = fopen(fname, "rb"))) {
			if (iWidth != 96) {
				for (i = 0; i < (iWidth * iHeight); i++) {
					greylcd[3*i] = iris[3];
					greylcd[3*i+1] = iris[3+4];
					greylcd[3*i+2] = iris[3+8];
				}
			}

			for (i = 0; i < 64*2; i++)
				fread(greylcd + 3*((iWidth-96*2)/2) + (3*i*iWidth),
				      1, 3 * 96*2, rfile);

			fclose(rfile);
		}
		free(fname);
		G_UNLOCK(greylcd);
		lcdshow = 0;
		return;
	}


	/*
	nse++;
	if (nse == 10 * 3) return;
	nse = 0;
	*/

	lcdptr = savelcd;
	for (t = 0; t < (rWidth / 8) * rHeight; t++) {
		for (i = 0; i < 8; i++) {
			/* if (!((*(lcdbuf + t) << i) & 0x80))
				(*lcdptr)++; */
			*lcdptr = ((15 * ((int)*lcdptr)
				    + ((int)(*(lcdbuf + t) << i) & 0x80) * NGRAYS / 128)
				   / 16);
			lcdptr++;
		}
	}

	/*
	ise++;
	if (ise != 0x03) return;
	ise = 0;
	*/

	G_LOCK(greylcd);

	for (i = 0; i < 3; i++) {
		cindex = iris + NGRAYS * i;
		lcdptr = savelcd;
		greyptr = greylcd + i;
		for (yln = 0; yln < rHeight; yln++) {
			for (xln = 0; xln < rWidth; xln++) {
	
				*(greyptr) = \
					*(greyptr + 3) = \
					*(greyptr + 3 * iWidth) = \
					*(greyptr + 3 * iWidth + 3) = cindex[*lcdptr];
				lcdptr++;
				greyptr += 6;
			}
			greyptr += 3 * 2 * rWidth;
		}
	}

	/*
	lcdptr = savelcd;
	for (t = 0; t < rWidth * rHeight; t++)
		*lcdptr++ = 0;
	*/

	G_UNLOCK(greylcd);
}


static gboolean ifresh(GtkWidget *lcd)
{
	if (!(G_TRYLOCK(greylcd))) return(TRUE);

	gdk_draw_rgb_image(lcd->window, lcd->style->fg_gc[GTK_STATE_NORMAL], 0, 0, iWidth, iHeight, GDK_RGB_DITHER_MAX, greylcd, 3 * iWidth);
	G_UNLOCK(greylcd);
	return(TRUE);
}


static void create_keyb(GtkWidget *kscreen, GtkWidget *drawarea)
{
	extern struct hardware *hw;

	char filename[15];
	GtkWidget *vtrio, *htrio, *mono;
	GtkWidget *calcleft, *calcright, *calctop, *calcbot;

	snprintf(filename, 15, "x%c_left.jpg", hw->model);
	calcleft = load_image(filename);
	gtk_widget_show(calcleft);

	snprintf(filename, 15, "x%c_right.jpg", hw->model);
	calcright = load_image(filename);
	gtk_widget_show(calcright);

	htrio = gtk_hbox_new(FALSE, 0);
		gtk_box_pack_start(GTK_BOX(htrio), calcleft, FALSE, FALSE, 0);
		gtk_box_pack_start(GTK_BOX(htrio), drawarea, FALSE, FALSE, 0);
		gtk_box_pack_start(GTK_BOX(htrio), calcright, FALSE, FALSE, 0);
	gtk_widget_show(htrio);

	snprintf(filename, 15, "x%c_top.jpg", hw->model);
	calctop = load_image(filename);
	gtk_widget_show(calctop);

	snprintf(filename, 15, "x%c_bot.jpg", hw->model);
	calcbot = load_image(filename);
	gtk_widget_show(calcbot);

	vtrio = gtk_vbox_new(FALSE, 0);
		gtk_box_pack_start(GTK_BOX(vtrio), calctop, FALSE, FALSE, 0);
		gtk_box_pack_start(GTK_BOX(vtrio), htrio, FALSE, FALSE, 0);
		gtk_box_pack_start(GTK_BOX(vtrio), calcbot, FALSE, FALSE, 0);
	gtk_widget_show(vtrio);

	mono = gtk_hbox_new(FALSE, 0);
		gtk_box_pack_start(GTK_BOX(mono), vtrio, FALSE, FALSE, 0);
	gtk_widget_show(mono);

	gtk_container_add(GTK_CONTAINER(kscreen), mono);
}


static gint keyin(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
	extern struct hardware *hw;

	return emkeyin((unsigned short) event->keyval, 0xFF);
}


static gint keyout(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
	extern struct hardware *hw;

	return emkeyup((unsigned short) event->keyval, 0xFF);
}
/* >>> Static */


/* >>> Exported */
void create_Screen(byte showkeyb)
{
	extern struct hardware *hw;
	double d;

	GtkWidget *gpix, *Screen;
	guint timerid;
	int i;

	lcdactive = /*(hw->model == '6')?1:*/ 0;
	rWidth = hw->xpix;
	iWidth = 2 * hw->xpix;
 
	if (greylcd != NULL) free(greylcd);
	if (!(greylcd = malloc(3 * iWidth * iHeight))) {
		fprintf(stderr, "Insufficient Memory\n");
		exit(-1);
	}
	if (savelcd != NULL) free(savelcd);
	if (!(savelcd = malloc(rWidth * rHeight))) {
		fprintf(stderr, "Insufficient Memory\n");
		exit(-1);
	}
	for (i = 0; i < rWidth * rHeight; i++)
		*(savelcd + i) = 0;

	for (i = 0; i < NGRAYS; i++) {
		iris[NGRAYS - i - 1] = iris[NGRAYS*2 - i - 1]
			= (0xbd * i) / (NGRAYS - 1);
		iris[NGRAYS*3 - i - 1] = (0xb5 * i) / (NGRAYS - 1);
	}
/*{
	int i;
	for (i = 0; i < 3 * iWidth * iHeight; i++)
		*(greylcd + i) = 0;
}*/

	gdk_rgb_init();

	gpix = gtk_drawing_area_new();
		gtk_drawing_area_size(GTK_DRAWING_AREA(gpix), iWidth, iHeight);
	gtk_widget_show(gpix);

	Screen = gtk_window_new(GTK_WINDOW_TOPLEVEL);
		gtk_window_set_title(GTK_WINDOW(Screen), "TilEm");
		gtk_window_set_position(GTK_WINDOW(Screen), GTK_WIN_POS_NONE);

		gtk_widget_set_events(Screen, GDK_KEY_RELEASE_MASK);

		if (showkeyb)
			create_keyb(Screen, gpix);
		else
			gtk_container_add(GTK_CONTAINER(Screen), gpix);
		create_menus(Screen, screenmenu, sizeof(screenmenu) / sizeof(GtkItemFactoryEntry), "<screen>");

	timerid = gtk_timeout_add(50, (GtkFunction) ifresh, gpix);
/*	timerid = gtk_timeout_add(50, (GtkFunction) gpix_refresh, gpix);*/
	lcfresh();
	gtk_object_set_user_data(GTK_OBJECT(Screen), (gpointer) timerid);
/*	gtk_signal_connect (GTK_OBJECT (gpix), "expose-event", GTK_SIGNAL_FUNC (on_gpix_expose), NULL);*/

		gtk_signal_connect(GTK_OBJECT(Screen), "destroy", GTK_SIGNAL_FUNC(exit_emulator), (gpointer) -1);
		gtk_signal_connect(GTK_OBJECT(Screen), "key_press_event", GTK_SIGNAL_FUNC(keyin), NULL);
		gtk_signal_connect(GTK_OBJECT(Screen), "key_release_event", GTK_SIGNAL_FUNC(keyout), NULL);

		switchhw(0x88, Screen);
	gtk_widget_show(Screen);
}
/* Exported <<< */
