/*
 * help.c
 * 
 * Opens help/settings window and handles events.
 * For yak.
 * 
 * Martin W. Scott, 12-Sep-92.
 */
#include <exec/types.h>
#include <dos/dosextens.h>
#include <graphics/gfxmacros.h>
#include <libraries/commodities.h>
#include <intuition/gadgetclass.h>
#include <intuition/intuition.h>
#include <libraries/gadtools.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <proto/graphics.h>
#include <proto/commodities.h>
#include <string.h>

#include "yak.h"
#include "hotkey_types.h"
#include "popup.h"
#include "version.h"
#ifndef YAK_LOCALE_STRINGS
#include "yak_locale_strings.h"
#endif

extern struct DosLibrary *DOSBase ;
static struct Window *curwin;

/* static protos */
static void __regargs InitHelpGadget(UWORD num, LONG tagtype, LONG tagvalue);
static void InitHelpGadgets(void);
static void __regargs InitHotKeyGadget(UWORD num, LONG tagtype, LONG tagvalue);
static void InitHotKeyGadgets(void);
static void __regargs NewPattern(UWORD gdx, UWORD n, struct Gadget *gad);
static BOOL ShowHelpWindow(void);
static BOOL ShowHotKeyWindow(void);
static BOOL SwitchWindows(void);
static LONG HandleHelpIDCMP(void);
static LONG HandleHotKeyIDCMP(void);


/* menu numbers */
#define LOAD 0
#define SAVE 1
#define HIDE 2
#define QUIT 3

/* initialise individual gadget in help window */
static void __regargs
InitHelpGadget(UWORD num, LONG tagtype, LONG tagvalue)
{
	GT_SetGadgetAttrs(HelpGadgets[num], HelpWnd, NULL, tagtype, tagvalue, TAG_DONE);
}

/* initialise all gadgets */
static void
InitHelpGadgets()
{
	UWORD	i;

	for (i = 0; i < NUM_TOGGLES; i++)
		if (toggles[i].gadid != -1)
			InitHelpGadget(toggles[i].gadid,
				   GTCB_Checked,
				   toggles[i].pos); 

	InitHelpGadget(GDX_MBMethod, GTCY_Active, mouseblank);
	InitHelpGadget(GDX_ScrTONum, GTIN_Number, blanksecs);
	InitHelpGadget(GDX_MouseTONum, GTIN_Number, mblanksecs);
	InitHelpGadget(GDX_ClickVol, GTIN_Number, click_volume);
	InitHelpGadget(GDX_AutoPat, GTST_String, (LONG)patterns[YP_AUTOSCR_PAT].patstr);
	InitHelpGadget(GDX_ClickPat, GTST_String, (LONG)patterns[YP_CLICKSCR_PAT].patstr);
	InitHelpGadget(GDX_PopPat, GTST_String, (LONG)patterns[YP_POPWIN_PAT].patstr);
	InitHelpGadget(GDX_ClickWinPat, GTST_String, (LONG)patterns[YP_CLICKWIN_PAT].patstr);
}

/* show current window */
BOOL
ShowWindow()
{
	WBenchToFront();
	if (curwin)		/* already open... */
	{
		WindowToFront(curwin);
		ActivateWindow(curwin);
		return TRUE;
	}

	if (SetupScreen())	/* try to get lock on WB */
		return FALSE;

	return ShowHelpWindow();
}

/* show our help window */
static BOOL
ShowHelpWindow()
{
	static char	title[80];

	strcpy(title, VERSION_NAME ": ");
	strcat(title, getString(Hotkey_Window_TITLE));
	strcat(title, PopKeyStr);
	strcat(title, ">");
	HelpWdt = title;
    InitGUI ();

	if (!OpenHelpWindow())	/* like the name says... */
	{
		InitHelpGadgets();
		wndsigflag = 1 << HelpWnd->UserPort->mp_SigBit;
		curwin = HelpWnd;
		return TRUE;
	}
	CloseDownScreen();
	return FALSE;
}

/* show our help window */
static BOOL
ShowHotKeyWindow()
{
	if (!OpenHotKeyWindow())	/* like the name says... */
	{
		InitHotKeyGadgets();
		wndsigflag = 1 << HotKeyWnd->UserPort->mp_SigBit;
		curwin = HotKeyWnd;
		return TRUE;
	}
	CloseDownScreen();
	return FALSE;
}

/* hide our window */
void
HideWindow()
{
	if (curwin)
	{
		if (curwin == HelpWnd)
			CloseHelpWindow();
		else
			CloseHotKeyWindow();

		CloseDownScreen();
		wndsigflag = NULL;
		curwin = HelpWnd = HotKeyWnd = NULL;
	}
}

/* switch between windows */
static BOOL
SwitchWindows()
{
	if (curwin == HelpWnd)
	{
		HelpLeft = HotKeyLeft = HelpWnd->LeftEdge;
		HelpTop = HotKeyTop = HelpWnd->TopEdge;
		CloseHelpWindow();
		return ShowHotKeyWindow();
	} else {
		CloseHotKeyWindow();
		return ShowHelpWindow();
	}
}

/* handle pattern string-gadget */
static void __regargs
NewPattern(UWORD gdx, UWORD n, struct Gadget *gad)
{
	char *newpatstr;

	newpatstr = GetString(gad);
	if (!InitPattern(newpatstr, n))
	{
		DisplayBeep(Scr);
		InitHelpGadget(gdx, GTST_String, (LONG)patterns[n].patstr);
	}
}

/* handle window events */
LONG
HandleIDCMP()
{
	if (curwin == HelpWnd)
		return HandleHelpIDCMP();
	else
		return HandleHotKeyIDCMP();
}

/* handle help window events */
static LONG
HandleHelpIDCMP()
{
	struct IntuiMessage *msg;
	struct Gadget   *gadget;
	ULONG           class;
	UWORD		code;
	LONG		num;

	while (msg = GT_GetIMsg(HelpWnd->UserPort))
	{
		class = msg->Class;
		code = msg->Code;
		gadget = (struct Gadget *)msg->IAddress;
		GT_ReplyIMsg(msg);

		switch (class)
		{
		case CLOSEWINDOW:
			HideWindow();
			return HELP_OKAY;

		case GADGETUP:
		case GADGETDOWN:
			switch (gadget->GadgetID)
			{
			case GD_EditHotkeys: 
				if (!SwitchWindows())
					PostError(getString(Couldnt_open_other_window_ERR));
				return HELP_OKAY;

			case GD_AutoPat:
				NewPattern(GDX_AutoPat, YP_AUTOSCR_PAT, gadget);
				break;

			case GD_ClickPat:
				NewPattern(GDX_ClickPat, YP_CLICKSCR_PAT, gadget);
				break;

			case GD_PopPat:
				NewPattern(GDX_PopPat, YP_POPWIN_PAT, gadget);
				break;

			case GD_ClickWinPat:
				NewPattern(GDX_ClickWinPat, YP_CLICKWIN_PAT, gadget);
				break;

			case GD_Hide:
				HideWindow();
				return HELP_OKAY;

			case GD_Quit:
				HideWindow();
				return HELP_QUIT;

			case GD_AutoCheck:	/* toggle */
				autopoint ^= TRUE;
				break;

			case GD_AutoPopCheck:	/* toggle */
				autopop ^= TRUE;
				break;

			case GD_KeyActCheck:	/* toggle */
				keyactivate ^= TRUE;
				break;

			case GD_CTFCheck:	/* toggle */
				clicktofront ^= TRUE;
				break;

			case GD_CTBCheck:	/* toggle */
				clicktoback ^= TRUE;
				break;

			case GD_ScrCycleCheck:	/* toggle */
				screencycle ^= TRUE;
				break;

			case GD_WildStarCheck:	/* toggle */
				wildstar ^= TRUE;
				if (wildstar) WILDSTARON; else WILDSTAROFF;
				break;

			case GD_ScrActCheck:	/* toggle */
				scractivate ^= TRUE;
				break;

			case GD_RMBActCheck:	/* toggle */
				rmbactivate ^= TRUE;
				break;

			case GD_ScrTONum:
				num = GetNumber(gadget);
				if (num >= 0) {
					blanksecs = num;
					blankcount = blanktimeout = blanksecs*10;
				} else {
					InitHelpGadget(GDX_ScrTONum, GTIN_Number, blanksecs);
					DisplayBeep(HelpWnd->WScreen);
				}
				break;

			case GD_MouseTONum:
				num = GetNumber(gadget);
				if (num >= 0) {
					mblanksecs = num;
					mblankcount = mblanktimeout = mblanksecs*10;
				} else {
					InitHelpGadget(GDX_MouseTONum, GTIN_Number, mblanksecs);
					DisplayBeep(HelpWnd->WScreen);
				}
				break;

			case GD_ClickVol:
				num = GetNumber(gadget);
				if (num >= 0 && num <= 64) {
					click_volume = num;
				} else {
					InitHelpGadget(GDX_ClickVol, GTIN_Number, click_volume);
					DisplayBeep(HelpWnd->WScreen);
				}
				break;

			case GD_MBMethod:
				mouseblank = code;
				mblankcount = mblanktimeout;
				break;

			} /* switch (gadget->GadgetID) */
			break;

		case REFRESHWINDOW:
			GT_BeginRefresh(HelpWnd);
			HelpRender();
			GT_EndRefresh(HelpWnd, TRUE);
			break;

		case IDCMP_MENUPICK:
			while (code != MENUNULL) 
			{
				struct MenuItem *item = ItemAddress(HelpMenus, code);

				switch (ITEMNUM(code))
				{
				case LOAD:
					LoadSettings();
					InitHelpGadgets();
					break;
				case SAVE:
					SaveSettings();
					break;
				case HIDE:
					HideWindow();
					return HELP_OKAY;
				case QUIT:
					HideWindow();
					return HELP_QUIT;
				}
				code = item->NextSelect;

			} /* while more menuchoices */
			break;

		} /* switch (class) */

	} /* while more messages */

	return HELP_OKAY;
}

/*******************************************************************************
 *	HOTKEY SPECIFIC DATA/ROUTINES
 *	perhaps move to another file?
 *******************************************************************************/

/* prototypes */
static struct Node *GetNode(struct List *lh, UWORD n);
static UWORD GetNodeNum(struct List *lh, struct Node *node);

/* external data */
static YakHotKey	*curhk;
static UWORD		curtype;

/* get nth node in list - list MUST have >= n nodes!!! */
static struct Node *
GetNode(struct List *lh, UWORD n)
{
	struct Node *ln;

	for (ln = lh->lh_Head; n--; ln = ln->ln_Succ)
		;
	return ln;
}

/* get number of node in list - node MUST be there! */
static UWORD
GetNodeNum(struct List *lh, struct Node *node)
{
	struct Node *ln;
	UWORD i;

	for (i = 0, ln = lh->lh_Head; ln != node; ln = ln->ln_Succ, i++)
		;
	return i;
}

/* initialise individual gadget in hotkey window */
static void __regargs
InitHotKeyGadget(UWORD num, LONG tagtype, LONG tagvalue)
{
	GT_SetGadgetAttrs(HotKeyGadgets[num], HotKeyWnd, NULL, tagtype, tagvalue, TAG_DONE);
}

/* initialise all gadgets */
static void
InitHotKeyGadgets()
{
	InitHotKeyGadget(GDX_Hotkeys, GTLV_Labels, (LONG)keylist(curtype));
	InitHotKeyGadget(GDX_Actions, GTLV_Selected, curtype);

	InitHotKeyGadget(GDX_Delete, GA_Disabled, !curhk);
	InitHotKeyGadget(GDX_HKStr, GA_Disabled, !curhk);

	/* something selected */
	if (curhk)
	{
		UWORD n = GetNodeNum(keylist(curtype), (struct Node *)curhk);

		if (YHK_Has_Options(curhk))
		{
			InitHotKeyGadget(GDX_Options, GA_Disabled, FALSE);
			InitHotKeyGadget(GDX_Options, GTCY_Active, (LONG)curhk->yhk_Options);
		}

		if (YHK_Takes_Arg(curhk))
		{
			InitHotKeyGadget(GDX_Argument, GA_Disabled, FALSE);
			InitHotKeyGadget(GDX_Argument, GTST_String, (LONG)curhk->yhk_ArgStr);
		}

		InitHotKeyGadget(GDX_Hotkeys, GTLV_Selected, n);
		InitHotKeyGadget(GDX_Hotkeys, GTLV_Top, n);
		InitHotKeyGadget(GDX_HKStr, GTST_String, (LONG)curhk->yhk_KeyDef);
	}
	else	/* no current hotkey */
	{
		InitHotKeyGadget(GDX_HKStr, GTST_String, (LONG)"");
		InitHotKeyGadget(GDX_Options, GTCY_Active, 0);
		InitHotKeyGadget(GDX_Argument, GTST_String, (LONG)"");

		InitHotKeyGadget(GDX_Argument, GA_Disabled, TRUE);
		InitHotKeyGadget(GDX_Options, GA_Disabled, TRUE);
	}
}

/* handle hotkey window events */
static LONG
HandleHotKeyIDCMP()
{
	struct IntuiMessage *msg;
	struct Gadget   *gadget;
	ULONG           class;
	UWORD		code;

	while (msg = GT_GetIMsg(HotKeyWnd->UserPort))
	{
		class = msg->Class;
		code = msg->Code;
		gadget = (struct Gadget *)msg->IAddress;
		GT_ReplyIMsg(msg);

		switch (class)
		{
		case CLOSEWINDOW:
			HideWindow();
			return HELP_OKAY;

		case GADGETUP:
		case GADGETDOWN:
			switch (gadget->GadgetID)
			{
			case GD_Hotkeys:
				curhk = (YakHotKey *)GetNode(keylist(curtype), code);
				InitHotKeyGadgets();
				ActivateGadget(HotKeyGadgets[GDX_HKStr], HotKeyWnd, NULL);
				break;

			case GD_HKStr:
				if (!curhk)	/* shouldn't happen */
					break;
				if (ModifyYHKKeyDef(curhk, GetString(gadget)))
				{
					InitHotKeyGadget(GDX_Hotkeys, GTLV_Labels, (LONG)keylist(curtype));
					if (YHK_Takes_Arg(curhk))
						ActivateGadget(HotKeyGadgets[GDX_Argument], HotKeyWnd, NULL);

				}
				else
				{
					InitHotKeyGadgets();
					ActivateGadget(HotKeyGadgets[GDX_HKStr], HotKeyWnd, NULL);
				}
				break;

			case GD_Argument:
				if (!curhk)	/* shouldn't happen */
					break;
				if (!(ModifyYHKArgStr(curhk, GetString(gadget))))
					InitHotKeyGadgets();
				break;

			case GD_Actions:
				if (code != curtype)
				{
					curtype = code;
					curhk = NULL;
					InitHotKeyGadgets();
				}
				break;

			case GD_Options:
				if (curhk)
					curhk->yhk_Options = code;
				break;

			case GD_Add:
				curhk = NewYakHotKey(curtype);
				InitHotKeyGadgets();
				ActivateGadget(HotKeyGadgets[GDX_HKStr], HotKeyWnd, NULL);
				break;

			case GD_Delete:
				if (curhk)
				{
					DeleteYakHotKey(curhk);
					curhk = NULL;
					InitHotKeyGadgets();
				}
				break;

			case GD_Return:
				curhk = NULL;	/* in case of reloading */
				if (!SwitchWindows())
					PostError(getString(Couldnt_open_other_window_ERR));
				return HELP_OKAY;

			} /* switch (gadget->GadgetID) */
			break;

		case REFRESHWINDOW:
			GT_BeginRefresh(HotKeyWnd);
			GT_EndRefresh(HotKeyWnd, TRUE);
			break;

		} /* switch (class) */

	} /* while more messages */

	return HELP_OKAY;
}
