/*  Core Wars.
 *  Copyright (C) 1999  Walter Hofmann
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as 
 *  published by the Free Software Foundation.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <stdlib.h>
#include <string.h>

#ifndef CMD_LINE
#include <gtk/gtk.h>
#endif

#include "main.h"
#include "main-gui.h"
#include "program.h"
#include "execute.h"
#include "statistic.h"
#include "options.h"

#ifndef CMD_LINE
GtkWidget *statistic_window = NULL;
GtkWidget *statistic_clist;
GtkWidget *statistic_follow;
struct process *selected_row;
int selected_row_number;
int record_selection_change = TRUE;

void handle_press (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (statistic_follow), FALSE);
}

void handle_toggle_focus_row (GtkCList *clist, gint row, gint column,
                              GdkEventButton *event, gpointer user_data)
{
  if (record_selection_change)
    {
      selected_row_number = row;
      selected_row = gtk_clist_get_row_data (GTK_CLIST (statistic_clist), row);
      execute_mark (selected_row);
    }
}

void statistic_view ()
{
  gchar *clist_titles[] = { "Color", "Rank", " Score ", "Threads", " Cells ", "Kills", "Title", "Author" };
  GtkWidget *scrolled_window;
  GtkWidget *okbutton;
  
  if (!statistic_window)
    {
      statistic_window = gtk_dialog_new ();
      gtk_signal_connect (GTK_OBJECT (statistic_window), "destroy", 
			  GTK_SIGNAL_FUNC (gtk_widget_destroyed), &statistic_window);
      gtk_window_set_title (GTK_WINDOW (statistic_window), "Game Statistic");
      scrolled_window = gtk_scrolled_window_new (NULL, NULL);
      gtk_widget_set (GTK_WIDGET (scrolled_window), "height", STATISTIC_WINDOW_HEIGHT, NULL);
      gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), 
				      GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC ); 
      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (statistic_window)->vbox),
			  scrolled_window, TRUE, TRUE, 0);
      statistic_clist = gtk_clist_new_with_titles (8, clist_titles);
      gtk_signal_connect (GTK_OBJECT (GTK_SCROLLED_WINDOW (scrolled_window)->vscrollbar), 
			  "button-press-event", GTK_SIGNAL_FUNC (handle_press), NULL); 
      gtk_signal_connect (GTK_OBJECT (statistic_clist), "select_row", 
			  GTK_SIGNAL_FUNC (handle_toggle_focus_row),
			  NULL); 
      gtk_clist_set_selection_mode (GTK_CLIST (statistic_clist), GTK_SELECTION_BROWSE);
      gtk_clist_set_shadow_type (GTK_CLIST (statistic_clist), GTK_SHADOW_OUT);
      gtk_clist_set_column_justification (GTK_CLIST (statistic_clist), 0, GTK_JUSTIFY_CENTER);
      gtk_clist_set_column_justification (GTK_CLIST (statistic_clist), 1, GTK_JUSTIFY_CENTER);
      gtk_clist_set_column_justification (GTK_CLIST (statistic_clist), 2, GTK_JUSTIFY_CENTER);
      gtk_clist_set_column_justification (GTK_CLIST (statistic_clist), 3, GTK_JUSTIFY_CENTER);
      gtk_clist_set_column_justification (GTK_CLIST (statistic_clist), 4, GTK_JUSTIFY_CENTER);
      gtk_clist_set_column_justification (GTK_CLIST (statistic_clist), 5, GTK_JUSTIFY_CENTER);
      gtk_clist_set_column_width (GTK_CLIST (statistic_clist), 6, STATISTIC_TITLE_WIDTH);
      gtk_clist_set_column_width (GTK_CLIST (statistic_clist), 7, STATISTIC_AUTHOR_WIDTH);
      gtk_container_add (GTK_CONTAINER (scrolled_window), 
			 statistic_clist);
      gtk_widget_show (statistic_clist);
      statistic_follow = gtk_check_button_new_with_label ("selection follows process");
      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (statistic_window)->vbox),
			  statistic_follow, FALSE, TRUE, 0);
      gtk_widget_show (statistic_follow);
      gtk_widget_show (scrolled_window);
      okbutton = gtk_button_new_with_label( "Close" );
      gtk_signal_connect_object (GTK_OBJECT (okbutton), "clicked", 
				 GTK_SIGNAL_FUNC (gtk_widget_destroy),
				 GTK_OBJECT (statistic_window)); 
      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (statistic_window)->action_area),
			  okbutton, TRUE, TRUE, 0);
      gtk_widget_show (okbutton);
      gtk_widget_show (statistic_window);
      selected_row = NULL;
      selected_row_number = 0;
      statistic_update (FALSE);
    }
  else
    gdk_window_raise (statistic_window->window);
}

void statistic_clear ()
{
  if (statistic_window)
    {
      gtk_clist_clear (GTK_CLIST (statistic_clist));
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (statistic_follow), FALSE);
      selected_row = 0;
    }
}

void statistic_update (int partial)
{
  int i, r;
  struct process *p;
  gchar *row[] = {"", "", "", "", "", "", "", ""};
  struct process **table;
  static int countdown = 0;
  
  if (statistic_window && process_count)
    {
      if (countdown && partial)
	countdown--;
      else
	{
	  partial = FALSE;
	  countdown = STATISTIC_FULL_REDRAW_COUNT;
	}
      table = malloc (sizeof (struct process *)*process_count);
      for (i=0; i<process_count; i++)
	*(table+i) = process_array+i;
      qsort (table, process_count, sizeof (struct process *), &process_compare);
      r = TRUE;
      gtk_clist_freeze (GTK_CLIST (statistic_clist));
      if (selected_row && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (statistic_follow)))
	{
	  for (i=0; *(table+i)!=selected_row; i++) ;
	  record_selection_change = FALSE;
	  gtk_clist_select_row (GTK_CLIST (statistic_clist), i, 0);
	  record_selection_change = TRUE;
	  selected_row_number = i;
	  if (gtk_clist_row_is_visible (GTK_CLIST (statistic_clist), i)!=GTK_VISIBILITY_FULL)
	    gtk_clist_moveto (GTK_CLIST (statistic_clist), i, 0, 0.5, 0.0);
	}
      for (i=0; i<process_count; i++)
	{
	  p = *(table+i);
	  if (!partial || i>=GTK_CLIST (statistic_clist)->rows || 
	      gtk_clist_row_is_visible (GTK_CLIST (statistic_clist), i)!=GTK_VISIBILITY_NONE)
	    {
	      if (i>=GTK_CLIST (statistic_clist)->rows)
		gtk_clist_append (GTK_CLIST (statistic_clist), row);
	      if (r)
		gtk_clist_set_text (GTK_CLIST (statistic_clist), i, 1, itos (i+1));
	      else
		gtk_clist_set_text (GTK_CLIST (statistic_clist), i, 1, "");
	      gtk_clist_set_text (GTK_CLIST (statistic_clist), i, 2, itos (process_score (p)));
	      if (p->thread_count)
		  gtk_clist_set_text (GTK_CLIST (statistic_clist), i, 3, itos (p->thread_count));
	      else
		  gtk_clist_set_text (GTK_CLIST (statistic_clist), i, 3, "dead");
	      gtk_clist_set_text (GTK_CLIST (statistic_clist), i, 4, itos (p->cell_count));
	      gtk_clist_set_text (GTK_CLIST (statistic_clist), i, 5, itos (p->kill_count));
	      gtk_clist_set_text (GTK_CLIST (statistic_clist), i, 6, p->program->title);
	      gtk_clist_set_text (GTK_CLIST (statistic_clist), i, 7, p->program->author);
	      gtk_clist_set_pixmap (GTK_CLIST (statistic_clist), i, 0, p->bullet, NULL);
	    }
	  gtk_clist_set_row_data (GTK_CLIST (statistic_clist), i, p);
	  if (i<process_count-1)
	    r = process_score (*(table+i+1))!=process_score (p);
	}
      if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (statistic_follow)) && marked_process)
	execute_mark (gtk_clist_get_row_data (GTK_CLIST (statistic_clist), selected_row_number));	
      gtk_clist_thaw (GTK_CLIST (statistic_clist));
      free (table);
    }
}

void statistic_select (int x, int y)
{
  struct process *p;
  int row;

  x = (x-1)/6;
  y = (y-1)/6;
  if (0<=x && x<DIMENSIONX && 0<=y && y<DIMENSIONY && x+DIMENSIONX*y<SIZE)
    {
      p = memory[x+DIMENSIONX*y].owner;
      execute_mark (p);
      if (statistic_window)
	if (p)
	  {
	    row = gtk_clist_find_row_from_data (GTK_CLIST (statistic_clist), p);
	    gtk_clist_select_row (GTK_CLIST (statistic_clist), row, 0);
	    if (gtk_clist_row_is_visible (GTK_CLIST (statistic_clist), row)!=GTK_VISIBILITY_FULL)
	      gtk_clist_moveto (GTK_CLIST (statistic_clist), row, 0, 0.5, 0.0);
	    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (statistic_follow), TRUE);
	    statistic_update (TRUE);
	  }
	else
	  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (statistic_follow), FALSE);
    }
  else
    execute_mark (NULL);
}

#endif

int process_score (struct process *p)
{
  return SCORE_ALIVE*(p->thread_count>0?elapsed_time:p->death_time) + 
    p->cell_count*SCORE_CELLS + p->kill_count*SCORE_KILLS;
}

int process_compare (const void *a, const void *b)
{
  return process_score (*(struct process **)b) - process_score (*(struct process **)a);
}
