/*
 * Copyright (C) 2000 TimeSys Corporation
 *
 * This 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 of the License, or (at your
 * option) any later version.
 *
 * This software 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 software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 */
/* the amazing racer */
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <gdk/gdkkeysyms.h>
#include "bitmaps.h"
#include "thread.h"



#define MAXCLR 9
static GdkGC *g[MAXCLR];
static GdkRectangle u_area;
static GdkPixmap *screen[2];
static GdkPixmap *ground[3];

static GtkWidget *label[4];


char *clrs[] = {"LightGray", "Red","Blue","Green","Yellow","Orange","LightBlue", "White", "Black"};
char *names[] = {"RED RACER","BLUE STREAK","MEAN GREEN"};
static GtkWidget *d_area;

static gint timer = 10;
static gint i,j, wHght = 850, wLen = 160, randomize;	


static gint configure_event (GtkWidget *, GdkEventConfigure *);
static gint expose_event (GtkWidget *, GdkEventExpose *);
static gint delete_event (GtkWidget *, GdkEvent  *, gpointer);
static gboolean key_pressed_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data);

static char buf[30];
static GdkPixmap *cars[3];
static GdkPixmap *fin;
static GdkBitmap *mask[3];
static GtkWidget *go_fixed;
static GtkWidget *go_random;
static GtkWidget *reset;
static GdkFont *font;
static char *szFont = "-biznet-terminal-medium-r-normal-*-18-140-*-*-c-*-iso8859-2";
	

static void setupGraphics();
static void updateScreen();
static void reset_threads();
static void make_screen();
static void upit(int i);
static void begin(GtkWidget *widget);

void timed();

gint main(gint argc, gchar *argv[])
{
	GtkWidget *window;
	GtkWidget *vbox;
	GtkWidget *hbox;
	GtkWidget *quit;
	
	

	for(i = 0; i < 3; i++)	
		RKera[i] = 1;	
	era = 1;
	milla = 2000000;
	period = 200000000;
	reservation = 1000000;	
	doit=1;
	cease = 0;
	end_it_all = 0;

	gtk_init(&argc, &argv);
	gdk_key_repeat_disable();


	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_default_size(GTK_WINDOW(window), wHght, wLen);
	vbox = gtk_vbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER(window), GTK_WIDGET(vbox));  //connect to window

//drawing area
	d_area = gtk_drawing_area_new();
	gtk_drawing_area_size (GTK_DRAWING_AREA(d_area),wHght,wLen);
	

	gtk_signal_connect (GTK_OBJECT (d_area), "expose_event", GTK_SIGNAL_FUNC (expose_event), NULL);
	gtk_signal_connect (GTK_OBJECT (d_area), "configure_event", GTK_SIGNAL_FUNC (configure_event), NULL);
	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(d_area), FALSE, FALSE, 5);
	gtk_widget_show(d_area);

//making the start/reset buttons

	hbox = gtk_hbox_new (FALSE, 0);

	go_fixed = gtk_button_new_with_label("GO");
	gtk_signal_connect (GTK_OBJECT (go_fixed), "clicked", GTK_SIGNAL_FUNC (begin), NULL);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(go_fixed), FALSE, FALSE, 5);	

	go_random = gtk_button_new_with_label("GO RANDOM");
	gtk_signal_connect (GTK_OBJECT (go_random), "clicked", GTK_SIGNAL_FUNC (begin), NULL);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(go_random), FALSE, FALSE, 5);	

	reset = gtk_button_new_with_label("RESET");
	gtk_signal_connect (GTK_OBJECT (reset), "clicked", GTK_SIGNAL_FUNC (reset_threads), NULL);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(reset), FALSE, FALSE, 5);
	
	quit = gtk_button_new_with_label("QUIT");
	gtk_signal_connect (GTK_OBJECT (quit), "clicked", GTK_SIGNAL_FUNC (delete_event), NULL);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(quit), FALSE, FALSE, 5);	

	for(i = 0; i < 3; i++)
	{
	   cpu_amt[i] = ((RKera[i] * reservation) / (float)(era * period)) * 100.0;
	   sprintf(buf, "[%s: %.1f%%]", names[i], cpu_amt[i]);
	   label[i] = gtk_label_new(buf);
	   gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label[i]), FALSE, FALSE, 5);
	   gtk_widget_show(label[i]);
	}
	sprintf(buf, "[TOTAL CPU RESERVED: %.1f%%]", cpu_amt[0] + cpu_amt[1] + cpu_amt[2]);
	label[3] = gtk_label_new(buf);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label[3]), FALSE, FALSE, 5);
	gtk_widget_show(label);


	
	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 5);	

	gtk_widget_show(go_fixed);
	gtk_widget_show(go_random);
	gtk_widget_show(quit);
	gtk_widget_show(hbox);
	gtk_widget_show(vbox);
	gtk_widget_show(window);
	gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (delete_event), NULL);
	gtk_signal_connect (GTK_OBJECT (window), "key_press_event", GTK_SIGNAL_FUNC (key_pressed_event), NULL);
	
//getting the font
	font = gdk_font_load (szFont);
	if (font == NULL)
	{
	   	font = d_area->style->font;
		g_print("\n\n*** RACER WARNING --- cannot find specified font, using default style\n\n");
	}	
	setupGraphics();
	gtk_timeout_add(timer,(void *)(updateScreen), NULL);
	gtk_main();
	doit = 0;
	if(end_it_all)
	{
		while(stopit != 3) {}
		destroy_threads();
	}
	gdk_key_repeat_restore();
	return(0);
}


static gint configure_event (GtkWidget *widget, GdkEventConfigure *event)
{
   if (!(screen[0])){
    screen[0] = gdk_pixmap_new(widget->window,widget->allocation.width, widget->allocation.height, -1);
    gdk_draw_rectangle (screen[0],widget->style->white_gc,TRUE,0,0,widget->allocation.width,  widget->allocation.height);
    }
    return TRUE; 
}

static gint expose_event (GtkWidget *widget, GdkEventExpose *event)
{	
   gdk_draw_pixmap(widget->window,widget->style->fg_gc[GTK_WIDGET_STATE (widget)], screen[0],event->area.x, 
	event->area.y, event->area.x, event->area.y, event->area.width, event->area.height);
   return FALSE;
}	

gint delete_event(GtkWidget *widget, GdkEvent  *event, gpointer   data)
{
        gtk_main_quit();
        return(FALSE);
}

void setupGraphics()
{
	GdkColormap *cmap;
	GdkVisual *vis;
	GdkColor *myColor;
	int i;

	for(i = 0; i < 3; i++)
		ground[i] = gdk_pixmap_new(d_area->window, 54, 20, -1);
	screen[1] = gdk_pixmap_new(d_area->window,d_area->allocation.width, d_area->allocation.height, -1);

//getting the bitmaps
	cars[0] = gdk_pixmap_create_from_xpm_d (d_area->window, &mask[0], NULL, (gchar **)racer_red);
	cars[1] = gdk_pixmap_create_from_xpm_d (d_area->window, &mask[1], NULL, (gchar **)racer_blue);
	cars[2] = gdk_pixmap_create_from_xpm_d (d_area->window, &mask[2], NULL, (gchar **)racer_green);
	fin = gdk_pixmap_create_from_xpm_d (d_area->window, NULL, NULL, (gchar **)finish);

	myColor = malloc(sizeof(GdkColor));
	u_area.x = 0;
	u_area.y = 0;
	u_area.width = d_area->allocation.width;
	u_area.height = d_area->allocation.height; 
	vis = gdk_visual_get_best();
	cmap = gdk_colormap_new(vis, TRUE);
	cmap = gdk_colormap_get_system();
	for(i = 0; i < MAXCLR; i++)
	{
		g[i] = gdk_gc_new(d_area->window);
		gdk_color_parse(clrs[i], myColor);
		gdk_colormap_alloc_color(cmap, myColor, TRUE, TRUE);	
		gdk_gc_set_foreground(g[i], myColor);
	}
	xp[0] = oldxp[0] = 5;              
	yp[0]= 20;
	xp[1] = oldxp[1] = 5;              
	yp[1] = 70;
	xp[2] = oldxp[2] = 5;              
	yp[2] = 120;

//drawing the racetrack


	make_screen();
	gdk_draw_pixmap(screen[1], g[0], screen[0], 0, 0, 0, 0, -1, -1);		
}	

void updateScreen()
{
	
	
	for(i = 0; i < MAXTH; i++)
	{	
		gdk_draw_pixmap(screen[0], g[0], ground[i], 0, 0, oldxp[i], yp[i],  56, 20); 

		gdk_gc_set_clip_mask (g[0], mask[i]);
		gdk_gc_set_clip_origin (g[0], xp[i], yp[i]);
		
		gdk_draw_pixmap(screen[0], g[0], cars[i], 0, 0, xp[i], yp[i],  55, 20);
		gdk_gc_set_clip_mask (g[0], NULL);
		oldxp[i] = xp[i];
		gdk_draw_pixmap (ground[i], g[0], screen[1], oldxp[i], yp[i], 0, 0, 56, 20);
	}
	if (race_over)
	{
	   sprintf(buf, "%s  WINS!!!", names[winner]);
	   gdk_draw_rectangle(screen[0], g[MAXCLR -2], TRUE, 280, 45, 250, 30);
	   gdk_draw_string(screen[0], font, g[winner+1], 300, 65, buf);
	   race_over = 0;
	}		
	gtk_widget_draw(GTK_WIDGET(d_area), &u_area); 	
}	

void begin(GtkWidget *widget)
{
	if(widget == go_random) randomize = 1;
	else randomize = 0;
	
	gtk_widget_show(reset);
	gtk_widget_hide(go_fixed);
	gtk_widget_hide(go_random);
	create_threads();
	cease = 1;
	for(i = 0; i < 3; i++)
	{
		cpu_amt[i] = ((RKera[i] * reservation) / (float)(era * period)) * 100.0;
		sprintf(buf, "[%s: %.1f%%]", names[i], cpu_amt[i]);
		gtk_label_set_text(GTK_LABEL(label[i]), buf);
	}
	sprintf(buf, "[TOTAL CPU RESERVED: %.1f%%]", cpu_amt[0] + cpu_amt[1] + cpu_amt[2]);
	gtk_label_set_text(GTK_LABEL(label[3]), buf);	
}

void reset_threads()
{
	doit = 0;
	make_screen();
 	while (stopit != 3) {}
	destroy_threads();
	xp[0] = oldxp[0] = 5;              
	yp[0]= 20;
	xp[1] = oldxp[1] = 5;              
	yp[1] = 70;
	xp[2] = oldxp[2] = 5;              
	yp[2] = 120;
	doit = 1;
	stopit = 0;
	running = 0;
	gtk_widget_show(go_fixed);
	gtk_widget_show(go_random);
	gtk_widget_hide(reset);
	
}

void make_screen()
{
	gdk_draw_rectangle(screen[0], g[MAXCLR - 2], TRUE, 0, 0, 850, 180);
	gdk_draw_rectangle(screen[0], g[6], TRUE, 75, 0, 700, 180);
	for(i = 0; i < 4; i++)
		gdk_draw_rectangle(screen[0], g[5], TRUE, 75, i * 50 + 3 , 700, 9);	
	for(i = 1; i < 36; i++)
	{
		gdk_draw_rectangle(screen[0], g[0], TRUE, i*20 + 50, 0, 17, 180);
		for(j = -2; j < 20; j++)
		{
		   gdk_draw_line(screen[0], g[MAXCLR -1], i* 20 + 50, j * 8, i * 20 + 66, j * 8 + 16);
 		   gdk_draw_line(screen[0], g[MAXCLR -1], i * 20 + 50, j * 8 + 16, i* 20 + 66, j * 8);
		}
		for(j = 0; j  < 4; j++)
 		{
		   gdk_draw_line(screen[0], g[5], i * 20 + 50, j * 50 + 2,  i * 20 + 66, j * 50 + 10); 
		   gdk_draw_line(screen[0], g[5], i * 20 + 50, j * 50 + 10,  i * 20 + 66, j * 50 + 2); 
		}
	}	
	gdk_draw_pixmap(screen[0], g[0], fin, 0,0, i*20 + 50, 0, -1, -1);
}


gboolean key_pressed_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
	if(cease)
	{
		if (event->keyval == 122)
			upit(0);
		if (event->keyval == 98)
			upit(1);
		if (event->keyval == 47)
			upit(2);
	}
	return TRUE;
}

void upit(int i)
{
	if (randomize)  j = rand() % 10 + 1;
	else j = 1;
	change_cpu_sets(i, j);
	sprintf(buf, "[%s: %.1f%%]", names[i], cpu_amt[i]);
	gtk_label_set_text(GTK_LABEL(label[i]), buf);
	sprintf(buf, "[TOTAL CPU RESERVED: %.1f%%]", cpu_amt[0] + cpu_amt[1] + cpu_amt[2]);
	gtk_label_set_text(GTK_LABEL(label[3]), buf);
	
}


	