/* 
 * Copyright (C) 2003 Tim Martin
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <sys/time.h>

#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <stdio.h>
#include <stdlib.h>

#include <errno.h>
#include <sys/types.h>
#include <pwd.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <string.h>

#include "callbacks.h"
#include "interface.h"
#include "support.h"

#include "screen.h"
#include "heightmap.h"
#include "utils.h"
#include "map.h"
#include "tiles.h"
#include "client.h"
#include "landvalue.h"
#include "gtkhelp_reports.h"

#include "sdlwin.h"
#include "utils.h"

static void draw_grid(GtkWidget *widget);
static void recenter_screen(GtkWidget *widget, screen_t *screen, map_t *map, int mapx, int mapy);
static void show_message(char *msg, void *rock);
static int placeobject_iterator(map_t *map, int mapx, int mapy, void *rock);

GtkWidget *about_window = NULL;
GtkWidget *popreport_window = NULL;
GtkWidget *finances_window = NULL;
GtkWidget *stats_window = NULL;
GtkWidget *newgame_window = NULL;
GtkWidget *info_window = NULL;
GtkWidget *gamelist_window = NULL;
GtkWidget *textdisp_window = NULL;
GtkWidget *taxes_window = NULL;
extern GtkWidget *window1;
guint idle_handler = -1;
extern int debug;

GtkEntry *currentposx;
GtkEntry *currentposy;
GtkLabel *CurrentToolLabel;
GtkLabel *CurrentTimeLabel;
GtkLabel *fundslabel = NULL;
GtkLabel *MessageLabel;


#define MAX_FRAMES_SEC 30
#define MYMIN(a,b) ((a < b) ? a : b)
#define MYMAX(a,b) ((a >= b) ? a : b)
 
GtkWidget *drawingareawidget = NULL;
map_t *map = NULL;
screen_t *screen;
tiles_t *tiles = NULL;
client_t *client;
player_t *me;
display_t display;
int block_speed_cb = 0;

static void set_current_activity(char *name);

static char *
default_userid(void)
{
    return getpwuid(getuid())->pw_name;
}

void
on_new1_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    GtkEntry *username_entry;
    GtkEntry *servername_entry;

    if (newgame_window) return;
    if (gamelist_window) return;

    newgame_window = create_newgameWindow ();

    username_entry = (GtkEntry *)lookup_widget(GTK_WIDGET(newgame_window), "username_entry");
    gtk_entry_set_text(username_entry, default_userid());

    servername_entry = (GtkEntry *)lookup_widget(GTK_WIDGET(newgame_window), "server_entry");
    gtk_entry_set_text(servername_entry, "localhost");

    gtk_widget_show (newgame_window);
}


void
on_quit1_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    /* xxx quit more safely */
    exit(0);
}

void
on_about1_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    if (!about_window) {
	about_window = create_AboutWindow();
    }
    gtk_widget_show (about_window);
    gdk_window_raise(about_window->window);
}

int screen_moved = 1;

static int
maybe_draw_spot(int mapx, int mapy, void *rock)
{
    int screenx;
    int screeny;

    if (screen_is_square_viewable(screen, mapx, mapy, &screenx, &screeny)) {

	sdlwin_draw_spot(&display, map, me, screen, tiles, screen_moved, mapx, mapy, screenx, screeny);
    }

    return 0;
}

enum selected_type {
    SELECT_POINT,
    SELECT_BOX,
    SELECT_LINE
};

static void
selected_set(enum selected_type type, int x1, int y1, int x2, int y2, int hitype)
{
    switch(type) 
	{
	case SELECT_POINT:
	    display.selected_cost = 
		map_set_temporary(map, me, x1, y1, display.activity, 
				  hitype, MAPSPECIAL_HILITE_INVALID);
	    break;
	case SELECT_BOX:
	    display.selected_cost = 
		map_set_temporary_box(map, me, x1, y1, x2, y2, display.activity,
				      hitype, MAPSPECIAL_HILITE_INVALID);
	    break;
	case SELECT_LINE:
	    display.selected_cost = map_set_temporary_line(map, me, x1, y1, x2, y2, 
							   display.activity,
							   hitype, MAPSPECIAL_HILITE_INVALID);
	    break;
	}
}

static void
selected_setup(enum selected_type type, int x1, int y1, int x2, int y2, int hitype)
{
    int cash;

    selected_set(type, x1, y1, x2, y2, hitype);
    
    cash = player_getmoney(me);
    if (cash < display.selected_cost) {
	selected_set(type, x1, y1, x2, y2, MAPSPECIAL_HILITE_INVALID);
    }
}

static void
set_cursor(int mapx, int mapy)
{
    selected_setup(SELECT_POINT, mapx, mapy, mapx, mapy, MAPSPECIAL_CURSOR);
}


static void
draw_grid(GtkWidget *widget)
{
    char coststr[100];
    char amountstr[12];

    /*
     * Don't draw anything if there is no map yet
     */
    if (!map) return;

    /*
     * could make a big increase by eliminating this call
     */
    if (screen_moved) {
	screen_viewarea_clear(screen);
	sdlwin_clearscreen();
    }


    /* iterate over the whole map but only draw the viewable (or
     *  partially viewable) squares. The order we iterate in is
     *  determined by our current rotation
     */

    if (screen_moved) { /* xxx really should be map changed */
	if (display.view == GAMEVIEW_POLICE_COVER) {
	    display.viewtype = MAPTYPE_POLICE;
	    display.objlist = map_find_tile_list(map, MAPTYPE_POLICE);
	} else if (display.view == GAMEVIEW_HOSPITAL_COVER) {
	    display.viewtype = MAPTYPE_HOSPITAL;
	    display.objlist = map_find_tile_list(map, MAPTYPE_HOSPITAL);
	} else if (display.view == GAMEVIEW_FIRE_COVER) {
	    display.viewtype = MAPTYPE_FIRE;
	    display.objlist = map_find_tile_list(map, MAPTYPE_FIRE);
	}
    }

    /*
     * XXX could get 10% increase by not calling this
     */
    screen_map_iterate(screen, &maybe_draw_spot, (void *)widget);

    sdlwin_updatescreen();

    prettyprint_money(display.selected_cost, amountstr, sizeof(amountstr)-1);
    snprintf(coststr, sizeof(coststr),_("Cost: %s"), amountstr);
    gtk_label_set_text(MessageLabel, coststr);

    /*
     * We just recalculated the spots. Re-position the hightlighted square too
     */
    if (screen_moved) {
	int x, y;
	GdkModifierType state;
	int mapx;
	int mapy;

	gdk_window_get_pointer (widget->window, &x, &y, &state);

	if (screen_to_mapcoord(screen, x, y, &mapx, &mapy) == 0) {
	    set_cursor(mapx, mapy);
	}

	screen_moved = 0;
    }

}

gboolean
on_maindrawingarea_key_press_event     (GtkWidget       *widget,
                                        GdkEventKey     *event,
                                        gpointer         user_data)
{
    int x, y;
    GdkModifierType state;
    int mapx, mapy;

    switch (event->keyval) 
	{
	case GDK_Escape:
	    gdk_window_get_pointer (event->window, &x, &y, &state);


	    if (screen_to_mapcoord(screen, x, y, &mapx, &mapy) != 0) {
		return FALSE;
	    }

	    set_cursor(mapx, mapy);
	    break;
	}
     
    return FALSE;
}

static void
recenter_screen(GtkWidget *widget, screen_t *screen, map_t *map, int mapx, int mapy)
{
    int sx;
    int sy;
    int mapsizex = map_get_sizex(map);
    int mapsizey = map_get_sizey(map);
    int h = 0;

    /* re-center the viewable map on mapx,mapy */
    mapcoord_to_screen(screen, mapsizex, mapsizey, mapx, mapy, &sx, &sy);

    if (map) {
	h = map_get_height(map, mapx, mapy);
	sy -= (screen_tileheight(screen) * h);
    }

    sx = sx - widget->allocation.width/2;
    sy = sy - widget->allocation.height/2;

    /* don't allow moving too far away from the map */
    screen_keep_in_bounds(screen, mapsizex, mapsizey, &sx, &sy);

    screen_set_position(screen, sx, sy);

    screen_moved = 1;
}

extern void
screen_center_on_xy(map_t *map, int mapx, int mapy)
{
    recenter_screen(drawingareawidget, screen, map, mapx, mapy);
}

static gint 
timer_function(gpointer data)
{
    int mapchanged;
    static time_t last = 0;
    time_t now = time(NULL);

    if (now - last > 5) { /* xxx configurable */
	if (finances_window) {
	    update_finances_window(finances_window, client);
	}
	if (popreport_window) {
	    update_population_report(popreport_window, client);
	}
	if (stats_window) {
	    update_stats_window(stats_window, client);
	}

	last = now;
    }

    if (client) {
	client_checkpoint(client, &mapchanged);    
    }

    /* return 1 because we don't want this timer callback to go away */
    return 1;
}

static gint
idle_loop (gpointer data)
{
	static int cnt = 0;
	static int lastsec = 0;
	static struct timeval last = {0, 0};
	struct timeval now;

	gettimeofday(&now, NULL);

	if (now.tv_sec > lastsec) {
	    
	    if (debug) printf("%d FPS\n",cnt);

	    cnt = 0;
	    lastsec = now.tv_sec;
	}

	if (last.tv_sec != 0) {
	    if ((now.tv_sec - last.tv_sec) * 1000000 + now.tv_usec - last.tv_usec < 
		1000000/(2*MAX_FRAMES_SEC)) {
		return TRUE;
	    }
	}
	
	last = now;    
	cnt++;

	draw_grid((GtkWidget *)data);

	return TRUE;
}

guint timeoutid = -1;

static void
timeout_add(void)
{
    timeoutid = gtk_timeout_add (1000, 
				 &timer_function,
				 NULL);
}

static void
timeout_remove(void)
{
    if (timeoutid != -1) {
	gtk_timeout_remove(timeoutid);
	timeoutid = -1;
    }
}

int foobar = 0;

gboolean
on_maindrawingarea_configure_event     (GtkWidget       *widget,
                                        GdkEventConfigure *event,
                                        gpointer         user_data)
{
    GtkRcStyle *rc_style;
    int r;
    int mapx = 0;
    int mapy = 0;

    if (idle_handler > -1) {
	gtk_idle_remove(idle_handler);
    }

    /* After filling in your GdkColor, create a GtkRcStyle */    
    if (!foobar) {
	rc_style = gtk_rc_style_new ();

	gtk_widget_modify_style (widget, rc_style);
    
	gtk_rc_style_unref (rc_style);
    }

    drawingareawidget = widget;

    sdlwin_init(widget);

    if (!map) {
	timeout_add();
    }   

    if (!screen) {
	r = screen_init(&screen);
	/* xxx screen_setmap(screen, map);*/

    }

    screen_setsize(screen, widget->allocation.width,widget->allocation.height);

    /*
     * Figure out where the old center of the screen is
     */
    screen_to_mapcoord_screen_center(screen, &mapx, &mapy);

    /* xxx recenter_screen(widget, screen, mapx, mapy);*/

    currentposx = (GtkEntry *)lookup_widget(widget, "currentposx");
    currentposy = (GtkEntry *)lookup_widget(widget, "currentposy");
    CurrentToolLabel = (GtkLabel *)lookup_widget(widget, "CurrentToolLabel");
    CurrentTimeLabel = (GtkLabel *)lookup_widget(widget, "CurrentTimeLabel");
    fundslabel = (GtkLabel *)lookup_widget(widget, "fundslabel");
    MessageLabel = (GtkLabel *)lookup_widget(widget, "MessageLabel");

    updatemoney();

    idle_handler = gtk_idle_add(idle_loop, widget);

    foobar = 1;
    return TRUE;
}



static void
show_mapspot_info(int mapx, int mapy)
{
    GtkCList *clist;

    if (!info_window) {
	info_window = create_info_window();
	setup_info_treeview(info_window);
    }

    update_info_window(info_window, client, mapx, mapy);

    gtk_widget_show (info_window);
    gdk_window_raise(info_window->window);
}

/* xxx put these in the display structure */
int mousepressed = 0;
int mousepressed_map_x = -1;
int mousepressed_map_y = -1;

gboolean
on_maindrawingarea_button_press_event  (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
    int mapx;
    int mapy;

    if (screen_to_mapcoord(screen, event->x, event->y, &mapx, &mapy) != 0) {
	return FALSE;
    }

    if (event->button == 1) {
	mousepressed_map_x = mapx;
	mousepressed_map_y = mapy;
	mousepressed = 1;

	selected_setup(SELECT_POINT, mapx, mapy, mapx, mapy, MAPSPECIAL_SELECTED);

    } else if (event->button == 2) {
	recenter_screen(widget, screen, map, mapx, mapy);

	/* reset the select square */
	map_temporary_reset(map);

    } else if (event->button == 3) {
	show_mapspot_info(mapx, mapy);
    }

    return TRUE;
}

gboolean
on_maindrawingarea_motion_notify_event (GtkWidget       *widget,
                                        GdkEventMotion  *event,
                                        gpointer         user_data)
{
    int x, y;
    GdkModifierType state;
    int mapx;
    int mapy;
    char str[10];
    int sizex;
    int sizey;
    int r;

    if (event->is_hint) {
	gdk_window_get_pointer (event->window, &x, &y, &state);
    } else {
	x = event->x;
	y = event->y;
	state = event->state;
    }

    /* get current map coordinate */
    if (screen_to_mapcoord(screen, x, y, &mapx, &mapy) != 0) {
	return FALSE;
    }

    /* tell the GUI the current position */
    snprintf(str,sizeof(str)-1,"%d",mapx);
    gtk_entry_set_text(currentposx, str);
    snprintf(str,sizeof(str)-1,"%d",mapy);
    gtk_entry_set_text(currentposy, str);
        
    tiles_getsize(tiles, display.activity, &sizex, &sizey);

    switch (display.activity) 
	{
	case MAPOBJ_ACTION_RAISE:
	case MAPOBJ_ACTION_LOWER:
	    selected_setup(SELECT_POINT, mapx, mapy, mapx, mapy, MAPSPECIAL_SELECTED);
	    return FALSE;
	default:
	    break;

    }

    if (state & GDK_BUTTON1_MASK) {
	/* mouse is being held down */

	if (display.activity == MAPOBJ_ACTION_FLATTEN) {
	    selected_setup(SELECT_BOX, mousepressed_map_x, mousepressed_map_y, 
			   mapx, mapy, MAPSPECIAL_SELECTED);
	    if (display.height_change_list) {
		mapspot_list_free(display.height_change_list);
		display.height_change_list = NULL;
	    }
	    r = map_temporary_iterate(map, MAPSPECIAL_SELECTED,
				      &placeobject_iterator, (void *)&display);
	    if (r) {
		selected_setup(SELECT_BOX, mousepressed_map_x, mousepressed_map_y, 
			       mapx, mapy, MAPSPECIAL_HILITE_INVALID);
	    } else {
		display.selected_cost = 
		    mapspot_list_length(display.height_change_list) * 1000; /* xxx */
	    }
	} else if (map_item_gettype(display.activity) == MAPTYPE_ROAD) {
	    selected_setup(SELECT_LINE, mousepressed_map_x, mousepressed_map_y, 
			   mapx, mapy, MAPSPECIAL_SELECTED);
	} else {
	    selected_setup(SELECT_BOX, mousepressed_map_x, mousepressed_map_y, 
			   mapx, mapy, MAPSPECIAL_SELECTED);
	}

    } else if (!mousepressed) {
	set_cursor(mapx, mapy);
    }
	    
    return FALSE;
}

void
updatemoney(void)
{
    char str[100];

    if (!me) return;

    prettyprint_money(player_getmoney(me), str, sizeof(str)-1);
    if (fundslabel) {
	gtk_label_set_text(fundslabel,str);
    }
}

static int
count_cur_diff(int x, int y, void *data, float dist, void *rock)
{
    int *cnt = (int *)rock;

    (*cnt) += (int)data;

    return 0;
}

static int
placeobject_iterator(map_t *map, int mapx, int mapy, void *rock)
{
    display_t *display = (display_t *)rock;
    int diff;
    int r;
    int i;
    int curdiff = 0;

    switch(display->activity)
	{
	case MAPOBJ_ACTION_BUYLAND:
	    if ((map_empty_land(map, mapx, mapy)) &&		
		(map_can_buyland(map, me, mapx, mapy))) {		
		client_buyland(client, mapx, mapy);
	    }
	    
            break;
	case MAPOBJ_ACTION_BUYALL:
	    if (map_can_buyland(map, me, mapx, mapy)) {
		client_buyland(client, mapx, mapy);	    
	    } 
	    break;
	case MAPOBJ_ACTION_SELLLAND:
	    if ((map_empty_land(map, mapx, mapy)) &&		
		(map_can_sellland(map, me, mapx, mapy))) {		
		client_sellland(client, mapx, mapy);
	    }
	    break;
	case MAPOBJ_ACTION_FLATTEN:
	    mapspot_within_iterate(display->height_change_list, 
				   mapx, mapy, 0.0,
				   count_cur_diff, (void *)&curdiff);

	    diff = map_get_height(map, mousepressed_map_x, mousepressed_map_y) 
		- (map_get_height(map, mapx, mapy) + curdiff);

	    for (i = 0; i < abs(diff); i++) {
		r = map_change_height_list(&display->height_change_list, 
					   map, me, mapx, mapy,
					   (diff > 0) ? 1 : -1);
		if (r) {
		    printf(_("Error changing %d,%d\n"), mapx, mapy);
		    return r;
		}
	    }
	    break;
	default:
	    if (display->activity != MAPOBJ_INVALID) {
		client_setspot(client, mapx, mapy, display->activity);
	    }
	}

    return 0;
}

gboolean
on_maindrawingarea_button_release_event(GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{

    if (event->button == 1) {
	int mapx;
	int mapy;
	int addx;
	int addy;
	int r;
	mapspot_list_t *list = NULL;

	if ((!client) || (!map)) return FALSE;

	screen_to_mapcoord(screen, event->x, event->y, &mapx, &mapy);

	screen_getdirviewadds(screen, &addx, &addy);

	switch(display.activity) {
	case MAPOBJ_ACTION_RAISE:

	    map_change_height_square(&list, map, me, mapx, mapy, 1);

	    client_txn_start(client);
	    client_changeheight(client, list);
	    client_txn_commit(client);	    
	    break;
	case MAPOBJ_ACTION_LOWER:

	    map_change_height_square(&list, map, me, mapx, mapy, -1);

	    client_txn_start(client);
	    client_changeheight(client, list);
	    client_txn_commit(client);
	    break;
	case MAPOBJ_ACTION_FLATTEN:
	    {
		int x1;
		int x2;
		int y1;
		int y2;

		x1 = MYMIN(mousepressed_map_x, mapx);
		x2 = MYMAX(mousepressed_map_x, mapx) + 1;

		y1 = MYMIN(mousepressed_map_y, mapy);
		y2 = MYMAX(mousepressed_map_y, mapy) + 1;
		
		selected_setup(SELECT_BOX, x1, y1, x2, y2, MAPSPECIAL_SELECTED);

		r = map_temporary_iterate(map, MAPSPECIAL_SELECTED,
				      &placeobject_iterator, (void *)&display);
		if (!r) {
		    client_txn_start(client);
		    client_changeheight(client, display.height_change_list);
		    client_txn_commit(client);
		} else {
		    printf(_("Error flattening\n"));
		}
		
		display.height_change_list = NULL;
	    }
	    break;
	default:
	    client_txn_start(client);
	    map_temporary_iterate(map, MAPSPECIAL_SELECTED,
				  &placeobject_iterator, (void *)&display);
	    client_txn_commit(client);	    
	    updatemoney();
	    break;
	}

	map_temporary_reset(map);

	set_cursor(mapx, mapy);
	screen_moved = 1;
    }

    mousepressed = 0;

    return FALSE;
}

gboolean
on_maindrawingarea_expose_event        (GtkWidget       *widget,
                                        GdkEventExpose  *event,
                                        gpointer         user_data)
{
    return FALSE;
}

static void
set_current_activity_obj(mapobj_t obj)
{
    display.activity = obj;

    if (CurrentToolLabel) {
	gtk_label_set_text(CurrentToolLabel, "xxx"); /* xxx */
    }
}

static void
set_current_activity(char *name)
{    
    display.activity = map_item_name2obj(name);
    if (display.activity == MAPOBJ_INVALID) {
	printf(_("Map object %s not found\n"), name);
    }
    if (CurrentToolLabel) {
	gtk_label_set_text(CurrentToolLabel, name);
    }
}



void
set_current_time(time_t curtime)
{
    struct tm *tm;
    char timestr[25];

    tm = gmtime(&curtime);

    strftime(timestr, sizeof(timestr)-1,_("%b %e, %Y"), tm);

    gtk_label_set_text(CurrentTimeLabel,timestr);


    
}

struct weather_buffer {
    char *name;
    GdkPixmap *pixmap;
} weather_buflist[20]; /* xxx */
int weather_buflist_len = 0;

static GdkPixmap *
get_weather_pic(GtkImage *weatherpic, char *weather)
{
    char buf[1024];
    GdkColormap *colormap;
    GdkPixmap *gdkpixmap;
    GdkBitmap *mask;
    int i;

    /*
     * look in cache
     */
    for (i = 0; i < weather_buflist_len; i++) {
	if (!weather_buflist[i].name) break;
	if (strcasecmp(weather_buflist[i].name, weather) == 0) {
	    return weather_buflist[i].pixmap;
	}
    }

    /*
     * Not found. load it
     */
    colormap = gtk_widget_get_colormap((GtkWidget *)weatherpic);

    snprintf(buf, sizeof(buf)-1,"../img/w_%s.xpm", weather);
    gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask,
						     NULL, buf);
    if (!gdkpixmap) {
	snprintf(buf, sizeof(buf)-1,"%s/w_%s.xpm", IMG_DIRECTORY, weather);
	gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask,
							 NULL, buf);
    }

    /* add to cache */
    weather_buflist[weather_buflist_len].name = strdup(weather);
    weather_buflist[weather_buflist_len].pixmap = gdkpixmap;
    weather_buflist_len++;

    return gdkpixmap;    
}

void
set_current_weather(char *weather, int temp)
{
    GtkImage *weatherpic;
    char buf[1024];
    GtkLabel *templabel;
    GtkWidget *pic;
    GdkImage *image = NULL;

    /*
     * Temperature label
     */
    templabel = (GtkLabel *)lookup_widget(window1, "temp_label");
    snprintf(buf, sizeof(buf)-1,"%dF", temp);
    gtk_label_set_text(templabel, buf);

    /*
     * Change the weather picture
     */ 
    weatherpic = (GtkImage *)lookup_widget(window1, "weather_pic");

    snprintf(buf, sizeof(buf), "../img/w_%s.png", weather);
    gtk_image_set_from_file(weatherpic, buf);
    gtk_widget_show ((GtkWidget *)weatherpic);
}

void
set_speed_ui(game_speeds_t speed)
{
    GtkWidget *w;

    switch (speed) 
	{
	case SPEED_FASTEST:
	    w = lookup_widget(window1, "fastest1");
	    break;
	case SPEED_FAST:
	    w = lookup_widget(window1, "fast1");
	    break;
	case SPEED_NORMAL:
	    w = lookup_widget(window1, "normal1");
	    break;
	case SPEED_SLOW:
	    w = lookup_widget(window1, "slow1");
	    break;
	default:
	case SPEED_PAUSED:
	    w = lookup_widget(window1, "paused1");
	    break;
	}

    block_speed_cb = 1;

    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM (w), TRUE);

    block_speed_cb = 0;
}

static void
zoom(int zoomchange)
{
    int mapx = 0;
    int mapy = 0;

    screen_zoom(screen, zoomchange);

    screen_to_mapcoord_screen_center(screen, &mapx, &mapy);

    recenter_screen(drawingareawidget, screen, map, mapx, mapy);
}

void
on_zoomin_clicked                      (GtkButton       *button,
                                        gpointer         user_data)
{
    zoom(1);
}


void
on_zoomout_clicked                     (GtkButton       *button,
                                        gpointer         user_data)
{
    zoom(-1);
}



void
on_show_grid1_activate                 (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    display.grid = !display.grid;

    gtk_check_menu_item_set_state ((GtkCheckMenuItem *)menuitem, (gboolean)display.grid);
}




void
on_about_ok_clicked             (GtkButton       *button,
				 gpointer         user_data)
{
    gtk_widget_hide (about_window);
}



static void
gameinfo_cb(char *name, void *rock)
{
    GList **glistp = (GList **)rock;

    *glistp = g_list_append (*glistp, strdup(name));
}

static char *
find_app(char *name, char *trypath, char *buf, int buflen)
{
    char *path = getenv("PATH");    
    char cwd[MAXPATHLEN+1];
    struct stat sb;

    /*
     * First try path requested
     */
    if (trypath) {
	snprintf(buf, buflen, "%s/%s", trypath, name);
	if (stat(buf, &sb) == 0) {
	    return buf;
	}
    }
    
    /*
     * Next try current directory
     */
    getcwd(cwd, sizeof(cwd)-1);
    snprintf(buf, buflen, "%s/%s", cwd, name);
    if (stat(buf, &sb) == 0) {
	return buf;
    }

    /*
     * Now try everything in the path
     */
    while (path) {
	char *colon = strchr(path, ':');
	char dir[MAXPATHLEN+1];

	if (colon) {
	    memcpy(dir, path, colon-path);
	    dir[colon-path] = '\0';
	} else {
	    strcpy(dir, path);
	}

	snprintf(buf, buflen, "%s/%s", dir, name);

	if (stat(buf, &sb) == 0) {
	    return buf;
	}

	if (colon) {
	    path = colon+1;
	} else {
	    path = NULL;
	}
    }

    return NULL;
}

extern void
start_local_server(void)
{
    pid_t pid;
    
    pid = fork();
    if (pid) {
	/* parent */
	return;

    } else {
	char serverstr[MAXPATHLEN+1];
	char *server = find_app("senkenserver", "../server/", 
				serverstr, sizeof(serverstr)-1);
	char xtermstr[MAXPATHLEN+1];
	char *xterm = find_app("xterm", NULL, xtermstr, sizeof(xtermstr)-1);

	execl(xterm, "xterm", "-e", server, NULL);

	/* never reaches */
	fprintf(stderr,_("Error execing server: %s"), strerror(errno));
	exit(1);
    }
}

extern int
server_connect(const char *username, const char *servername)
{
    int r;

    if (!username) {
	username = default_userid();
    }

    /*
     * Close + free old client connection
     */
    if (client) {
	client_close(client);
	client_free(client);
    }
    
    r = client_init(servername, 5000, username, &show_message, NULL, &client);

    return r;
}

extern void
show_select_game(void)
{
    GtkCombo *combo;
    GList *gamelist = NULL;

    /*
     * Show the games list window
     */
    gamelist_window = create_gamelistwindow ();
    combo = (GtkCombo *)lookup_widget(gamelist_window, "GameListMenu");

    /*
     * Tell server we want the games list
     */
    client_listgames(client, &gameinfo_cb, &gamelist);
    gtk_combo_set_popdown_strings(combo, gamelist);

    /*
     * show game list window
     */
    gtk_widget_show (gamelist_window);

    
}

void
on_login_button_clicked             (GtkButton       *button,
                                        gpointer         user_data)
{
    GtkEntry *username_entry;
    GtkEntry *servername_entry;
    const char *username;
    const char *servername;
    int r;

    /*
     * Figure out user name
     */
    username_entry = (GtkEntry *)lookup_widget(GTK_WIDGET(button), "username_entry");
    username = gtk_entry_get_text(username_entry);

    /*
     * Figure out server name
     */
    servername_entry = (GtkEntry *)lookup_widget(GTK_WIDGET(button), "server_entry");
    servername = gtk_entry_get_text(servername_entry);

    r = server_connect(username, servername);

    if (r) {
	char msg[1024];
	GtkLabel *errormsg;

	snprintf(msg, sizeof(msg)-1, _("Error connecting to server: %s\n"), servername);

	errormsg = (GtkLabel *)lookup_widget(GTK_WIDGET(button), "newgame_errormsg");
	gtk_label_set_text(errormsg, msg);
	return;
    }

    /*
     * Hide the newgame window now
     */
    gtk_widget_hide (newgame_window);
    newgame_window = NULL;

    show_select_game();
}

void
on_population_report_activate          (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    if (!popreport_window) {
	popreport_window = create_popreport_window();
	setup_population_treeview(popreport_window);
    }

    update_population_report(popreport_window, client);
    gdk_window_raise(popreport_window->window);
}


void
on_popreport_okbutton_clicked          (GtkButton       *button,
                                        gpointer         user_data)
{
    gtk_widget_hide (popreport_window);
    popreport_window = NULL;
}

void
on_finances_activate                   (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    if (!finances_window) {
	finances_window = create_Finances();

	setup_finances_treeview(finances_window);
	setup_loans_treeview(finances_window);
    }

    update_finances_window(finances_window, client);
    gdk_window_raise(finances_window->window);
}

void
on_fastest1_activate                   (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    if (!block_speed_cb) {
	client_setspeed(client, SPEED_FASTEST);
    }
}


void
on_fast1_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    if (!block_speed_cb) {
	client_setspeed(client, SPEED_FAST);
    }
}


void
on_normal1_activate                    (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    if (!block_speed_cb) {
	client_setspeed(client, SPEED_NORMAL);
    }
}


void
on_slow1_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    if (!block_speed_cb) {
	client_setspeed(client, SPEED_SLOW);
    }
}


void
on_paused1_activate                    (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    if (!block_speed_cb) {
	client_setspeed(client, SPEED_PAUSED);
    }
}

void
on_info_okay_buttom_clicked            (GtkButton       *button,
                                        gpointer         user_data)
{
    gtk_widget_hide (info_window);
}


void
on_borrow_button_clicked               (GtkButton       *button,
                                        gpointer         user_data)
{
    GtkEntry *entry;
    const char *amount_str;
    int amount;
    char *next;

    entry = (GtkEntry *)lookup_widget(finances_window, "borrow_amount");

    amount_str = gtk_entry_get_text(entry);

    amount = strtoul(amount_str, &next, 10);
    if ((amount < 0) || (amount > 999999999) || (*next)) {
	printf(_("Invalid amount\n"));
	return;
    }

    client_borrow(client, amount);

    gtk_entry_set_text(entry, "");

    update_finances_window(finances_window, client);
}


gboolean
on_maindrawingarea_leave_notify_event  (GtkWidget       *widget,
                                        GdkEventCrossing *event,
                                        gpointer         user_data)
{
    int x, y;
    GdkModifierType state;
    int mapx, mapy;

    /* release any buttons */
    mousepressed = 0;

    gdk_window_get_pointer (widget->window, &x, &y, &state);

    if (screen_to_mapcoord(screen, x, y, &mapx, &mapy) == 0) {

	set_cursor(mapx, mapy);
    }

    return FALSE;
}

static void
update_label(GtkLabel *label, char *str)
{
    int cnt = 0;

    gtk_label_set_text(label, str);

    while (gtk_events_pending() && cnt < 100) {
	gtk_main_iteration_do(FALSE);
	cnt++;
    }
}

static void *
loadimage_cb(char *filename, 
	     int request_width, int request_height,
	     int *extra_height, 
	     void *rock)
{
#if 0
    char buf[128];
    snprintf(buf, sizeof(buf)-1,_("Loading tile: %s"), filename);
    update_label((GtkLabel *)rock, buf);
#endif /* 0 */

    return sdlwin_loadimage(filename,
			    request_width, request_height,
			    extra_height, NULL);
}

extern int
select_game(const char *game)
{
    GtkLabel *loadlabel;
    GtkWidget *load_dialog;

    timeout_remove();
    
    memset(&display, 0, sizeof(display_t));
    display.grid = 1;
    display.view = GAMEVIEW_NORMAL;
    display.showbuildings = 1;

    load_dialog = create_load_dialog();
    gtk_widget_show_all (load_dialog);

    loadlabel = (GtkLabel *)lookup_widget(load_dialog, "load_status_label");

    update_label(loadlabel, _("Contacting server"));

    client_selectgame(client, game);

    update_label(loadlabel, _("Loading tiles"));

    if (!tiles) {
	if (tiles_init(&tiles, "../img/tiles.data", &loadimage_cb, loadlabel)) {
	    if (tiles_init(&tiles, IMG_DIRECTORY "tiles.data",
			   &loadimage_cb, loadlabel)) {
		printf(_("Error initializing tiles\n"));
		exit(1);
	    }
	}
    }

    /*
     * Get game data from server
     */
    update_label(loadlabel, _("Getting map"));
    map = client_getmap(client, tiles);
    screen_setmap(screen, map);
    me = client_getme(client);
    updatemoney();

    set_current_activity("Road");

    /* show the goal */
    on_menu_report_goal_activate(NULL, NULL);

    gtk_widget_destroy(load_dialog);

    timeout_add();

    return 0;
}

static void
show_message(char *msg, void *rock)
{
    GtkTextView *textbox;
    GtkTextBuffer *buffer;
    int len;

    if (!textdisp_window) {
	textdisp_window = create_textdisp_window();
    }

    textbox = (GtkTextView *)lookup_widget(textdisp_window, "textdisp_textbox");
    if (!textbox) return;


    buffer = gtk_text_buffer_new(NULL);
    gtk_text_buffer_set_text(buffer, msg, -1);

    gtk_text_view_set_buffer(textbox, buffer);
    gtk_widget_show (textdisp_window);    
    gdk_window_raise(textdisp_window->window);
}

void
on_menu_report_goal_activate           (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    char *goal = client_getgoal(client);
    
    show_message(goal, NULL);
}

void
on_payoff_button_clicked               (GtkButton       *button,
                                        gpointer         user_data)
{
    GtkTreeIter iter;
    GtkTreeView *loanview;
    GtkTreeModel *model;
    GtkTreeSelection *selection;
    int num = 0;

    loanview = (GtkTreeView *)lookup_widget(finances_window, "loansview");
    selection = gtk_tree_view_get_selection(loanview);
    if (!selection) return;

    gtk_tree_selection_get_selected(selection,
				    &model,
				    &iter);

    gtk_tree_model_get(model, &iter, 0, &num, -1);

    client_payoff_loan(client, num);

    update_finances_window(finances_window, client);
}

void
on_popreport_window_remove             (GtkContainer    *container,
                                        GtkWidget       *widget,
                                        gpointer         user_data)
{
    popreport_window = NULL;
}


void
on_Finances_remove                     (GtkContainer    *container,
                                        GtkWidget       *widget,
                                        gpointer         user_data)
{
    finances_window = NULL;
}



void
on_stats_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    if (!stats_window) {
	stats_window = create_stats_window();
	setup_stats_treeview(stats_window);
    }

    update_stats_window(stats_window, client);
    gdk_window_raise(stats_window->window);
}


void
on_stats_okay_buttom_clicked           (GtkButton       *button,
                                        gpointer         user_data)
{
    gtk_widget_hide (stats_window);
    stats_window = NULL;
}


void
on_zoom_in1_activate                   (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    zoom(1);
}


void
on_zoom_out1_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    zoom(-1);
}


void
on_rotate1_activate                    (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    int mapx;
    int mapy;

    screen_to_mapcoord_screen_center(screen, &mapx, &mapy);

    screen_rotate(screen, 1);

    recenter_screen(drawingareawidget, screen, map, mapx, mapy);
}


void
on_buy_land1_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity_obj(MAPOBJ_ACTION_BUYLAND);
    government_enable_landvalue_cache(map);
}


void
on_zone_housing1_activate              (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("ZoneHouse");
}


void
on_zone_office1_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("ZoneOffice");
}


void
on_zone_industrial1_activate           (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("ZoneIndustrial");
}


void
on_zone_commercial1_activate           (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("ZoneCommercial");
}


void
on_zone_farm1_activate                 (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("ZoneFarm");
}


void
on_road2_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Road");
}


void
on_trees1_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Trees");
}


void
on_park1_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Park");
}


void
on_pool1_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Pool");
}


void
on_fire_station1_activate              (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("FireStation");
}

static void
getrate(char *name)
{
    int rate;
    GtkSpinButton *spin;
    char spin_name[100];

    rate = client_gettaxrate(client, name);

    snprintf(spin_name, sizeof(spin_name)-1,"%stax_control", name);
    spin = (GtkSpinButton *)lookup_widget(taxes_window, spin_name);
    if (!spin) {
	printf(_("Error find spincontrol named %s\n"), spin_name);
	return;
    }

    gtk_spin_button_set_value(spin, rate);
}

static void
setrate(char *name)
{
    int rate;
    GtkSpinButton *spin;
    char spin_name[100];

    snprintf(spin_name, sizeof(spin_name)-1,"%stax_control", name);
    spin = (GtkSpinButton *)lookup_widget(taxes_window, spin_name);

    if (!spin) {
	printf(_("Error find spincontrol named %s\n"), spin_name);
	return;
    }

    rate = gtk_spin_button_get_value_as_int(spin);

    client_settaxrate(client, name, rate);
}

void
on_tax_rates_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    int i;

    if (!taxes_window) {
	taxes_window = create_taxes_window();
    }

    for (i = 0; i < NUM_TAX_TYPES; i++) {
	getrate(tax_types[i]);
    }

    gtk_widget_show (taxes_window);    
    gdk_window_raise(taxes_window->window);
}

void
on_taxes_okbutton_clicked              (GtkButton       *button,
                                        gpointer         user_data)
{
    int i;

    for (i = 0; i < NUM_TAX_TYPES; i++) {
	setrate(tax_types[i]);
    }

    gtk_widget_hide (taxes_window);
    taxes_window = NULL;
}


void
on_buy_all1_activate                   (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity_obj(MAPOBJ_ACTION_BUYALL);
    government_enable_landvalue_cache(map);
}


void
on_sell1_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity_obj(MAPOBJ_ACTION_SELLLAND);
    government_enable_landvalue_cache(map);
}


void
on_demolish1_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity_obj(MAPOBJ_ACTION_DEMOLISH);
}

static void
setgameview(int view)
{
    display.view = view;
    screen_moved = 1;
}

void
on_menu_normal_view_activate           (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    setgameview(GAMEVIEW_NORMAL);
}


void
on_menu_owner_view_activate            (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    setgameview(GAMEVIEW_OWNERS);
}

void
on_police_coverage1_activate           (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    setgameview(GAMEVIEW_POLICE_COVER);
}

void
on_hospital_coverage1_activate         (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    setgameview(GAMEVIEW_HOSPITAL_COVER);
}


void
on_fire_station_coverage1_activate     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    setgameview(GAMEVIEW_FIRE_COVER);
}

void
on_menu_mine_view_activate             (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    setgameview(GAMEVIEW_MINE);
}



void
on_show_buildings_activate             (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    display.showbuildings = !display.showbuildings;
}



void
on_gamelistwindow_remove               (GtkContainer    *container,
                                        GtkWidget       *widget,
                                        gpointer         user_data)
{
    gtk_widget_hide (gamelist_window);
    gamelist_window = NULL;
}


void
on_textdisp_window_remove                  (GtkContainer    *container,
                                        GtkWidget       *widget,
                                        gpointer         user_data)
{
    gtk_widget_hide (textdisp_window);
    textdisp_window = NULL;
}


void
on_stats_window_remove                 (GtkContainer    *container,
                                        GtkWidget       *widget,
                                        gpointer         user_data)
{
    gtk_widget_hide (stats_window);
    stats_window = NULL;
}


void
on_happiness_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    char *msg = client_gethappiness(client);
    
    show_message(msg, NULL);
}


void
on_flatten_activate                    (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity_obj(MAPOBJ_ACTION_FLATTEN);
}


void
on_raise_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity_obj(MAPOBJ_ACTION_RAISE);
}


void
on_lower_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity_obj(MAPOBJ_ACTION_LOWER);
}


void
on_golf_course1_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Golf");
}

void
on_localserverbutton_clicked           (GtkButton       *button,
                                        gpointer         user_data)
{
    /*
     * Try starting local server
     */
    start_local_server();

}


void
on_info_window_remove                  (GtkContainer    *container,
                                        GtkWidget       *widget,
                                        gpointer         user_data)
{
    gtk_widget_hide (info_window);
    info_window = NULL;
}



void
on_coal_power_plant_activate           (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("PowerCoal");
}


void
on_water_well_activate                 (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Well");
}


void
on_garbage_dump_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("DumpEmpty");
}


void
on_port_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Port");
}


void
on_sewage_treatment_plant_activate     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Sewage");
}


void
on_small_school_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("MiniSchool");
}


void
on_school1_activate                    (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("School");
}


void
on_quick_help_activate                 (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    char *quick_help_msg =
	_("To get your city started:                                                \n"
	"                                                                         \n"
	"1. Build some roads                                                      \n"
	"2. Build a power plant                                                   \n"
	"3. Zone some housing near roads. People should start building houses     \n"
	"4. Zone some commercial, industrial, and office nearby for people to work\n"
	"5. To keep people happy you'll need to provide services: schools, police,\n"
        "     hospital, fire stations, etc.                                       \n"
	"6. Keep track of what's going on with the Reports->Stats window          \n"
	  "\n")
	;

    show_message(quick_help_msg, NULL);
}


void
on_gas_power_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("PowerGas");
}


void
on_well_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Well");
}


void
on_tower_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Tower");
}


void
on_landfill_activate                   (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("DumpEmpty");
}


void
on_sheriff_activate                    (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Sheriff");
}


void
on_police_station_activate             (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Police");
}


void
on_clinic_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Clinic");
}


void
on_hospital_activate                   (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("Hospital");
}


void
on_nuclear_power_plant_activate        (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("PowerNuclear");
}


void
on_university_activate                 (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    set_current_activity("University");
}




void
on_StartGameButton_clicked             (GtkButton       *button,
                                        gpointer         user_data)
{
    GtkCombo *gamelist;
    const char *name;

    gamelist = (GtkCombo *)lookup_widget(gamelist_window, "GameListMenu");

    name = gtk_entry_get_text (GTK_ENTRY (gamelist->entry));
   
    gtk_widget_hide (gamelist_window);
    gamelist_window = NULL;

    select_game(name);
}



void
on_textdisp_okay_button_clicked        (GtkButton       *button,
                                        gpointer         user_data)
{
    gtk_widget_hide(textdisp_window);
}



void
on_finances_okay_button_clicked        (GtkButton       *button,
                                        gpointer         user_data)
{
    gtk_widget_hide (finances_window);
    finances_window = NULL;
}



