/*
 * 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
 */
/* rolling program --- demostrating allocating resource sets */

#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <rk/rk.h>
#include <rk/rk_error.h>
#include "process.h"

#define MAXTH 6
#define MAXCLR 6
static GdkGC *g[MAXCLR];
static GdkRectangle u_area;
static GdkPixmap *screen;
struct timespec spec[MAXTH];

char *clrs[] = {"Blue", "Green", "Yellow", "Red", "White", "Black"};


#define NS_PER_MS	1000000


static GtkWidget *d_area;

static gint movex, movey;
static gint oldxp[MAXTH], oldyp[MAXTH];
static gint  chmove, center; 
static gint timer = 2, ptimer;
static gint side  = 1, i, wHght = 800, wLen = 360;	

static gint taps[] = {0,0,0};
static gint tapswitch[] = {0,0,0};

static gint configure_event (GtkWidget *, GdkEventConfigure *);
static gint expose_event (GtkWidget *, GdkEventExpose *);
static gint delete_event (GtkWidget *, GdkEvent  *, gpointer);


static char buf[60];

static GtkWidget *start;	
static GtkWidget *close;



static GtkWidget *ReservationButton, *PeriodButton;
static GtkWidget *ReservationText, *PeriodText;
static GtkWidget *wazzup;
static GtkWidget *label[4];


static void setupGraphics();
static void updateScreen();
static void rolling_on();
static void wait_for_me();
static gint change_me(GtkWidget *, GdkEvent  *, gpointer);



long long reservation;
long long period;
long long era, RKera;
int enf_mode, rep_mode;

gint main(gint argc, gchar *argv[])
{
	GtkWidget *window;
	GtkWidget *vbox;
	GtkWidget *hbox, *hbox2;
	
	
	
	if (argc < 2 )
	{
		g_print("USAGE: %s <allocation for each of first three balls (1-100)> <period> [HARD/SOFT]", argv[0]);
		exit(1);
	}
	reservation = 1 * NS_PER_MS;
	period = 100 * NS_PER_MS;

	if (argc >=2) RKera = (long long)atoi(argv[1]);
	if (argc >=3) period = (long long)atoi(argv[2]) * NS_PER_MS;
	printf("period: %d, RKera: %d\n", (int)period, (int)RKera);
	if (argc <= 3) rep_mode = RSV_SOFT;
	else {
	if (argv[3] == NULL) {
	  rep_mode = RSV_SOFT;
	}
	else {
	  if (!(strcmp(argv[3], "HARD"))) {
	    rep_mode = RSV_HARD;
	  }
	  else {
	    rep_mode = RSV_SOFT;
	  }
	}
	}
	gtk_init(&argc, &argv);
	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_default_size(GTK_WINDOW(window), wHght, wLen);
	gtk_window_set_title(GTK_WINDOW(window), "     CONTROLLING PROCESSES USING RT");
	vbox = gtk_vbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER(window), GTK_WIDGET(vbox));  //connect to window
	
/*setting up 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);

/*setting up start button -- start is visible first */
	start = gtk_button_new_with_label("START");
	gtk_signal_connect (GTK_OBJECT (start), "clicked", GTK_SIGNAL_FUNC (rolling_on), NULL);
	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(start), FALSE, FALSE, 5);
	gtk_widget_show(start);

	close = gtk_button_new_with_label("CLOSE");
	gtk_signal_connect (GTK_OBJECT (close), "clicked", GTK_SIGNAL_FUNC (delete_event), NULL);
	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(close), FALSE, FALSE, 5);

/* setting up resevation and period indicators */
	hbox = gtk_hbox_new (FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 5);

	label[0] = gtk_label_new(" ");
	sprintf(buf, "TOTAL CPU RESERVATION FOR FIRST THREE BALLS: %.2f%%  ", 
			(((RKera * reservation) / (float)(period)) * 100) * 3);
	gtk_label_set_text(GTK_LABEL(label[0]), buf);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label[0]), FALSE, FALSE, 5);
	gtk_widget_show(label[0]);

	label[1] = gtk_label_new(" ");
	sprintf(buf, "RESERVATION PERIOD (in milliseconds) %0.f ", 
			(( period)/ (float)NS_PER_MS));
	gtk_label_set_text(GTK_LABEL(label[1]), buf);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label[1]), FALSE, FALSE, 5);
	gtk_widget_show(label[1]);
	gtk_widget_show(hbox);

/* dummy label for spacing */
	
	hbox = gtk_hbox_new (TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), TRUE, TRUE, 0);
	gtk_widget_show(hbox);
	wazzup = gtk_label_new(" ");
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(wazzup), TRUE, TRUE, 0);
	gtk_widget_show(wazzup);
	gtk_widget_show(hbox);

/* setting up text widgets for changing reservation and period */
	hbox = gtk_hbox_new (TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 0);

	hbox2 = gtk_hbox_new (FALSE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(hbox2), FALSE, FALSE, 0);

	ReservationButton = gtk_button_new_with_label("CHANGE RESERVATION");
	gtk_box_pack_start(GTK_BOX(hbox2), GTK_WIDGET(ReservationButton), FALSE, FALSE, 0);
	gtk_signal_connect (GTK_OBJECT (ReservationButton), "clicked", GTK_SIGNAL_FUNC (change_me), NULL);
	gtk_widget_show(ReservationButton);	
	
	ReservationText = gtk_entry_new_with_max_length(5);
	gtk_box_pack_start(GTK_BOX(hbox2), GTK_WIDGET(ReservationText), FALSE, FALSE,0);
	gtk_widget_show(ReservationText);
	gtk_widget_show(hbox2);

	hbox2 = gtk_hbox_new (FALSE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(hbox2), FALSE, FALSE, 0);

	PeriodButton = gtk_button_new_with_label("CHANGE PERIOD");
	gtk_box_pack_start(GTK_BOX(hbox2), GTK_WIDGET(PeriodButton), FALSE, FALSE, 0);
	gtk_signal_connect (GTK_OBJECT (PeriodButton), "clicked", GTK_SIGNAL_FUNC (change_me), NULL);
	gtk_widget_show(PeriodButton);

	PeriodText = gtk_entry_new_with_max_length(5);
	gtk_box_pack_start(GTK_BOX(hbox2), GTK_WIDGET(PeriodText), FALSE, FALSE, 0);
	gtk_widget_show(PeriodText);
	gtk_widget_show(hbox2);
	gtk_widget_show(hbox);

/*message for the bottom */
	hbox = gtk_hbox_new (TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), TRUE, TRUE, 0);
	gtk_widget_show(hbox);
	wazzup = gtk_label_new("\nreal time balls are spinning left, plain balls are spinning right\n");
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(wazzup), TRUE, TRUE, 0);
	gtk_widget_show(wazzup);
	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);
	

	setupGraphics();
	gtk_main();
	doit = 0;
	while(stopit != 3) {}
	destroy_threads();
	return(0);


}


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

gint expose_event (GtkWidget *widget, GdkEventExpose *event)
       {	
		gdk_draw_pixmap(widget->window,widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
                         screen,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;

	rad = 60;
	right = d_area->allocation.width - rad;
	
//setting up color and the update area	


	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] = right;              
	yp[0] = oldyp[0] = 40;
	xp[1] = oldxp[1] = 0;              
	yp[1] = oldyp[1] = 40;
	xp[2] = oldxp[2] = right;              
	yp[2] = oldyp[2] = 150;
	xp[3] = oldxp[3] = 0;             
	yp[3] = oldyp[3] = 150;
	xp[4] = oldxp[4] = right;              
	yp[4] = oldyp[4] = 260;
	xp[5] = oldxp[5] = 0;             
	yp[5] = oldyp[5] = 260;
	center = (rad / 2) - 5;
	ch[0] = -1;
	ch[1] = 1;
	ch[2] = -1;
	ch[3] = 1;
	ch[4] = -1;
	ch[5] = 1;
	chmove = 2;

	for(i = 0; i < MAXTH + 2; i++)
		gdk_draw_line(screen, g[MAXCLR -1], 0, ((i / 2) * 110) + 14, u_area.width, 
					((i / 2) * 110) + 14);
	updateScreen();
}	


void updateScreen()
{
	
	

	for(i = 0; i < MAXTH; i++)
	{
		gdk_draw_arc(screen, g[MAXCLR -2], TRUE, oldxp[i], oldyp[i], rad, rad, 0, 23040);
		oldxp[i] = xp[i];
	}
	movey = (int)sqrt((double)(484 - (movex * movex)));
	if(((movex == 19) && (side == 1))|| ((movex == -19) && (side == -1))) chmove /= 2;  
	if(((movex == 19) && (side == -1))|| ((movex == -19) && (side == 1))) chmove *= 2; 
	if(movex == 22) {chmove = -1; side = -1;} 
	if(movex == -22) {chmove = 1; side = 1;}
	movey *= side;
	movex += chmove;	
	for(i = 0; i < MAXTH; i++)
	{	
		if(i % 2 == 1)
		{
			
			if((ch[i] == -1) && (tapswitch[i / 2] == 0))
			{
			 	taps[i / 2]++;
				sprintf(buf,"%d", taps[i / 2]);
				gdk_draw_rectangle(screen, g[1], TRUE, u_area.width/2, ((i / 2) * 110) + 5,
					  30, 20);
				gdk_draw_rectangle(screen, g[MAXCLR -1], FALSE, u_area.width/2, ((i / 2) * 110 + 5),
					  30, 20);
				gdk_draw_string(screen, d_area->style->font, g[MAXCLR - 1],
					 u_area.width/2 + 3, ((i / 2) * 110) + 19, buf);

				tapswitch[i / 2] = 1;
			}
			 else if(ch[i] == 1)
				tapswitch[i / 2] = 0;
			
		}
		if (i < 3)
		{	
			gdk_draw_arc(screen, g[0], TRUE, xp[i], yp[i], rad, rad, 0, 23040);
			gdk_draw_arc(screen, g[MAXCLR - 2], TRUE, (xp[i] + (center + movex)), 
					(yp[i] + (center + movey)), 10, 10, 0, 23040);
		}
		else
		{
			gdk_draw_arc(screen, g[i-2], TRUE, xp[i], yp[i], rad, rad, 0, 23040);
			gdk_draw_arc(screen, g[MAXCLR - 2], TRUE, (xp[i] + (center + movex)), 
					(yp[i] + (center - movey)), 10, 10, 0, 23040);
		}
	
	}
	
	gtk_widget_draw(GTK_WIDGET(d_area), &u_area); 	
}

void rolling_on()
{
	gtk_widget_show(close);	
	gtk_widget_hide(start);

	create_threads();
	ptimer = gtk_timeout_add(200,(void *)(wait_for_me), NULL);	
	
}

void wait_for_me()
{
	gtk_timeout_add(timer,(void *)(updateScreen), NULL);
	gtk_timeout_remove(ptimer);
}	

gint change_me(GtkWidget *widget, GdkEvent  *event, gpointer data)
{
	int time, success;
	if (widget == ReservationButton)
	{
		time = atoi(gtk_entry_get_text(GTK_ENTRY(ReservationText)));
		if((((((time * NS_PER_MS) / (float)(period)) * 100) * 3) < 70) && (time > 0))
			success =  change_cpu_sets(time, -1);
		else	
			success = RK_ERROR;
	}
				
	
	if (widget == PeriodButton)
	{
		time = atoi(gtk_entry_get_text(GTK_ENTRY(PeriodText)));
		if(((((reservation) / (float)(time * NS_PER_MS)) * 100) * 3) < 70)
			success =  change_cpu_sets(-1, time);
		else
			success = RK_ERROR;
	}
	if(success == 0)
	{
		gtk_label_set_text(GTK_LABEL(wazzup), "\nThe cpu resource sets for the three real time balls have
				been modified\n");
		if (widget == ReservationButton)
		{
		   reservation = time * NS_PER_MS;
		   sprintf(buf, "TOTAL CPU RESERVATION FOR FIRST THREE BALLS: %.2f%%  ", 
			(((reservation / (float)(period)) * 100) * 3));
		   gtk_label_set_text(GTK_LABEL(label[0]), buf);
		}
		if (widget == PeriodButton)
		{
			sprintf(buf, "RESERVATION PERIOD (in milliseconds) %d  ", time);
			gtk_label_set_text(GTK_LABEL(label[1]), buf);
			period = time * NS_PER_MS;
			sprintf(buf, "TOTAL CPU RESERVATION FOR FIRST THREE BALLS: %.2f%%  ", 
				((reservation / (float)(period)) * 100) * 3);
		   	gtk_label_set_text(GTK_LABEL(label[0]), buf);
		}

	}
	else
		gtk_label_set_text(GTK_LABEL(wazzup), "\nThe resource set cannot be changed with current parameters");	
	gtk_entry_set_text(GTK_ENTRY(ReservationText), "");
	gtk_entry_set_text(GTK_ENTRY(PeriodText), "");	
}	
