/*
*Copyright(c)2018, Jeffrey Lee
*Allrightsreserved.
*
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met: 
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <kernel.h>
#include <swis.h>

//#define DEBUG

#include "limp.h"
#include "../build/VersionNum.sed"

#ifdef DEBUG
FILE *debuglog;
#endif

int wh_xfer_send,wh_proginfo,wh_general,wh_cargo,wh_damage,wh_messages;

void get_save_data();

#include "savegame.c"

int handle_iconbar;

int iconbar_block[] = {	-1, // Icon pos
			0, // Icon block...
			0,
			86,
			68,
			0x301A, // Flags - sprite, h&v centered, button type click with no auto repeat
			0x6E755321, // "!Sun"
			0x6465, // "ed"
			0};

// These structures make menus simpler - just make an anonymous struct, e.g.:
// struct {
// menu_header header;
// menu_item items[3];
// } mymenu;
// For each menu :)

typedef struct
{
	char title[12];
	char title_for_col,title_back_col,work_for_col,work_back_col;
	int width;
	int height;
	int gap;
} menu_header;

typedef struct
{
	int item_flags;
	int submenu;
	int icon_flags;
	union {int i[3];char c[12];} data;
} menu_item;

struct {
	menu_header header;
	menu_item items[3];
} menu_block;

struct {
	menu_header header;
	menu_item items[6];
} class_menu;

struct {
	menu_header header;
	menu_item items[5];
} system_menu;

struct {
	menu_header header;
	menu_item items[4];
} location_menu;

struct {
	menu_header header;
	menu_item items[244]; // Ack!
} name_menu;

int openmenu;

void setup_windows();

void open_menu();

void create_menu();

void start_file_drag();

void stop_file_drag();

void data_save_ack();

void do_class_menu();
void do_ship_name_menu();
void do_system_menu();
void do_location_menu();
void class_menu_select();
void name_menu_select();
void system_menu_select();
void location_menu_select();

void check_esgs();

void open_mainwindow();
void open_cargowindow();
void open_damagewindow();
void open_messageswindow();

int main(int argc,char **argv)
{
	int code;
	int quit;
	int x,y;
	// Init...
#ifdef DEBUG
	debuglog = fopen("<Obey$Dir>.Debug","w");
#endif
	file_open = 0;
	load_shipnames("<SunBurst$Dir>.Disc2.Data.ShipNames");
	Limp_Initialise("SunEd");
	Limp_OpenTemplate("<Obey$Dir>.Templates");
	wh_xfer_send = Limp_LoadTemplate("xfer_send",(void *) -1);
	wh_proginfo = Limp_LoadTemplate("progInfo",(void *) -1);
	wh_general = Limp_LoadTemplate("general",(void *) -1);
	wh_cargo = Limp_LoadTemplate("cargo",(void *) -1);
	wh_damage = Limp_LoadTemplate("damage",(void *) -1);
	wh_messages = Limp_LoadTemplate("messages",(void *) -1);
	Limp_CloseTemplate();
	handle_iconbar = Limp_CreateIcon(0,&iconbar_block);
	create_menu();
	Limp_SetIconText(wh_proginfo,0,"SunEd");
	Limp_SetIconText(wh_proginfo,1,"Editing SunBurst save games");
	Limp_SetIconText(wh_proginfo,2,"Jeffrey Lee");
	Limp_SetIconText(wh_proginfo,3,VersionString);
	// Now main loop
	quit = 0;
	do
	{
		code=Limp_Poll(1+16+32,NULL);
#ifdef DEBUG
		if (code != 2)
			fprintf(debuglog,"Code %d\n",code);
#endif
		switch(code)
		{
		case 1: // Redraw window
#ifdef DEBUG
			fprintf(debuglog,"Window %d needs redrawing...\n",limp.b[0]);
#endif
			Limp_RedrawWindow(limp.b[0]);
			do {} while (Limp_GetRectangle() != 0);
#ifdef DEBUG
			fprintf(debuglog,"Done\n");
#endif
			break;
		case 2: // Open window
			Limp_OpenWindow(limp.b[0],limp.b[1],limp.b[2],limp.b[3],limp.b[4],limp.b[5],limp.b[6],limp.b[7]);
			break;
		case 3: // Close window - just close any for now
				Limp_CloseWindow(limp.b[0]);
			break;
		case 6: // Button click
#ifdef DEBUG
			fprintf(debuglog,"Buttons %d, window %d, icon %d\n",limp.b[2],limp.b[3],limp.b[4]);
#endif
			if (limp.b[2] == 4) // Select
			{
				if (limp.b[3] == -2)
				{
					if (file_open == 1)
						open_mainwindow();
				}
				else if ((limp.b[3] == wh_general) && (limp.b[4] == 78))
					open_cargowindow();
				else if ((limp.b[3] == wh_general) && (limp.b[4] == 79))
					open_damagewindow();
				else if ((limp.b[3] == wh_general) && (limp.b[4] == 100))
					open_messageswindow();
				else if ((limp.b[3] == wh_xfer_send) && (limp.b[4] == 0))
				{
					save_file(Limp_GetIconText(wh_xfer_send,1));
					Limp_CreateMenu((void *) -1,0,0);
				}
				else if ((limp.b[3] == wh_general) && (limp.b[4] == 74))
					do_class_menu();
				else if ((limp.b[3] == wh_general) && (limp.b[4] == 77))
					do_ship_name_menu();
				else if ((limp.b[3] == wh_general) && (limp.b[4] == 83))
					do_system_menu();
				else if ((limp.b[3] == wh_general) && (limp.b[4] == 89))
					do_location_menu();
			}
			else if (limp.b[2] == 2) // Menu
				open_menu();
			else if (limp.b[2] == 64) // Drag
			{
				if ((limp.b[3] == wh_xfer_send) && (limp.b[4] == 2))
					start_file_drag();
			}
			else if (limp.b[2] == 1) // Adjust
				if (limp.b[3] == wh_general)
					check_esgs(); // Possibility they have deselected an ESG...
			break;
		case 7: // User drag box finish
			stop_file_drag();
			break;
		case 8: // Key pressed
#ifdef DEBUG
			fprintf(debuglog,"Window %d, icon %d, key %d\n",limp.b[0],limp.b[1],limp.b[6]);
#endif
			if ((limp.b[0] == wh_general) && ((limp.b[1] == 84) || (limp.b[1] == 86)))
			{ // Changed the ship location...
				x = atoi(Limp_GetIconText(wh_general,84));
				y = atoi(Limp_GetIconText(wh_general,86));
				if (x > 63)
				{
					Limp_SetIconText(wh_general,84,"63");
					x = 63;
				}
				if (y > 63)
				{
					Limp_SetIconText(wh_general,86,"63");
					y = 63;
				}
				ship_x = x;
				ship_y = y;
				Limp_SetIconText(wh_general,88,decode_ship_location());
			}
			else if (limp.b[0] == wh_damage)
			{
				Limp_SetIconText(wh_damage,limp.b[1]+1,decode_damage(atoi(Limp_GetIconText(wh_damage,limp.b[1])))); // Assume it was from a text box (And that atoi("") returns 0...)
			}
			else if (limp.b[0] == wh_general)
			{
				if (limp.b[1] == 93)
				{
					if (atoi(Limp_GetIconText(wh_general,93)) > 100)
						Limp_SetIconText(wh_general,93,"100");
				}
				else if (limp.b[1] == 95)
				{
					if (atoi(Limp_GetIconText(wh_general,95)) > 30)
						Limp_SetIconText(wh_general,95,"30");
				}
				else if (atoi(Limp_GetIconText(wh_general,limp.b[1])) > 255)
					Limp_SetIconText(wh_general,limp.b[1],"255"); // Missile boxes
			}
			else if (limp.b[0] == wh_cargo)
			{
				// Assume it's from the cargo boxes...
				if (atoi(Limp_GetIconText(wh_cargo,limp.b[1])) > 255)
					Limp_SetIconText(wh_cargo,limp.b[1],"255");
			}
			else if ((limp.b[0] == wh_xfer_send) && (limp.b[6] == 13))
			{
				save_file(Limp_GetIconText(wh_xfer_send,1));
				Limp_CreateMenu((void *) -1,0,0);
			}
			break;
		case 9: // Menu selection
#ifdef DEBUG
			fprintf(debuglog,"Menu item %d\n",limp.b[0]);
#endif
			if (openmenu == 1)
			{
				if (limp.b[0] == 2)
					quit = 1;
			}
			else if (openmenu == 2)
				class_menu_select();
			else if (openmenu == 3)
				name_menu_select();
			else if (openmenu == 4)
				system_menu_select();
			else if (openmenu == 5)
				location_menu_select();
			break;
		case 17: // User message
		case 18: // More user messages
#ifdef DEBUG
			fprintf(debuglog,"Message &%X\n",limp.b[4]);
#endif
			if (limp.b[4] == 0) // Quit
				quit = 1;
			else if (limp.b[4] == 2) // Data save ack
				data_save_ack();
			else if (limp.b[4] == 3) // Data load
			{
				if (limp.b[10] == 0x7DB) // Sunburst
				{
					game_loadfile();
					setup_windows();
					open_mainwindow();
					menu_block.items[1].icon_flags = 0x7000021; // Make the save menu availabe
				}
			}
			break;
		}
	}
	while (quit == 0);
#ifdef DEBUG
	fclose(debuglog);
#endif
	Limp_CloseDown();
	return 0;
}

void set_icon_number(int w,int h,int n)
{
	char t[32];
	_kernel_swi_regs regs;
	regs.r[0]=n;
	regs.r[1]=(int) t;
	regs.r[2]=32;
	_kernel_swi(OS_ConvertInteger4,&regs,&regs);
	Limp_SetIconText(w,h,t);
}

void setup_windows()
{
	int a;
	// Set the values for the windows...
	// Misc items...
	Limp_SetIconState(wh_general,19,0x200000*get_cloaked_ship_detector(),0x200000);
	Limp_SetIconState(wh_general,21,0x200000*get_cloak(),0x200000);
	Limp_SetIconState(wh_general,22,0x200000*get_auto_tracker(),0x200000);
	Limp_SetIconState(wh_general,23,0x200000*get_sound_monitor(),0x200000);
	Limp_SetIconState(wh_general,24,0x200000*get_windows(),0x200000);
	Limp_SetIconState(wh_general,25,0x200000*get_auto_pilot(),0x200000);
	Limp_SetIconState(wh_general,26,0x200000*get_attractor(),0x200000);
	Limp_SetIconState(wh_general,27,0x200000*get_repair_upgrade(),0x200000);
	// ESG's...
	// Have to clear all the icons first :(
	// Make a new Limp command...
	Limp_SelectESGIcon(wh_general,1,31+get_weapon_power(),4);
	Limp_SelectESGIcon(wh_general,2,36+get_firing_rate(),4);
	Limp_SelectESGIcon(wh_general,3,41+get_shields(),4);
	Limp_SelectESGIcon(wh_general,4,46+get_rotation_speed(),4);
	Limp_SelectESGIcon(wh_general,5,51+get_acceleration(),4);
	Limp_SelectESGIcon(wh_general,6,56+get_top_speed(),4);
	Limp_SelectESGIcon(wh_general,7,61+get_power_generator(),4);
	Limp_SelectESGIcon(wh_general,8,66+get_ecm(),4);
	Limp_SelectESGIcon(wh_general,9,96+selected_missile,4);
	// Numbers....
	set_icon_number(wh_general,2,kills);
	set_icon_number(wh_general,3,level);
	set_icon_number(wh_general,5,credits);
	set_icon_number(wh_general,7,jump_speed);
	set_icon_number(wh_general,9,missiles_red);
	set_icon_number(wh_general,11,missiles_yellow);
	set_icon_number(wh_general,13,missiles_green);
	set_icon_number(wh_general,15,missiles_blue);
	set_icon_number(wh_general,17,debt);
	set_icon_number(wh_general,84,ship_x);
	set_icon_number(wh_general,86,ship_y);
	set_icon_number(wh_general,93,shield_charge);
	set_icon_number(wh_general,95,laser_charge);
	// Text...
	Limp_SetIconText(wh_general,73,decode_ship_class());
	Limp_SetIconText(wh_general,76,ship_names[ship_name-names_memory]);
	Limp_SetIconText(wh_general,82,decode_ship_system());
	Limp_SetIconText(wh_general,88,decode_ship_location());
	// Now the cargo
	// Use a loop to fill in the cargo values
	set_icon_number(wh_cargo,0,cargo_size);
	for (a=0;a<11;a++)
	{
		set_icon_number(wh_cargo,44-(4*a),game.c[688+a]);
		set_icon_number(wh_cargo,46-(4*a),game.c[699+a]);
	}
	set_icon_number(wh_cargo,2,cargo_cloth);
	// Now the damage
	set_icon_number(wh_damage,1,life_support_damage);
	set_icon_number(wh_damage,4,engine_damage);
	set_icon_number(wh_damage,7,weapons_damage);
	set_icon_number(wh_damage,10,targeting_damage);
	set_icon_number(wh_damage,13,scanner_damage);
	set_icon_number(wh_damage,16,ecm_damage);
	set_icon_number(wh_damage,19,cloak_damage);
	// Now text
	Limp_SetIconText(wh_damage,2,decode_damage(life_support_damage));
	Limp_SetIconText(wh_damage,5,decode_damage(engine_damage));
	Limp_SetIconText(wh_damage,8,decode_damage(weapons_damage));
	Limp_SetIconText(wh_damage,11,decode_damage(targeting_damage));
	Limp_SetIconText(wh_damage,14,decode_damage(scanner_damage));
	Limp_SetIconText(wh_damage,17,decode_damage(ecm_damage));
	Limp_SetIconText(wh_damage,20,decode_damage(cloak_damage));
	// Messages...
	// Use a loop
	for (a=0;a<19;a++)
		Limp_SetIconState(wh_messages,a,0x200000*(game.c[429+a] == 1),0x200000);
	// Hyang/shipping list
	Limp_SetIconState(wh_messages,19,0x200000*(game.c[448] & 1),0x200000);
	Limp_SetIconState(wh_messages,20,0,0x200000);
	Limp_SetIconState(wh_messages,21,0,0x200000);
	Limp_SetIconState(wh_messages,22,0,0x200000);
	Limp_SetIconState(wh_messages,23,0,0x200000);
	Limp_SetIconState(wh_messages,24,0,0x200000);
	a = 0;
	if ((game.c[448] & 0xFE) == 10)
		a = 20;
	else if ((game.c[448] & 0xFE) == 20)
		a = 21;
	else if ((game.c[448] & 0xFE) == 30)
		a = 22;
	else if ((game.c[448] & 0xFE) == 40)
		a = 23;
	else if ((game.c[448] & 0xFE) == 50)
		a = 24;
	if (a != 0)
		Limp_SetIconState(wh_messages,a,0x200000,0x200000);
	// More messages
	for (a=0;a<12;a++)
		Limp_SetIconState(wh_messages,a+25,0x200000*(game.c[449+a] == 1),0x200000);
	// Spike status
	Limp_SetIconState(wh_messages,37,0,0x200000);
	Limp_SetIconState(wh_messages,38,0,0x200000);
	Limp_SetIconState(wh_messages,39,0,0x200000);
	Limp_SetIconState(wh_messages,40,0,0x200000);
	a = 0;
	if ((game.c[461] & 0xFE) == 10)
		a = 37;
	else if ((game.c[461] & 0xFE) == 20)
		a = 38;
	else if ((game.c[461] & 0xFE) == 30)
		a = 39;
	else if ((game.c[461] & 0xFE) == 40)
		a = 40;
	if (a != 0)
		Limp_SetIconState(wh_messages,a,0x200000,0x200000);
	Limp_SetIconState(wh_messages,41,0x200000*(game.c[461] & 1),0x200000);
	// More messages
	for (a=0;a<16;a++)
		Limp_SetIconState(wh_messages,a+42,0x200000*(game.c[462+a] == 1),0x200000);
}

void get_save_data()
{
	int a;
	// Start with the number values...
	kills = atoi(Limp_GetIconText(wh_general,2));
	level = atoi(Limp_GetIconText(wh_general,3));
	credits = atoi(Limp_GetIconText(wh_general,5));
	jump_speed = atoi(Limp_GetIconText(wh_general,7));
	missiles_red = atoi(Limp_GetIconText(wh_general,9));
	missiles_yellow = atoi(Limp_GetIconText(wh_general,11));
	missiles_green = atoi(Limp_GetIconText(wh_general,13));
	missiles_blue = atoi(Limp_GetIconText(wh_general,15));
	debt = atoi(Limp_GetIconText(wh_general,17));
	shield_charge = atoi(Limp_GetIconText(wh_general,93));
	laser_charge = atoi(Limp_GetIconText(wh_general,95));
	// Cargo...
	cargo_size = atoi(Limp_GetIconText(wh_cargo,0));
	for (a=0;a<11;a++)
	{
		game.c[688+a] = atoi(Limp_GetIconText(wh_cargo,44-(4*a)));
		game.c[699+a] = atoi(Limp_GetIconText(wh_cargo,46-(4*a)));
	}
	cargo_cloth = atoi(Limp_GetIconText(wh_cargo,2));
	life_support_damage = atoi(Limp_GetIconText(wh_damage,1));
	engine_damage = atoi(Limp_GetIconText(wh_damage,4));
	weapons_damage = atoi(Limp_GetIconText(wh_damage,7));
	targeting_damage = atoi(Limp_GetIconText(wh_damage,10));
	scanner_damage = atoi(Limp_GetIconText(wh_damage,13));
	ecm_damage = atoi(Limp_GetIconText(wh_damage,16));
	cloak_damage = atoi(Limp_GetIconText(wh_damage,19));
	// Misc items...
	Limp_GetIconState(wh_general,19);
	set_cloaked_ship_detector((limp.b[6] & 0x200000)>>21);
	Limp_GetIconState(wh_general,21);
	set_cloak((limp.b[6] & 0x200000)>>21);
	Limp_GetIconState(wh_general,22);
	set_auto_tracker((limp.b[6] & 0x200000)>>21);
	Limp_GetIconState(wh_general,23);
	set_sound_monitor((limp.b[6] & 0x200000)>>21);
	Limp_GetIconState(wh_general,24);
	set_windows((limp.b[6] & 0x200000)>>21);
	Limp_GetIconState(wh_general,25);
	set_auto_pilot((limp.b[6] & 0x200000)>>21);
	Limp_GetIconState(wh_general,26);
	set_attractor((limp.b[6] & 0x200000)>>21);
	Limp_GetIconState(wh_general,27);
	set_repair_upgrade((limp.b[6] & 0x200000)>>21);
	// ESG's...
	set_weapon_power(Limp_GetSelectedESGIcon(wh_general,1)-31);
	set_firing_rate(Limp_GetSelectedESGIcon(wh_general,2)-36);
	set_shields(Limp_GetSelectedESGIcon(wh_general,3)-41);
	set_rotation_speed(Limp_GetSelectedESGIcon(wh_general,4)-46);
	set_acceleration(Limp_GetSelectedESGIcon(wh_general,5)-51);
	set_top_speed(Limp_GetSelectedESGIcon(wh_general,6)-56);
	set_power_generator(Limp_GetSelectedESGIcon(wh_general,7)-61);
	set_ecm(Limp_GetSelectedESGIcon(wh_general,8)-66);
	selected_missile = Limp_GetSelectedESGIcon(wh_general,9)-96;
	// Ship class, name and system are updated whenever they are changed
	// Messages...
	for (a=0;a<19;a++)
	{
		Limp_GetIconState(wh_messages,a);
		game.c[429+a]=(limp.b[6] & 0x200000)>>21;
	}
	Limp_GetIconState(wh_messages,19);
	a = (limp.b[6] & 0x200000)>>21;
	Limp_GetIconState(wh_messages,24);
	if (limp.b[6] & 0x200000)
		a = a + 50;
	else
	{
		Limp_GetIconState(wh_messages,23);
		if (limp.b[6] & 0x200000)
			a = a + 40;
		else
		{
			Limp_GetIconState(wh_messages,22);
			if (limp.b[6] & 0x200000)
				a = a + 30;
			else
			{
				Limp_GetIconState(wh_messages,21);
				if (limp.b[6] & 0x200000)
					a = a + 20;
				else
				{
					Limp_GetIconState(wh_messages,20);
					if (limp.b[6] & 0x200000)
						a = a + 10;
				}
			}
		}
	}
	game.c[448] = a;
	for (a=0;a<12;a++)
	{
		Limp_GetIconState(wh_messages,a+25);
		game.c[449+a]=(limp.b[6] & 0x200000)>>21;
	}
	Limp_GetIconState(wh_messages,41);
	a = (limp.b[6] & 0x200000)>>21;
	Limp_GetIconState(wh_messages,40);
	if (limp.b[6] & 0x200000)
		a = a + 40;
	else
	{
		Limp_GetIconState(wh_messages,39);
		if (limp.b[6] & 0x200000)
			a = a + 30;
		else
		{
			Limp_GetIconState(wh_messages,38);
			if (limp.b[6] & 0x200000)
				a = a + 20;
			else
			{
				Limp_GetIconState(wh_messages,37);
				if (limp.b[6] & 0x200000)
					a = a + 10;
			}
		}
	}
	game.c[461] = a;
	for (a=0;a<16;a++)
	{
		Limp_GetIconState(wh_messages,a+42);
		game.c[462+a]=(limp.b[6] & 0x200000)>>21;
	}
}

void open_menu()
{
	int x,y; // Screen pos
	x = limp.b[0]-64;
	if (limp.b[3] == -2)
		y = 96+(44*3);
	else
		y = limp.b[1] + 44;
#ifdef DEBUG
	fprintf(debuglog,"Creating main menu at %d,%d\n",x,y);
#endif
	Limp_CreateMenu(&menu_block,x,y);
	openmenu = 1; // Main menu
}

void enter_header(menu_header *m,char *title)
{
	strcpy(m->title,title);
	m->title_for_col = 7;
	m->title_back_col = 2;
	m->work_for_col = 7;
	m->work_back_col = 0;
	m->width = (strlen(title)-1)*16;
	m->height = 44;
	m->gap = 0;
}

void enter_item(menu_header *m,menu_item *i,int itemf,int sub,int iconf,char *name)
{
	i->item_flags = itemf;
	i->submenu = sub;
	if (strlen(name) > 12)
	{
		// Indirected...
		i->icon_flags = iconf | 256;
		i->data.i[0] = (int) name;
		i->data.i[1] = 0;
		i->data.i[2] = strlen(name);
		if ((i->data.i[2]-1)*16 > m->width)
			m->width = (i->data.i[2]-1)*16;
	}
	else if (strlen(name) == 12)
	{
		// Make sure terminator is not copied
		i->icon_flags = iconf;
		strncpy(i->data.c,name,12);
		if (176 > m->width)
			m->width = 176;
	}
	else
	{
		// Normal
		i->icon_flags = iconf;
		strcpy(i->data.c,name);
		if ((i->data.i[2]-1)*16 > m->width)
			m->width = (i->data.i[2]-1)*16;
	}
}

void create_menu()
{
	int a;
	enter_header(&menu_block.header,"SunEd");
	enter_item(&menu_block.header,&menu_block.items[0],0,wh_proginfo,0x7000021,"Info");
	enter_item(&menu_block.header,&menu_block.items[1],0,wh_xfer_send,0x7400021,"Save");
	enter_item(&menu_block.header,&menu_block.items[2],128,-1,0x7000021,"Quit");
	// Class menu...
	enter_header(&class_menu.header,"Ship class");
	enter_item(&class_menu.header,&class_menu.items[0],0,-1,0x7000021,"Shuttle");
	enter_item(&class_menu.header,&class_menu.items[1],0,-1,0x7000021,"Sirius");
	enter_item(&class_menu.header,&class_menu.items[2],0,-1,0x7000021,"Wing");
	enter_item(&class_menu.header,&class_menu.items[3],0,-1,0x7000021,"Nova");
	enter_item(&class_menu.header,&class_menu.items[4],0,-1,0x7000021,"Kosmos");
	enter_item(&class_menu.header,&class_menu.items[5],128,-1,0x7000021,"Magnx");
	// System menu...
	enter_header(&system_menu.header,"Ship system");
	enter_item(&system_menu.header,&system_menu.items[0],0,-1,0x7000021,"Virain");
	enter_item(&system_menu.header,&system_menu.items[1],0,-1,0x7000021,"Imperial");
	enter_item(&system_menu.header,&system_menu.items[2],0,-1,0x7000021,"Poliniss");
	enter_item(&system_menu.header,&system_menu.items[3],0,-1,0x7000021,"Void");
	enter_item(&system_menu.header,&system_menu.items[4],128,-1,0x7000021,"Alien");
	// Location menu...
	// Just enter blank names for now
	enter_header(&location_menu.header,"Location");
	enter_item(&location_menu.header,&location_menu.items[0],0,-1,0x7000021,"Home Station"); // Longest name
	enter_item(&location_menu.header,&location_menu.items[1],0,-1,0x7000021," ");
	enter_item(&location_menu.header,&location_menu.items[2],0,-1,0x7000021," ");
	enter_item(&location_menu.header,&location_menu.items[3],128,-1,0x7000021," ");
	// Name menu...
	enter_header(&name_menu.header,"Ship name");
	for (a=0;a<244;a++)
		enter_item(&name_menu.header,&name_menu.items[a],0,-1,0x7000021,ship_names[a]);
	name_menu.header.width +=64; // Make it 4 chars wider to account for all the caps
	name_menu.items[243].item_flags = 128;
}

void start_file_drag()
{
	int ox,oy;
	Limp_GetWindowState(wh_xfer_send); // I'm not 100% sure what this code does, but it works ;)
	ox=limp.b[1]-limp.b[5];
	oy=limp.b[4]-limp.b[6];
	Limp_GetIconState(wh_xfer_send,2);
	limp.b[0]=wh_xfer_send;
	limp.b[1]=5; // Drag type 5
	limp.b[2]=limp.b[2]+ox;
	limp.b[3]=limp.b[3]+oy;
	limp.b[4]=limp.b[4]+ox;
	limp.b[5]=limp.b[5]+oy;
	limp.b[6]=0;
	limp.b[7]=0;
	limp.b[8]=0x7FFFFFFF;
	limp.b[9]=0x7FFFFFFF;
	Limp_DragBox(&limp.b);
}

void stop_file_drag()
{
	int x,y,w,h;
	char *p;
	char *op;
	// Send datasave message...
	Limp_GetPointerInfo();
	x=limp.b[0];
	y=limp.b[1];
	w=limp.b[3];
	h=limp.b[4];
	if ((w == wh_xfer_send) || (w == wh_proginfo) || (w == wh_general) || (w == wh_cargo) || (w == wh_damage) || (w == wh_messages))
		return; // Bah! dragged to one of our own windows!
	// Need to get file leafname...
	p = Limp_GetIconText(wh_xfer_send,1);
	do
	{
		op = p;
		p = strchr(op,'.'); // Find the next '.'
		if (p != NULL)
			p++; // Skip char
	}
	while (p != NULL);
#ifdef DEBUG
	fprintf(debuglog,"Leafname as %s\n",op);
#endif
	// Now copy the leafname from op
	limp.b[0]=45+strlen(op); // 44 for message, string length, terminator
	limp.b[0]=(limp.b[0]+3); // Add 3 bytes...
	limp.b[0]=limp.b[0] - (limp.b[0] & 3); // And clear bottom 2 bits to round up to nearest word
	limp.b[1]=0;
	limp.b[2]=0;
	limp.b[3]=0; // Your ref
	limp.b[4]=1; // Data save
	limp.b[5]=w;
	limp.b[6]=h;
	limp.b[7]=x;
	limp.b[8]=y;
	limp.b[9]=888;
	limp.b[10]=0x7DB;
	strcpy((char *) &limp.b[11],op);
#ifdef DEBUG
	fprintf(debuglog,"Outgoing message block dump:\n");
	fprintf(debuglog,"Length %d, sender %d, my ref %d, your ref %d, code %d\n",limp.b[0],limp.b[1],limp.b[2],limp.b[3],limp.b[4]);
	fprintf(debuglog,"Dest window %d, icon %d, x %d, y %d\n",limp.b[5],limp.b[6],limp.b[7],limp.b[8]);
	fprintf(debuglog,"Size %d, type %X, pathname %s\n",limp.b[9],limp.b[10],(char *) &limp.b[11]);
	fprintf(debuglog,"End word is %X, next is %X\n",limp.b[(limp.b[0]/4)-1],limp.b[limp.b[0]/4]);
#endif
	Limp_SendMessage(17,&limp.b,w,h);
}

void data_save_ack()
{
	// We have somewhere to save data to...
#ifdef DEBUG
	fprintf(debuglog,"Incoming message block dump:\n");
	fprintf(debuglog,"Length %d, sender %d, my ref %d, your ref %d, code %d\n",limp.b[0],limp.b[1],limp.b[2],limp.b[3],limp.b[4]);
	fprintf(debuglog,"Dest window %d, icon %d, x %d, y %d\n",limp.b[5],limp.b[6],limp.b[7],limp.b[8]);
	fprintf(debuglog,"Size %d, type %X, pathname %s\n",limp.b[9],limp.b[10],(char *) &limp.b[11]);
	fprintf(debuglog,"End word is %X, next is %X\n",limp.b[(limp.b[0]/4)-1],limp.b[limp.b[0]/4]);
#endif
	save_file((char *) &limp.b[11]);
	// Now update file name
	if (limp.b[9] != -1)
		Limp_SetIconText(wh_xfer_send,1,(char *) &limp.b[11]); // Luckily SetIconText doesn't corrupt limp.b[11] and beyond
	Limp_CreateMenu((void *) -1,0,0); // Close menu
}

void do_class_menu()
{
	// Open the class menu...
	Limp_CreateMenu(&class_menu,limp.b[0]-64,limp.b[1]+44);
	openmenu = 2;
}

void do_ship_name_menu()
{
	Limp_CreateMenu(&name_menu,limp.b[0]-64,limp.b[1]+44);
	openmenu = 3;
}

void do_system_menu()
{
	Limp_CreateMenu(&system_menu,limp.b[0]-64,limp.b[1]+44);
	openmenu = 4;
}

void do_location_menu()
{
	// Fill in values...
	location_menu.items[0].item_flags = 0;
	location_menu.items[2].item_flags = 0;
	if (ship_system == 0)
	{
		strcpy(location_menu.items[0].data.c,"HyperJump");
		strcpy(location_menu.items[1].data.c,"Homeworld");
		strcpy(location_menu.items[2].data.c,"Nebula");
		location_menu.items[2].item_flags = 128; // Last item
	}
	else if (ship_system == 1)
	{
		strcpy(location_menu.items[0].data.c,"Jumpstation");
		strcpy(location_menu.items[1].data.c,"Imperial HQ");
		strcpy(location_menu.items[2].data.c,"Nimbus");
		location_menu.items[2].item_flags = 128;
	}
	else if (ship_system == 2)
	{
		strcpy(location_menu.items[0].data.c,"HyperJump");
		strncpy(location_menu.items[1].data.c,"Home Station",12);
		strcpy(location_menu.items[2].data.c,"Fortress");
		location_menu.items[2].item_flags = 128;
	}
	else if (ship_system == 3)
	{
		strcpy(location_menu.items[0].data.c,"HyperJump");
		strcpy(location_menu.items[1].data.c,"Research1");
		strcpy(location_menu.items[2].data.c,"Oasis");
		strcpy(location_menu.items[3].data.c,"Research2");
		location_menu.items[3].item_flags = 128;
	}
	else if (ship_system == 4)
	{
		strcpy(location_menu.items[0].data.c,"Alien Lab");
		location_menu.items[0].item_flags = 128;
	}
	else
		return; // Don't open for unknown system
	Limp_CreateMenu(&location_menu,limp.b[0]-64,limp.b[1]+44);
	openmenu = 5;
}

void class_menu_select()
{
	ship_type = limp.b[0];
	Limp_SetIconText(wh_general,73,decode_ship_class());
}

void name_menu_select()
{
	ship_name = limp.b[0] + names_memory;
	Limp_SetIconText(wh_general,76,ship_names[ship_name-names_memory]);
}

void system_menu_select()
{
	ship_system = limp.b[0];
	Limp_SetIconText(wh_general,82,decode_ship_system());
	Limp_SetIconText(wh_general,88,decode_ship_location());
}

void location_menu_select()
{
	if (ship_system == 0)
	{
		if (limp.b[0] == 0)
		{
			ship_x = 58;
			ship_y = 60;
		}
		if (limp.b[0] == 1)
		{
			ship_x = 20;
			ship_y = 10;
		}
		if (limp.b[0] == 2)
		{
			ship_x = 10;
			ship_y = 50;
		}
	}
	if (ship_system == 1)
	{
		if (limp.b[0] == 0)
		{
			ship_x = 8;
			ship_y = 32;
		}
		if (limp.b[0] == 1)
		{
			ship_x = 48;
			ship_y = 42;
		}
		if (limp.b[0] == 2)
		{
			ship_x = 40;
			ship_y = 4;
		}
	}
	if (ship_system == 2)
	{
		if (limp.b[0] == 0)
		{
			ship_x = 5;
			ship_y = 8;
		}
		if (limp.b[0] == 1)
		{
			ship_x = 50;
			ship_y = 38;
		}
		if (limp.b[0] == 2)
		{
			ship_x = 10;
			ship_y = 48;
		}
	}
	if (ship_system == 3)
	{
		if (limp.b[0] == 0)
		{
			ship_x = 55;
			ship_y = 57;
		}
		if (limp.b[0] == 1)
		{
			ship_x = 48;
			ship_y = 4;
		}
		if (limp.b[0] == 2)
		{
			ship_x = 20;
			ship_y = 24;
		}
		if (limp.b[0] == 3)
		{
			ship_x = 8;
			ship_y = 48;
		}
	}
	if (ship_system == 4)
	{
		if (limp.b[0] == 0)
		{
			ship_x = 5;
			ship_y = 20;
		}
	}
	set_icon_number(wh_general,84,ship_x);
	set_icon_number(wh_general,86,ship_y);
	Limp_SetIconText(wh_general,88,decode_ship_location());
}

void check_esgs()
{
	if (Limp_GetSelectedESGIcon(wh_general,1) == -1)
		Limp_SelectESGIcon(wh_general,1,31+get_weapon_power(),4); // Reset to original value
	if (Limp_GetSelectedESGIcon(wh_general,2) == -1)
		Limp_SelectESGIcon(wh_general,2,36+get_firing_rate(),4);
	if (Limp_GetSelectedESGIcon(wh_general,3) == -1)
		Limp_SelectESGIcon(wh_general,3,41+get_shields(),4);
	if (Limp_GetSelectedESGIcon(wh_general,4) == -1)
		Limp_SelectESGIcon(wh_general,4,46+get_rotation_speed(),4);
	if (Limp_GetSelectedESGIcon(wh_general,5) == -1)
		Limp_SelectESGIcon(wh_general,5,51+get_acceleration(),4);
	if (Limp_GetSelectedESGIcon(wh_general,6) == -1)
		Limp_SelectESGIcon(wh_general,6,56+get_top_speed(),4);
	if (Limp_GetSelectedESGIcon(wh_general,7) == -1)
		Limp_SelectESGIcon(wh_general,7,61+get_power_generator(),4);
	if (Limp_GetSelectedESGIcon(wh_general,8) == -1)
		Limp_SelectESGIcon(wh_general,8,66+get_ecm(),4);
	if (Limp_GetSelectedESGIcon(wh_general,9) == -1)
		Limp_SelectESGIcon(wh_general,9,96+selected_missile,4);
}

void open_mainwindow()
{
	int x,y,ye;
	_kernel_swi_regs regs;
	// Get current screen size...
	regs.r[0] = -1;
	regs.r[1] = 5;
	_kernel_swi(OS_ReadModeVariable,&regs,&regs);
	ye = regs.r[2];
	regs.r[1] = 12;
	_kernel_swi(OS_ReadModeVariable,&regs,&regs);
	y = regs.r[2] << ye; // Get size in OS units
	x = 100; // 100 units in...
	y = (y+936)/2; // And half way down the screen
	Limp_OpenWindow(wh_general,x,y-936,x+1236,y,0,0,-1);
}

void open_cargowindow()
{
	int x,y;
	Limp_GetWindowState(wh_general);
	x = limp.b[1] + 100;
	y = limp.b[4] - 100; // Get max y, not min y!
	Limp_OpenWindow(wh_cargo,x,y-790,x+770,y,0,0,-1);
}

void open_damagewindow()
{
	int x,y;
	Limp_GetWindowState(wh_general);
	x = limp.b[1] + 100;
	y = limp.b[4] - 100;
	Limp_OpenWindow(wh_damage,x,y-412,x+618,y,0,0,-1);
}

void open_messageswindow()
{
	int x,y;
	Limp_GetWindowState(wh_messages);
	x = limp.b[1] + 100;
	y = limp.b[4] - 100;
	Limp_OpenWindow(wh_messages,x,y-2630,x+836,y,0,0,-1);
}
