/*
**	PhonePanelPlus.c
**
**	The phonebook and support routines
**
**	Copyright © 1990-1995 by Olaf `Olsen' Barthel
**		All Rights Reserved
**
**	:ts=4
*/

#include "termGlobal.h"

	// The gadget IDs are in there

#include "PhonePanel.h"

	/* PhoneListViewRender():
	 *
	 *	This callback routine is responsible for rendering
	 *	the single listview entries.
	 */

ULONG __saveds __asm
PhoneListViewRender(register __a0 struct Hook *Hook,register __a1 struct LVDrawMsg *Msg,register __a2 struct PhoneNode *Node)
{
		/* We only know how to redraw lines. */

	if(Msg -> lvdm_MethodID == LV_DRAW)
	{
		struct RastPort	*RPort	= Msg -> lvdm_RastPort;
		LONG			 Count	= Node -> Entry -> Count + 1,
						 Left	= Msg -> lvdm_Bounds . MinX,
						 Top	= Msg -> lvdm_Bounds . MinY,
						 Width	= Msg -> lvdm_Bounds . MaxX - Msg -> lvdm_Bounds . MinX + 1,
						 Height	= Msg -> lvdm_Bounds . MaxY - Msg -> lvdm_Bounds . MinY + 1,
						 FgPen,BgPen,
						 Template,
						 Len,LabelLen;
		UBYTE			 String[80],Num[8];

			/* Determine the rendering pens. */

		switch(Msg -> lvdm_State)
		{
			case LVR_SELECTEDDISABLED:
			case LVR_NORMALDISABLED:
			case LVR_NORMAL:

				FgPen = Msg -> lvdm_DrawInfo -> dri_Pens[TEXTPEN];
				BgPen = Msg -> lvdm_DrawInfo -> dri_Pens[BACKGROUNDPEN];
				break;

			case LVR_SELECTED:

				FgPen = Msg -> lvdm_DrawInfo -> dri_Pens[FILLTEXTPEN];
				BgPen = Msg -> lvdm_DrawInfo -> dri_Pens[FILLPEN];
				break;
		}

		if(Count > 0)
		{
			if(Msg -> lvdm_DrawInfo -> dri_Pens[HIGHLIGHTTEXTPEN] != BgPen)
				FgPen = Msg -> lvdm_DrawInfo -> dri_Pens[HIGHLIGHTTEXTPEN];
		}

		SetAPen(RPort,BgPen);
		RectFill(RPort,Left,Top,Left + 1,Top + Height - 1);

		Left	+= 2;
		Width	-= 2;

			/* Determine maximum index text length. */

		Template = 3 * ((ULONG)Hook -> h_Data) + TextLength(RPort," - ",3);

			/* Get the vanilla name. */

		strcpy(String,&Node -> VanillaNode . ln_Name[6]);

			/* Set the rendering pens. */

		SetDrMd(RPort,JAM2);
		SetBPen(RPort,BgPen);

			/* Has this entry been selected? */

		if(Count > 0)
		{
			LONG Delta;

				/* Set up the header. */

			SPrintf(Num,"%3ld - ",Count);

				/* Determine header length. */

			Len = TextLength(RPort,Num,6);

				/* Fill the space to precede the header. */

			if((Delta = Template - Len) > 0)
			{
				SetAPen(RPort,BgPen);
				RectFill(RPort,Left,Top,Left + Delta - 1,Top + Height - 1);
			}

				/* Render the header, right-justified. */

			SetAPen(RPort,FgPen);

			Move(RPort,Left + Delta,Top + RPort -> Font -> tf_Baseline);
			Text(RPort,Num,6);
		}
		else
		{
				/* Fill the blank space to precede the vanilla name. */

			SetAPen(RPort,BgPen);
			RectFill(RPort,Left,Top,Left + Template - 1,Top + Height - 1);
			SetAPen(RPort,FgPen);
		}

			/* Adjust width and area left edge. */

		Left	+= Template;
		Width	-= Template;

			/* Determine length of vanilla name. */

		LabelLen = strlen(String);

			/* Try to make it fit. */

		while(LabelLen > 0 && (Len = TextLength(RPort,String,LabelLen)) > Width)
			LabelLen--;

			/* Print the vanilla name if possible. */

		if(LabelLen)
		{
			Move(RPort,Left,Top + RPort -> Font -> tf_Baseline);
			Text(RPort,String,LabelLen);

			Left	+= Len;
			Width	-= Len;
		}

			/* Fill the area to follow the vanilla name. */

		if(Width > 0)
		{
			SetAPen(RPort,BgPen);
			RectFill(RPort,Left,Top,Left + Width - 1,Top + Height - 1);
		}

			/* If the item happens to be disabled, draw the cross-hatch
			 * pattern across it.
			 */

		if(Msg -> lvdm_State == LVR_SELECTEDDISABLED || Msg -> lvdm_State == LVR_NORMALDISABLED)
		{
			SetDrMd(RPort,JAM1);

			SetAPen(RPort,Msg -> lvdm_DrawInfo -> dri_Pens[BLOCKPEN]);

			SetAfPt(RPort,(UWORD *)&Ghosting,1);

			RectFill(RPort,Msg -> lvdm_Bounds . MinX,Msg -> lvdm_Bounds . MinY,Msg -> lvdm_Bounds . MaxX,Msg -> lvdm_Bounds . MaxY);

			SetAfPt(RPort,NULL,0);
		}

		return(LVCB_OK);
	}
	else
		return(LVCB_UNKNOWN);
}

BOOLEAN
SaveChanges(struct Window *Parent)
{
	return((BOOLEAN)MyEasyRequest(Parent,LocaleString(MSG_SAVE_CHANGES),LocaleString(MSG_GLOBAL_YES_NO_TXT)));
}

BYTE __regargs
EditConfig(struct Configuration *Config,LONG Type,ULONG Qualifier,struct Window *Window)
{
	STATIC LONG TypeMappings[15][2] =
	{
		GAD_SERIAL_EDIT,		PREF_SERIAL,
		GAD_MODEM_EDIT,			PREF_MODEM,
		GAD_SCREEN_EDIT,		PREF_SCREEN,
		GAD_TERMINAL_EDIT,		PREF_TERMINAL,
		GAD_EMULATION_EDIT,		PREF_EMULATION,
		GAD_CLIPBOARD_EDIT,		PREF_CLIP,
		GAD_CAPTURE_EDIT,		PREF_CAPTURE,
		GAD_COMMAND_EDIT,		PREF_COMMAND,
		GAD_MISC_EDIT,			PREF_MISC,
		GAD_PATH_EDIT,			PREF_PATH,
		GAD_TRANSFER_EDIT,		PREF_TRANSFER,
		GAD_TRANSLATION_EDIT,	PREF_TRANSLATIONFILENAME,
		GAD_MACRO_EDIT,			PREF_MACROFILENAME,
		GAD_CURSOR_EDIT,		PREF_CURSORFILENAME,
		GAD_FASTMACRO_EDIT,		PREF_FASTMACROFILENAME
	};

	struct FileRequester	*FileRequest;
	UBYTE					 DummyBuffer[MAX_FILENAME_LENGTH],
							*DummyChar;
	BOOLEAN					 Changed	= FALSE,
							 Default	= FALSE,
							 FallBack	= TRUE;
	LONG					 PrefType;
	WORD					 i;
	APTR					 Data;

		// Find the prefs fragment that should be worked upon

	for(i = 0 ; i < sizeof(TypeMappings) / (sizeof(LONG) * 2) ; i++)
	{
		if(TypeMappings[i][0] == Type)
		{
			PrefType = TypeMappings[i][1];

			break;
		}
	}

	Data = GetConfigEntry(Config,PrefType);

	if(CreateConfigEntry(Config,PrefType))
	{
		if(!Data)
			ResetConfigEntry(Config,PrefType,FALSE);

		switch(Type)
		{
			case GAD_SERIAL_EDIT:

				Changed = SerialPanel(Config,&Default);
				break;

			case GAD_MODEM_EDIT:

				Changed = ModemPanel(Config,&Default);
				break;

			case GAD_SCREEN_EDIT:

				Changed = ScreenPanel(Config,&Default);
				break;

			case GAD_TERMINAL_EDIT:

				Changed = TerminalPanel(Config,&Default);
				break;

			case GAD_EMULATION_EDIT:

				Changed = EmulationPanel(Config,&Default);
				break;

			case GAD_CLIPBOARD_EDIT:

				Changed = ClipPanel(Config,&Default);
				break;

			case GAD_CAPTURE_EDIT:

				Changed = CapturePanel(Config,&Default);
				break;

			case GAD_COMMAND_EDIT:

				Changed = CommandPanel(Config,&Default);
				break;

			case GAD_MISC_EDIT:

				Changed = MiscPanel(Config,&Default);
				break;

			case GAD_PATH_EDIT:

				Changed = PathPanel(Config,&Default);
				break;

			case GAD_TRANSFER_EDIT:

				Changed = LibPanel(Config,&Default);
				break;

			case GAD_TRANSLATION_EDIT:

				if(!(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
				{
					struct TranslationEntry **Send,**Receive = NULL;
					BOOLEAN			Success = FALSE;

					strcpy(DummyBuffer,Config -> TranslationFileName);

					if(Send = AllocTranslationTable())
					{
						if(Receive = AllocTranslationTable())
						{
							Success = TRUE;

							if(DummyBuffer[0])
							{
								if(!LoadTranslationTables(DummyBuffer,Send,Receive))
								{
									ShowError(Window,ERR_LOAD_ERROR,IoErr(),DummyBuffer);

									FillTranslationTable(Send);
									FillTranslationTable(Receive);
								}
							}
							else
							{
								FillTranslationTable(Send);
								FillTranslationTable(Receive);
							}
						}
					}

					if(Success)
					{
						if(TranslationPanel(&Send,&Receive,DummyBuffer,Window,NULL))
						{
							if(Send || Receive)
							{
								if(IsStandardTable(Send) && IsStandardTable(Receive))
									DummyBuffer[0] = 0;

								if(DummyBuffer[0])
								{
									if(SaveChanges(Window))
									{
										if(!SaveTranslationTables(DummyBuffer,Send,Receive))
											ShowError(Window,ERR_SAVE_ERROR,IoErr(),DummyBuffer);
									}
								}
							}
							else
								DummyBuffer[0] = 0;
						}

						if(strcmp(Config -> TranslationFileName,DummyBuffer))
						{
							strcpy(Config -> TranslationFileName,DummyBuffer);

							Changed = TRUE;
						}

						FallBack = FALSE;
					}

					if(Send)
						FreeTranslationTable(Send);

					if(Receive)
						FreeTranslationTable(Receive);
				}

				if(FallBack)
				{
					SplitFileName(Config -> TranslationFileName,&DummyChar,DummyBuffer);

					if(FileRequest = GetFile(Window,LocaleString(MSG_PHONEPANEL_SELECT_TRANSLATION_TXT),DummyBuffer,DummyChar,DummyBuffer,"#?.prefs",FALSE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SELECT_TXT),TRUE))
					{
						strcpy(Config -> TranslationFileName,DummyBuffer);

						FreeAslRequest(FileRequest);

						Changed = TRUE;
					}
				}

				break;

			case GAD_MACRO_EDIT:

				if(!(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
				{
					struct MacroKeys *Keys;

					if(Keys = (struct MacroKeys *)AllocVecPooled(sizeof(struct MacroKeys),MEMF_ANY | MEMF_CLEAR))
					{
						strcpy(DummyBuffer,Config -> MacroFileName);

						if(DummyBuffer[0])
						{
							if(!LoadMacros(DummyBuffer,Keys))
								ShowError(Window,ERR_LOAD_ERROR,IoErr(),DummyBuffer);
						}

						if(MacroPanel(Keys,DummyBuffer,FALSE,Window,NULL))
						{
							if(SaveChanges(Window))
							{
								if(!WriteIFFData(DummyBuffer,Keys,sizeof(struct MacroKeys),ID_KEYS))
									ShowError(Window,ERR_SAVE_ERROR,IoErr(),DummyBuffer);
							}
						}

						if(strcmp(Config -> MacroFileName,DummyBuffer))
						{
							strcpy(Config -> MacroFileName,DummyBuffer);

							Changed = TRUE;
						}

						FallBack = FALSE;

						FreeVecPooled(Keys);
					}
				}

				if(FallBack)
				{
					SplitFileName(Config -> MacroFileName,&DummyChar,DummyBuffer);

					if(FileRequest = GetFile(Window,LocaleString(MSG_PHONEPANEL_SELECT_KEYBOARD_MACROS_TXT),DummyBuffer,DummyChar,DummyBuffer,"#?.prefs",FALSE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SELECT_TXT),TRUE))
					{
						strcpy(Config -> MacroFileName,DummyBuffer);

						FreeAslRequest(FileRequest);

						Changed = TRUE;
					}
				}

				break;

			case GAD_CURSOR_EDIT:

				if(!(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
				{
					struct CursorKeys *Keys;

					if(Keys = (struct CursorKeys *)AllocVecPooled(sizeof(struct CursorKeys),MEMF_ANY | MEMF_CLEAR))
					{
						strcpy(DummyBuffer,Config -> CursorFileName);

						if(DummyBuffer[0])
						{
							if(!ReadIFFData(DummyBuffer,Keys,sizeof(struct CursorKeys),ID_KEYS))
							{
								ResetCursorKeys(Keys);

								ShowError(Window,ERR_LOAD_ERROR,IoErr(),DummyBuffer);
							}
						}
						else
							ResetCursorKeys(Keys);

						if(CursorPanel(Keys,DummyBuffer,Window,NULL))
						{
							if(SaveChanges(Window))
							{
								if(!WriteIFFData(DummyBuffer,Keys,sizeof(struct CursorKeys),ID_KEYS))
									ShowError(Window,ERR_SAVE_ERROR,IoErr(),DummyBuffer);
							}
						}

						if(strcmp(Config -> CursorFileName,DummyBuffer))
						{
							strcpy(Config -> CursorFileName,DummyBuffer);

							Changed = TRUE;
						}

						FallBack = FALSE;

						FreeVecPooled(Keys);
					}
				}

				if(FallBack)
				{
					SplitFileName(Config -> CursorFileName,&DummyChar,DummyBuffer);

					if(FileRequest = GetFile(Window,LocaleString(MSG_PHONEPANEL_SELECT_CURSOR_KEYS_TXT),DummyBuffer,DummyChar,DummyBuffer,"#?.prefs",FALSE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SELECT_TXT),TRUE))
					{
						strcpy(Config -> CursorFileName,DummyBuffer);

						FreeAslRequest(FileRequest);

						Changed = TRUE;
					}
				}

				break;

			case GAD_FASTMACRO_EDIT:

				if(!(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
				{
					struct List *List;

					if(List = CreateList())
					{
						strcpy(DummyBuffer,Config -> FastMacroFileName);

						if(DummyBuffer[0])
						{
							if(!LoadFastMacros(DummyBuffer,List))
								ShowError(Window,ERR_LOAD_ERROR,IoErr(),DummyBuffer);
						}

						if(FastMacroPanel(List,DummyBuffer,Window,NULL))
						{
							if(SaveChanges(Window))
							{
								if(!SaveFastMacros(DummyBuffer,List))
									ShowError(Window,ERR_SAVE_ERROR,IoErr(),DummyBuffer);
							}
						}

						if(strcmp(Config -> FastMacroFileName,DummyBuffer))
						{
							strcpy(Config -> FastMacroFileName,DummyBuffer);

							Changed = TRUE;
						}

						FallBack = FALSE;

						DeleteList(List);
					}
				}

				if(FallBack)
				{
					SplitFileName(Config -> FastMacroFileName,&DummyChar,DummyBuffer);

					if(FileRequest = GetFile(Window,LocaleString(MSG_PHONEPANEL_SELECT_FAST_MACROS_TXT),DummyBuffer,DummyChar,DummyBuffer,"#?.prefs",FALSE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SELECT_TXT),TRUE))
					{
						strcpy(Config -> FastMacroFileName,DummyBuffer);

						FreeAslRequest(FileRequest);

						Changed = TRUE;
					}
				}

				break;
		}

		if((!Changed && !Data) || Default)
		{
			DeleteConfigEntry(Config,PrefType);

			if(Default)
				Changed = TRUE;
		}
	}
	else
		DisplayBeep(Window -> WScreen);

	return(Changed);
}

BOOLEAN __regargs
ChangeState(LONG Type,UWORD Default,struct PhoneNode *Node)
{
	STATIC LONG TypeMappings[][2] =
	{
		GAD_SERIAL_STATE,		PREF_SERIAL,
		GAD_MODEM_STATE,		PREF_MODEM,
		GAD_SCREEN_STATE,		PREF_SCREEN,
		GAD_TERMINAL_STATE,		PREF_TERMINAL,
		GAD_EMULATION_STATE,	PREF_EMULATION,
		GAD_CLIPBOARD_STATE,	PREF_CLIP,
		GAD_CAPTURE_STATE,		PREF_CAPTURE,
		GAD_COMMAND_STATE,		PREF_COMMAND,
		GAD_MISC_STATE,			PREF_MISC,
		GAD_PATH_STATE,			PREF_PATH,
		GAD_TRANSFER_STATE,		PREF_TRANSFER,
		GAD_TRANSLATION_STATE,	PREF_TRANSLATIONFILENAME,
		GAD_MACRO_STATE,		PREF_MACROFILENAME,
		GAD_CURSOR_STATE,		PREF_CURSORFILENAME,
		GAD_FASTMACRO_STATE,	PREF_FASTMACROFILENAME,
		GAD_RATE_STATE,			PREF_RATES
	};

	struct Configuration	*LocalConfig;
	LONG					 PrefType;
	WORD					 i;
	APTR					 Data;

		// Find the prefs fragment that should be worked upon

	for(i = 0 ; i < sizeof(TypeMappings) / (sizeof(LONG) * 2) ; i++)
	{
		if(TypeMappings[i][0] == Type)
		{
			PrefType = TypeMappings[i][1];

			break;
		}
	}

		// This is the one we're about to put through the wringer

	LocalConfig = Node -> Entry -> Config;

		// Get a pointer to it

	Data = GetConfigEntry(LocalConfig,PrefType);

		// A special case, the phone rates

	if(PrefType == PREF_RATES)
	{
		if(Default)
		{
				// There will be some rates...

			Node -> Entry -> Header -> NoRates = FALSE;

				// Nothing in this list?

			if(!Node -> Entry -> TimeDateList . mlh_Head -> mln_Succ)
			{
				struct TimeDateNode *TimeDateNode;

					// Provide defaults

				if(TimeDateNode = CreateTimeDateNode(-1,-1,"",2))
					AddTail((struct List *)&Node -> Entry -> TimeDateList,&TimeDateNode -> VanillaNode);
				else
				{
					Node -> Entry -> Header -> NoRates = TRUE;	// Sorry, guv'nor

					return(FALSE);
				}
			}
		}
		else
		{
				// Discard the time/date list

			FreeTimeDateList((struct List *)&Node -> Entry -> TimeDateList);

				// No rates here

			Node -> Entry -> Header -> NoRates = TRUE;
		}

		return(TRUE);
	}

		// Default == TRUE means: replace fragment with a copy of the
		//                        current global configuration which the
		//                        user can edit later. Making a connection
		//                        through the phonebook will cause the
		//                        global configuration to be replaced
		//                        with this copy.

	if(Default)
	{
		BOOLEAN Result;

			// Get rid of the old stuff

		if(Data)
		{
			DeleteConfigEntry(LocalConfig,PrefType);

			Result = TRUE;
		}
		else
			Result = FALSE;

			// Create a new fragment with default values

		if(!CreateConfigEntry(LocalConfig,PrefType))
			return(Result);
	}
	else
	{
			// Default == FALSE means: discard this fragment; making a
			//                         connection through the phonebook
			//                         will then leave these main config
			//                         fragments unmodified.

		if(Data)
			DeleteConfigEntry(LocalConfig,PrefType);
		else
			return(FALSE);
	}

	return(TRUE);
}

STRPTR *
BuildLabels()
{
	LONG		 Count;
	struct Node	*Node;
	STRPTR		*Labels;
	LONG		 i;

	for(Count = 0, Node = (struct Node *)PhoneGroupList . mlh_Head ; Node -> ln_Succ ; Node = Node -> ln_Succ)
		Count++;

	if(!(Labels = (STRPTR *)AllocVecPooled(sizeof(STRPTR) * (Count + 2),MEMF_ANY)))
		return(NULL);

	Labels[0] = LocaleString(MSG_PHONEBOOK_ALL_GROUP_TXT);

	for(i = 1, Node = (struct Node *)PhoneGroupList . mlh_Head ; Node -> ln_Succ ; Node = Node -> ln_Succ)
		Labels[i++] = Node -> ln_Name;

	Labels[i] = NULL;

	return(Labels);
}

VOID __regargs
FindGroup(struct List **pCurrentList,LONG *pSelected,ULONG *pGrouper,struct List *PhoneList,struct MinList *List,struct PhoneNode *This)
{
	PhoneGroupNode		*GroupNode;
	struct PhoneNode	*Node;
	LONG				 Index;
	ULONG				 Group;

	Group = 1;

	for(GroupNode = (PhoneGroupNode *)List -> mlh_Head ; GroupNode -> Node . ln_Succ ; GroupNode = (PhoneGroupNode *)GroupNode -> Node . ln_Succ)
	{
		Index = 0;

		for(Node = (struct PhoneNode *)GroupNode -> GroupList . mlh_Head ; Node -> VanillaNode . ln_Succ ; Node = (struct PhoneNode *)Node -> VanillaNode . ln_Succ)
		{
			if(Node == This)
			{
				*pCurrentList	= (struct List *)&GroupNode -> GroupList;
				*pSelected		= Index;
				*pGrouper		= Group;

				return;
			}

			Index++;
		}

		Group++;
	}

	Index = 0;

	for(Node = (struct PhoneNode *)PhoneList -> lh_Head ; Node -> VanillaNode . ln_Succ ; Node = (struct PhoneNode *)Node -> VanillaNode . ln_Succ)
	{
		if(Node == This)
		{
			*pCurrentList	= PhoneList;
			*pSelected		= Index;
			*pGrouper		= 0;

			return;
		}

		Index++;
	}
}
