/* XdY.c
 * The core (application) functions of XdY
 * Musus Umbra, 1996/7
 */
                         
#include "Tables.h"
#include "XdYmath.h"
#include "IconNums.h"
#include "XdY.h"

#include "DeskLib:Window.h"
#include "DeskLib:Core.h"
#include "DeskLib:WimpSWIs.h"
#include "DeskLib:Template.h"
#include "DeskLib:Msgs.h"
#include "DeskLib:Event.h"
#include "DeskLib:Icon.h"
#include "DeskLib:Handler.h"
#include "DeskLib:Menu.h"
#include "DeskLib:Kbd.h"

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

static xdy_values values_[2] =	/* ie. current & previous */
{
	{ { 1,4,0,0,5.0,1,0 }, { 18,18,1, RACE_HUMAN, CLASS_WARRIOR }, { 0,0,0 } },
	{ { 1,4,0,0,5.0,1,0 }, { 18,18,1, RACE_HUMAN, CLASS_WARRIOR }, { 0,0,0 } }
};

static BOOL			auto_update = FALSE;

static xdy_values *values = values_;
static int curr_values = 0;

static xdy_result results_;
static xdy_result *results = &results_;

static window_handle	main_win = 0;
static window_handle	res_win  = 0;

static menu_ptr			race_menu = 0;
static menu_ptr			class_menu = 0;
static menu_ptr			std_menu = 0;


static menu_ptr make_menu( char *title, char **array, int size )
{
	int tl = 0;
	menu_ptr m;
	char *t,*s;
	int i;
	for ( i=0; i<size; i++ )
		tl += strlen(array[i])+1;
	s = t = (char*) malloc(tl);
	if ( !t ) { return NULL; }
	for ( i=0; i<size; i++ )
	{
		strcpy(t,array[i]);
		t+=strlen(t);
		*t++=',';
	}
	*--t = 0;	/* terminate over final ',' */
	m = Menu_New( title, s );
	free(s);
	return m;
}



static void write_defaults( void )
{
	FILE *def = fopen("<xdy+$dir>.defaults","wb");
	if ( !def ) { return; }
	fputc(auto_update,def);
	fwrite(&values_[curr_values ? 0 : 1],sizeof(xdy_values),1,def);
	fwrite(&values_[curr_values ? 1 : 0],sizeof(xdy_values),1,def);
	fputc(results->ac,def);
	fclose(def);
}


static BOOL Hnd_Close( event_pollblock *b, void *ref )
{
	Handler_DeleteWindow( b, ref );
	*( (int*) ref ) = 0;
	return TRUE;
}


static char *stat_to_text( int v )
{
	static char buffer[16];
	if ( v<=18 )
		sprintf(buffer,"%d",v);
	else if ( v<=238 )
		sprintf(buffer,"18/%02d",v-18);
	else
		sprintf(buffer,"18/***");
	return buffer;
}


static void set_modifier_icon( window_handle w, icon_handle i, int v )
{
	if ( v >= 0 )
		Icon_printf( w, i, "+%d" , v );
	else
		Icon_printf( w, i, "%d" , v );
}



static void setup_main_window( void )
{
	/* First, the character section */
	Icon_SetText( main_win, STR, stat_to_text( values->chr.str ) );
	Icon_SetText( main_win, DEX, stat_to_text( values->chr.dex ) );
	Icon_SetInteger( main_win, LEVEL, values->chr.level );
	Icon_SetText( main_win, RACE, race_name[values->chr.race] );
	Icon_SetText( main_win, CLASS, class_name[values->chr.class] );
	/* Now, the Weapon Section */
	Icon_SetInteger( main_win, DICE, values->wpn.x );
	Icon_SetInteger( main_win, DIESIZE, values->wpn.y );
	Icon_SetInteger( main_win, ATTACKS, values->wpn.a );
	set_modifier_icon( main_win, TOHIT, values->wpn.h );
	set_modifier_icon( main_win, TODAM, values->wpn.d );
	Icon_printf( main_win, WEIGHT, "%.1lf", values->wpn.w );
	/* And now the 'other' frame */
	Icon_SetSelect( main_win, EDGED, values->wpn.e );
	set_modifier_icon( main_win, O_TOHIT, values->other.h );
	set_modifier_icon( main_win, O_TODAM, values->other.d );
	set_modifier_icon( main_win, ARMOUR, values->other.ap );
	/* The auto update icon */
	Icon_SetSelect( main_win, AUTO, auto_update );
}


static void incdecm( icon_handle i, int u, int a, int min, int max, int *v )
{
	if (a) { u=!u; }
	if (u) { a = *v + 1; } else { a = *v - 1; }
	if (a>=min && a<=max)
	{
		*v = a;
		set_modifier_icon( main_win, i, a );
	}
}

static void incdec( icon_handle i, int u, int a, int min, int max, int *v )
{
	if (a) { u=!u; }
	if (u) { a = *v + 1; } else { a = *v - 1; }
	if (a>=min && a<=max)
	{
		*v = a;
		Icon_SetInteger( main_win, i, a );
	}
}


static void swap_values( void )
{
	if ( curr_values )
		values = &(values_[0]);
	else
		values = &(values_[1]);
	curr_values = !curr_values;
}

static char *percent( double p )
{
	static char buffer[32];
	if ( p>=0.0 )
		sprintf(buffer,"%.1lf%%",p*100.0);
	else
		sprintf(buffer,"0%%");
	return buffer;
}


static void setup_result_window( void )
{
	xdy_calculate( values, results );
	Icon_SetInteger( res_win, BLOWS, results->blows );
	Icon_SetInteger( res_win, SKILL, results->skill );
	Icon_SetText( res_win, HITPROB, percent(results->hit_prob) );
	Icon_SetText( res_win, CRITPROB, percent(results->crit.prob) );
	Icon_SetText( res_win, GOODPROB, percent(results->crit.good) );
	Icon_SetText( res_win, GREATPROB, percent(results->crit.great) );
	Icon_SetText( res_win, SUPERBPROB, percent(results->crit.superb) );
	Icon_SetText( res_win, SGREATPROB, percent(results->crit.s_great) );
	Icon_SetText( res_win, SSUPERBPROB, percent(results->crit.s_superb) );
	Icon_SetDouble( res_win, AVGDAM, results->dam_per_hit,1 );
	Icon_SetInteger( res_win, MAXDAM, results->max_dam );
	Icon_SetInteger( res_win, MINDAM, results->min_dam );
	Icon_SetInteger( res_win, AC, results->ac );
	Icon_SetDouble( res_win, DAMPERROUND, results->dam_per_round,1 );
}



static BOOL Hnd_MainClick( event_pollblock *b, void *ref )
{
	int adj = b->data.mouse.button.data.adjust;
	int icn = b->data.mouse.icon;
	int t;
	double w;
	if ( b->data.mouse.button.data.menu ) { return FALSE; }
	switch ( icn )
	{
		case STR_U : case STR_D :
			t = ( icn == STR_U);
			if ( adj ) { t = !t; }
			if ( t ) { t = values->chr.str+1; } else { t = values->chr.str-1; }
			if ( t>=3 && t<=247 ) { values->chr.str = t; }
			Icon_SetText( main_win, STR, stat_to_text( values->chr.str ) );
			break;
		case DEX_U : case DEX_D :
			t = ( icn == DEX_U);
			if ( adj ) { t = !t; }
			if ( t ) { t = values->chr.dex+1; } else { t = values->chr.dex-1; }
			if ( t>=3 && t<=247 ) { values->chr.dex = t; }
			Icon_SetText( main_win, DEX, stat_to_text( values->chr.dex ) );
			break;
		case LEVEL_U : case LEVEL_D :
			incdec(LEVEL,icn==LEVEL_U,adj,1,50,&(values->chr.level));
			break;
		case DICE_U : case DICE_D :
			incdec(DICE,icn==DICE_U,adj,1,25,&(values->wpn.x));
			break;
		case ARMOUR_U : case ARMOUR_D :
			incdec(ARMOUR,icn==ARMOUR_U,adj,-16,0,&(values->other.ap));
			break;
		case DIESIZE_U : case DIESIZE_D :
			incdec(DIESIZE,icn==DIESIZE_U,adj,1,50,&(values->wpn.y));
			break;
		case TOHIT_U : case TOHIT_D :
			incdecm(TOHIT,icn==TOHIT_U,adj,-100,100,&(values->wpn.h));
			break;
		case TODAM_U : case TODAM_D :
			incdecm(TODAM,icn==TODAM_U,adj,-100,100,&(values->wpn.d));
			break;
		case O_TOHIT_U : case O_TOHIT_D :
			incdecm(O_TOHIT,icn==O_TOHIT_U,adj,-100,100,&(values->other.h));
			break;
		case O_TODAM_U : case O_TODAM_D :
			incdecm(O_TODAM,icn==O_TODAM_U,adj,-100,100,&(values->other.d));
			break;
		case ATTACK_U : case ATTACK_D :
			incdec(ATTACKS,icn==ATTACK_U,adj,0,2,&(values->wpn.a));
			break;
		case WEIGHT_U : case WEIGHT_D :
			t = ( icn == WEIGHT_U);
			if ( adj ) { t = !t; }
			if ( t )
				w = values->wpn.w+0.5;
			else
				w = values->wpn.w-0.5;
			if ( w>=0.5 && w<=150.0 ) { values->wpn.w = w; }
			Icon_printf( main_win, WEIGHT, "%.1lf", values->wpn.w );
			break;
		case EDGED :
			values->wpn.e = Icon_GetSelect(main_win,icn);
			break;
		case PREV_WPN :
			swap_values();
			setup_main_window();
			if ( !res_win ) { break; }
		case SHOW_RES :
			if ( !res_win ) { xdy_start_results(); }
			setup_result_window();
			break;
		case CLASS_MENU :
			if ( class_menu ) { Menu_PopUpAuto(class_menu); }
			break;
		case RACE_MENU :
			if ( race_menu ) { Menu_PopUpAuto(race_menu); }
			break;
		case STD_MENU :
			if ( std_menu ) { Menu_PopUpAuto(std_menu); }
			break;
		case SAVE :
			write_defaults();
			break;
		case AUTO :
			auto_update = Icon_GetSelect( main_win, AUTO );
			break;
	}
	if ( auto_update && res_win )
		setup_result_window();
	return TRUE;
}


static BOOL Hnd_ResClick( event_pollblock *b, void *ref )
{
	int adj = b->data.mouse.button.data.adjust;
	int icn = b->data.mouse.icon;
	int t;
	if ( b->data.mouse.button.data.menu ) { return FALSE; }
	switch ( icn )
	{
		case AC_U : case AC_D :
			t = icn == AC_U ? +1 : -1;
			if ( Kbd_KeyDown( -1 ) ) { t*=5; }
			if (adj) { t=-t; }
			t = results->ac + t;
			if ( t<1 ) { t=1; } else if ( t>250 ) { t=250; }
			results->ac = t;
			xdy_calculate_new_ac(values,results);
			Icon_SetInteger( res_win, AC, results->ac );
			Icon_SetDouble( res_win, DAMPERROUND, results->dam_per_round,1 );
			Icon_SetText( res_win, HITPROB, percent(results->hit_prob) );
			break;
		case PREV_STATS :
			swap_values();
			setup_result_window();
			if ( main_win ) { setup_main_window(); }
			break;
		case CLOSE_STATS :
			Window_Delete(res_win);
			res_win = 0;
			break;
	}
	return TRUE;
}




static void claim_main_handlers( void )
{
	Event_Claim( event_CLOSE,main_win,event_ANY,Hnd_Close,(void*)&main_win);
	Event_Claim( event_CLICK,main_win,event_ANY,Hnd_MainClick, 0 );
}

static void claim_result_handlers( void )
{
	Event_Claim( event_CLOSE,res_win,event_ANY,Hnd_Close,(void*)&res_win);
	Event_Claim( event_CLICK,res_win,event_ANY,Hnd_ResClick, 0 );
}

static BOOL Hnd_XdYMenu( event_pollblock *b, void *ref )
{
	mouse_block mb;
	if ( menu_currentopen == race_menu )
	{
		values->chr.race = b->data.selection[0];
		Icon_SetText( main_win, RACE, race_name[values->chr.race] );
	}
	else if ( menu_currentopen == class_menu )
	{
		values->chr.class = b->data.selection[0];
		Icon_SetText( main_win, CLASS, class_name[values->chr.class] );
	}
	else if ( menu_currentopen == std_menu )
	{
		values->wpn.x = std_weapons[b->data.selection[0]].x;
		values->wpn.y = std_weapons[b->data.selection[0]].y;
		values->wpn.w = std_weapons[b->data.selection[0]].w;
		values->wpn.e = std_weapons[b->data.selection[0]].e;
		Icon_SetInteger( main_win, DICE, values->wpn.x );
		Icon_SetInteger( main_win, DIESIZE, values->wpn.y );
		Icon_printf( main_win, WEIGHT, "%.1lf", values->wpn.w );
		Icon_SetSelect( main_win, EDGED, values->wpn.e );
	}
	else
	{
		return FALSE;
	}
	Wimp_GetPointerInfo(&mb);
	if ( mb.button.data.adjust ) { Menu_ShowLast(); }
	if ( auto_update && res_win ) { setup_result_window(); }
	return TRUE;
}


static void init_menus(void)
{
	static int claimed = 0;
	if ( !race_menu ) { race_menu = make_menu( "Race", race_name, 10 ); }
	if ( !class_menu ) { class_menu = make_menu( "Class", class_name, 6 ); }
	if ( !std_menu ) { std_menu = make_menu( "Weapon", std_names, 49 ); }
	if ( !claimed )
	{
		Event_Claim( event_MENU, event_ANY, event_ANY, Hnd_XdYMenu, NULL );
		claimed = 1;
	}
}

void xdy_init(void)
{
	xdy_values	defaults[2];
	FILE *def = fopen("<xdy+$dir>.defaults","rb");
	init_menus();
	if ( !def ) { return; }
	auto_update = fgetc(def);
	if ( fread(defaults,sizeof(xdy_values),2,def) == 2 )
		memcpy(values_,defaults,2*sizeof(xdy_values));
	results->ac = fgetc(def);
	fclose(def);
}


void xdy_start_main(void)
{
	if ( !main_win )
	{
		main_win = Window_Create( "main", template_TITLEMIN );
		setup_main_window();
		claim_main_handlers();
		Window_Show( main_win, open_CENTERED );
	}
	Window_BringToFront( main_win );
}


void xdy_start_results(void)
{
	if ( !res_win )
	{
		res_win = Window_Create( "results", template_TITLEMIN );
		setup_result_window();
		claim_result_handlers();
		Window_Show( res_win, open_CENTERED );
	}
	Window_BringToFront( res_win );
}


