/* !Upd8LHSh !Runimage
 *  Musus Umbra, 1997
 * A Desktop re-write of two programs by Stefan Jokisch.
 */

#include "ChooseRes.h"
#include "Query.h"
#include "Extract.h"
#include "Update.h"

#include "Desklib:Core.h"
#include "Desklib:Wimp.h"
#include "Desklib:Template.h"
#include "Desklib:Window.h"
#include "Desklib:Sprite.h"
#include "Desklib:Msgs.h"
#include "Desklib:Event.h"
#include "Desklib:EventMsg.h"
#include "Desklib:Menu.h"
#include "Desklib:Error.h"
#include "Desklib:Screen.h"
#include "Desklib:Handler.h"
#include "Desklib:Icon.h"
#include "Desklib:Resource.h"
#include "Desklib:WimpSWIs.h"
#include "Desklib:Sound.h"
#include "Desklib:File.h"
#include "Desklib:Save.h"
#include "Desklib:SWI.h"
#include "Desklib:Hourglass.h"

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

#define LURKING			1
#define SHERLOCK		2
#define NOGAME			0

#define SRC_GAME		3
#define SRC_CNV			7
#define SRC_CANCEL		8
#define SRC_UPDATE		9


static menu_ptr      bar_menu = 0;
static window_handle inf_win  = 0;
static window_handle upd8_win = 0;

static BOOL got_game = FALSE;
static BOOL got_cnv  = FALSE;
static int game_type = NOGAME;

static char game_name[260];
static char cnv_name[260];

static char *converted = NULL;

static save_saveblock *saveblk = 0;
static window_handle  save_box = 0;

/* Identification of valid story-files */
static struct { int rel; char serial[8]; } lurking  = { 203, "870506" };
static struct { int rel; char serial[8]; } sherlock = {  21, "871214" };

/* Identity of 'patched' story files */
static struct { int rel; char serial[8]; } dlurk    = { 221, "870918" };
static struct { int rel; char serial[8]; } dsher    = {  26, "880127" };

/* Identity of the Amiga Lurking Horror 219 */
static struct { int rel; char serial[8]; } alurk    = { 219, "870912" };

static int lurk_cnv_size = 129944;
static int sher_cnv_size = 190180;


/* To be registered with atexit to automatically delete any scrapfile */
/* we might otherwise leave in !Scrap  								  */
static void cleanup(void)
{
	if ( converted )
	{
		remove(converted);
		converted = NULL;
	}
}


static char *lookup( char *tag )
{
	static char buffer[260];
	if ( !Msgs_Lookup( tag, buffer, 260 ) )
		Error_ReportFatal( 0, "Message tag '%s' not found", tag );
	return buffer;
}



static void saveover( void )
{
	if ( !converted )		/* ie. success */
	{
		Save_ReleaseSaveHandlers( saveblk );
		saveblk = NULL;
		*game_name = *cnv_name = NULL;
		game_type = NOGAME;
		got_game = got_cnv = FALSE;
		Window_Delete(save_box);
		save_box = 0;
	}
	else
	{
		Window_BringToFront(save_box);
	}
}


static BOOL Hnd_FileSave( char *as, void *ref )
{
	FILE *dest;
	os_error *e;

	if ( !rename( converted, as ) )
	{
		converted = NULL;
		saveover();
		return TRUE;
	}

	if ( (dest = fopen( as, "rb" )) != NULL )
	{
		fclose(dest);
		if ( !query_box("err.overwt","err.overwm","err.overwn","err.overwy") )
		{
			return TRUE;
		}
	}


	Hourglass_On();
	e = SWI( 4,0, SWI_OS_FSControl, 26, converted, as, (1<<1)|(1<<7)|(1<<14) );
	Hourglass_Off();

	if ( !e )
	{
		converted = NULL;
		saveover();
		return TRUE;
	}

	Msgs_Report(e->errnum,"err.filesave",e->errmess);
	return TRUE;
}





static BOOL Hnd_AbortSave( event_pollblock *b, void *ref )
{
	Save_ReleaseSaveHandlers( saveblk );
	saveblk = NULL;
	Window_Delete(save_box);
	save_box = 0;
	cleanup();
	return TRUE;
}


static void start_savebox( void )
{
	save_box = Window_Create("save",template_TITLEMIN);
	saveblk = Save_InitSaveWindowHandler( save_box, FALSE, FALSE, FALSE,
		2, 0, -1, 1, Hnd_FileSave, NULL, NULL,
		128<<10, 0x11a, NULL );

	Icon_SetText( save_box, 1, game_type==LURKING ? "Lurk_Upd8":"Shrlk_Upd8" );

	Window_Show( save_box, open_CENTEREDUNDERPOINTER );

	Event_Claim( event_OPEN, save_box, event_ANY, Handler_OpenWindow, NULL );
	/* Mung: */
	Event_Claim( event_CLICK, save_box, 3, Hnd_AbortSave, NULL );
}




static int already_patched( void )
{
	query_box( "err.alreadyt", "err.already", NULL, "err.cancel" );
	return NOGAME;
}

static int wrong_story( void )
{
	query_box( "err.wrongt", "err.wrong", NULL, "err.cancel" );
	return NOGAME;
}

static int amiga_lh( void )
{
	query_box( "err.amigalht", "err.amigalh", NULL, "err.cancel" );
	return NOGAME;
}


static int validate_story(char *filename)
{
	int ehi = extract_header_info(filename);
	switch ( ehi )
	{
		case EXTRACT_OPENERROR :
		case EXTRACT_READERROR :
			Msgs_Report(0,"err.reads",filename);
			return FALSE;
		case EXTRACT_BADHEADER :
			Msgs_Report(0,"err.badstory",filename);
			return FALSE;
		default :
			if ( h_release == lurking.rel )
				if ( !memcmp(h_serial,lurking.serial,6) )
					return LURKING;
			if ( h_release == sherlock.rel )
				if ( !memcmp(h_serial,sherlock.serial,6) )
					return SHERLOCK;
			if ( h_release == dlurk.rel )
				if ( !memcmp(h_serial,dlurk.serial,6) )
					return already_patched();
			if ( h_release == dsher.rel )
				if ( !memcmp(h_serial,dsher.serial,6) )
					return already_patched();
			if ( h_release == alurk.rel )
				if ( !memcmp(h_serial,alurk.serial,6) )
					return amiga_lh();
	}
	return wrong_story();
}


static void do_update(void)
{
	int csize = File_Size( cnv_name );
	if ( csize != (game_type==LURKING ? lurk_cnv_size : sher_cnv_size) )
	{
		query_box( "err.badcnvt", "err.badcnv", NULL, "err.cancel" );
		return;
	}
	Window_Delete( upd8_win );
	upd8_win = 0;

	Hourglass_On();
	if ( game_type == LURKING )
		converted = update_lh( game_name, cnv_name );
	else
		converted = update_sh( game_name, cnv_name );
	Hourglass_Off();

	if ( converted )
	{
		File_SetType(converted,0x11a);
		start_savebox();
	}
	else		/* The update failed! */
	{
		Msgs_Report(0,"err.update",lookup(upd8_err));
	}

}



static BOOL Hnd_DataLoad( event_pollblock *b, void *ref )
{
	int g;
	switch (b->data.message.data.dataload.filetype)
	{
		case 0x11a : /* the story file */
			g = validate_story(b->data.message.data.dataload.filename);
			if ( g==NOGAME ) { return TRUE; }
			game_type = g;
			strcpy( game_name, b->data.message.data.dataload.filename );
			got_game = TRUE;
			Icon_SetText( upd8_win, SRC_GAME, game_name );
			break;
		case 0xffd : /* the conversion file */
			strcpy( cnv_name, b->data.message.data.dataload.filename );
			got_cnv = TRUE;
			Icon_SetText( upd8_win, SRC_CNV, cnv_name );
			break;
		default :
			Sound_SysBeep();
			break;
	}
	Icon_SetShade( upd8_win, SRC_UPDATE, !(got_game && got_cnv) );
	return TRUE;
}


static BOOL Hnd_Upd8Close( event_pollblock *b, void *ref )
{
	Window_Delete( upd8_win );
	upd8_win = 0;
	return TRUE;
}


static void make_bar_menu(void)
{
	char title[24];
	/* Create icon bar menu */
	if ( !bar_menu )
	{
		strcpy(title,lookup("menu.bart"));
		bar_menu = Menu_New( title, lookup("menu.bar") );
		if ( !bar_menu ) { Msgs_ReportFatal(0,"err.menu"); }
	}
}


static BOOL Hnd_Upd8Click( event_pollblock *b, void *ref )
{
	int adj = b->data.mouse.button.data.adjust;

	if ( b->data.mouse.button.data.menu )	/* menu click */
	{
		make_bar_menu();
		Menu_Show( bar_menu, b->data.mouse.pos.x, b->data.mouse.pos.y );
		return TRUE;
	}

	switch ( b->data.mouse.icon )
	{
		case SRC_UPDATE :
			if ( got_game && got_cnv ) { do_update(); }
			if ( !adj ) { return Hnd_Upd8Close(b,ref); }
			break;
		case SRC_CANCEL :
			got_game = got_cnv = FALSE;
			game_type = NOGAME;
			*game_name = *cnv_name = 0;
			Icon_SetText( upd8_win, SRC_GAME, "" );
			Icon_SetText( upd8_win, SRC_CNV, "" );
			Icon_SetShade( upd8_win, SRC_UPDATE, TRUE );
			if ( !adj ) { return Hnd_Upd8Close(b,ref); }
			break;
	}
	return TRUE;
}

static void start_update(void)
{
	/* Don't allow another update if save hasn't been completed */
	if ( converted )
	{
		if (query_box("err.unsavet","err.unsavem","err.unsaven","err.unsavey"))
			cleanup();
		else
			return;
	}

	if ( upd8_win )
	{
		Window_BringToFront(upd8_win);
		return;
	}

	upd8_win = Window_Create( "source", template_TITLEMIN );
	Icon_SetText( upd8_win, SRC_GAME, game_name );
	Icon_SetText( upd8_win, SRC_CNV, cnv_name );
	Icon_SetShade( upd8_win, SRC_UPDATE, !(got_game && got_cnv) );
	Event_Claim( event_OPEN, upd8_win, event_ANY, Handler_OpenWindow, NULL );
	Event_Claim( event_CLOSE, upd8_win, event_ANY, Hnd_Upd8Close, NULL );
	Event_Claim( event_CLICK, upd8_win, event_ANY, Hnd_Upd8Click, NULL );
	EventMsg_Claim( message_DATALOAD, upd8_win, Hnd_DataLoad, NULL );
	Window_Show( upd8_win, open_CENTERED );
}



static BOOL Hnd_MenuWarn( event_pollblock *b, void *ref )
{
	int x,y;
	if ( menu_currentopen != bar_menu ) { return FALSE; }
	if ( !inf_win )
	{
		inf_win = Window_Create( "info", template_TITLEMIN );
		Event_Claim( event_OPEN, inf_win, event_ANY, Handler_OpenWindow, NULL );
		Icon_SetText( inf_win, 3, lookup("task.version") );
	}
	x = b->data.message.data.menuwarn.openpos.x;
	y = b->data.message.data.menuwarn.openpos.y;
	Wimp_CreateSubMenu( (menu_ptr) inf_win, x, y );
	return TRUE;
}


static BOOL Hnd_MenuDel( event_pollblock *b, void *ref )
{
	if ( b->data.message.data.words[0] != (int) bar_menu ) { return FALSE; }
	Menu_FullDispose( bar_menu );
	if ( inf_win ) { Window_Delete( inf_win ); }
	inf_win = 0;
	bar_menu = 0;
	return TRUE;
}



static BOOL Hnd_BarMenu( event_pollblock *b, void *ref )
{
	mouse_block mb;
	if ( menu_currentopen != bar_menu ) { return FALSE; }
	switch ( b->data.selection[0] )
	{
		case 0 : /* Info> */
			break;
		case 1 : /* Quit */
			Event_CloseDown();
			exit(0);
			break;
	}
	Wimp_GetPointerInfo( &mb );
	if ( mb.button.data.adjust )
	{
		Menu_ShowLast();
	}
	return TRUE;
}



static BOOL Hnd_BarClick( event_pollblock *b, void *ref )
{
	if ( b->data.mouse.button.data.menu )	/* menu click */
	{
		make_bar_menu();
		Menu_Show( bar_menu, b->data.mouse.pos.x, -1 );
	}
	else		/* select or adjust */
	{
		start_update();
	}
	return TRUE;
}





int main( void )
{
	icon_handle ibar_icn;
	char *tmp;
	/* Initialise */
	Hourglass_On();
	atexit(cleanup);
	Screen_CacheModeInfo();
	Resource_Initialise( "upd8lhsh" );		/* where our resources live */
	Event_Initialise( "UpdateLHSh" );		/* initialise the Event system */
	EventMsg_Initialise();					/* and the EventMsg system */
	/* Load resources */
	Msgs_LoadFile( "messages" );			/* load our messages file */
	tmp = choose_sprites( "<upd8lhsh$dir>.Sprites" );
	if ( !tmp ) { Msgs_ReportFatal(0,"err.nosprs"); }
	resource_sprites = Sprite_LoadFile( tmp );
	tmp = choose_templates( "<upd8lhsh$dir>.Templates" );
	if ( !tmp ) { Msgs_ReportFatal(0,"err.notmpls"); }
	Template_Initialise();
	Template_UseSpriteArea( resource_sprites );
	Template_LoadFile( tmp );
	/* Install Icon bar icon */
	ibar_icn = Icon_BarIcon( lookup("task.icon"), iconbar_RIGHT );
	/* Install some handlers */
	EventMsg_Claim( message_MODECHANGE, event_ANY, Handler_ModeChange, NULL );
	EventMsg_Claim( message_MENUWARN, event_ANY, Hnd_MenuWarn, NULL );
	EventMsg_Claim( message_MENUSDELETED, event_ANY, Hnd_MenuDel, NULL );
	Event_Claim( event_CLICK, window_ICONBAR, ibar_icn, Hnd_BarClick, NULL );
	Event_Claim( event_MENU, event_ANY, event_ANY, Hnd_BarMenu, NULL );
	/* Polling loop */
	Hourglass_Off();
	start_update();
	while ( TRUE ) { Event_Poll(); }
}


