/*
**	$Id: FastMacros.c,v 1.2 92/04/06 20:10:01 olsen Sta Locker: olsen $
**	$Revision: 1.2 $
**	$Date: 92/04/06 20:10:01 $
**
**	Fast! macros support routines
**
**	Copyright © 1990-1992 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

STATIC WORD		 Left = -1,Top = -1,Height = -1;
STATIC struct Gadget	*GadgetList = NULL;
STATIC struct IBox	 Dims = { -1,-1,-1,-1 };

#define WIDTH	192
#define HEIGHT	99

VOID
RefreshFastWindow(WORD Height)
{
	struct Gadget		*Gadget;
	struct NewGadget	 NewGadget;
	WORD			 TopEdge = Screen -> WBorTop + Screen -> Font -> ta_YSize + 1;

	memset(&NewGadget,0,sizeof(struct NewGadget));

	if(GadgetList)
	{
		RemoveGList(FastWindow,GadgetList,-1);

		SetAPen(FastWindow -> RPort,0);

		RectFill(FastWindow -> RPort,FastWindow -> BorderRight,FastWindow -> BorderTop,FastWindow -> Width - (FastWindow -> BorderLeft + 1),FastWindow -> Height - (FastWindow -> BorderBottom + 1));

		FreeGadgets(GadgetList);

		GadgetList = NULL;
	}

	if(Gadget = CreateContext(&GadgetList))
	{
		NewGadget . ng_Width		= 180;
		NewGadget . ng_Height		= Height - (TopEdge + 4 + 8);
		NewGadget . ng_GadgetText	= "";
		NewGadget . ng_GadgetID		= 0;
		NewGadget . ng_LeftEdge		= 6;
		NewGadget . ng_TopEdge		= 1 + TopEdge;
		NewGadget . ng_TextAttr		= &DefaultFont;
		NewGadget . ng_VisualInfo	= VisualInfo;
	
		FastGadget = Gadget = CreateGadget(LISTVIEW_KIND,Gadget,&NewGadget,
			GTLV_Labels,	&FastMacroList,
		TAG_DONE);
	}

	if(Gadget)
	{
		AddGList(FastWindow,GadgetList,(UWORD)-1,(UWORD)-1,NULL);
		RefreshGList(GadgetList,FastWindow,NULL,(UWORD)-1);
		GT_RefreshWindow(FastWindow,NULL);
	}
	else
	{
		FreeGadgets(GadgetList);

		GadgetList = NULL;
	}
}

VOID
CloseFastWindow()
{
	if(FastWindow)
	{
		Left	= FastWindow -> LeftEdge;
		Top	= FastWindow -> TopEdge;
		Height	= FastWindow -> Height;

		ClearMenuStrip(FastWindow);
		CloseWindowSafely(FastWindow);

		FastWindow = NULL;
	}

	if(GadgetList)
	{
		FreeGadgets(GadgetList);

		GadgetList = NULL;
	}
}

BYTE
OpenFastWindow()
{
	if(Height == -1)
		Height = HEIGHT;

	if(Left == -1)
		Left = Screen -> Width - WIDTH;

	if(Top == -1)
		Top = Screen -> WBorTop + Screen -> Font -> ta_YSize + 1;

	if(Top + Height > Screen -> Height)
	{
		if(Top >= Screen -> Height - (HEIGHT - 56))
			Top = Screen -> Height - (HEIGHT - 56);

		while(Top + Height > Screen -> Height)
			Height--;
	}

	if(Dims . Left == -1)
	{
		Dims . Left	= 0;
		Dims . Top	= 0;
		Dims . Width	= WIDTH;
		Dims . Height	= Screen -> WBorTop + Screen -> Font -> ta_YSize + 1;
	}

	if(FastWindow = OpenWindowTags(NULL,
		WA_Width,	WIDTH,
		WA_Height,	Height,

		WA_Left,	Left,
		WA_Top,		Top,

		WA_DragBar,	TRUE,
		WA_DepthGadget,	TRUE,
		WA_CloseGadget,	TRUE,
		WA_RMBTrap,	TRUE,
		WA_Zoom,	&Dims,

		WA_SizeGadget,	TRUE,
		WA_SizeBBottom,	TRUE,

		WA_MinWidth,	WIDTH,
		WA_MaxWidth,	WIDTH,

		WA_MinHeight,	HEIGHT - 56,
		WA_MaxHeight,	~0,

		WA_Title,	LocaleString(MSG_FASTMACROS_FAST_MACROS_TXT),

		WA_CustomScreen,Screen,
	TAG_DONE))
	{
		FastWindow -> UserPort = Window -> UserPort;

		ModifyIDCMP(FastWindow,Window -> IDCMPFlags);

		SetMenuStrip(FastWindow,Menu);

		FastWindow -> Flags &= ~WFLG_RMBTRAP;

		RefreshFastWindow(Height);

		return(TRUE);
	}

	return(FALSE);
}

struct MacroNode *
NewFastMacro(UBYTE *Macro,UBYTE *Code)
{
	struct MacroNode *Node;

	if(Node = (struct MacroNode *)AllocVec(sizeof(struct MacroNode) + 21 + 257,MEMF_ANY|MEMF_CLEAR))
	{
		Node -> mn_Macro	= (UBYTE *)(Node + 1);
		Node -> mn_Code		= &Node -> mn_Macro[21];

		strcpy(Node -> mn_Macro,Macro);
		strcpy(Node -> mn_Code ,Code);

		return(Node);
	}

	return(NULL);
}

VOID
RemFastMacro(struct MacroNode *Node)
{
	Remove((struct Node *)Node);

	FreeVec(Node);
}

struct MacroNode *
GetFastMacro(LONG Offset)
{
	struct MacroNode	*Node;
	LONG			 i;

	Node = (struct MacroNode *)FastMacroList . lh_Head;

	for(i = 0 ; i < Offset ; i++)
	{
		if(!Node -> mn_Succ -> mn_Succ)
			return(NULL);

		Node = Node -> mn_Succ;
	}

	return(Node);
}

VOID
ClearFastMacroList(struct List *List)
{
	struct Node *Node,*NextNode;

	Node = List -> lh_Head;

	while(Node -> ln_Succ)
	{
		NextNode = Node -> ln_Succ;

		Remove(Node);

		FreeVec(Node);

		Node = NextNode;
	}
}

LONG
GetFastMacroOffset(struct MacroNode *MacroNode)
{
	struct MacroNode	*Node;
	LONG			 Offset = 0;

	Node = (struct MacroNode *)FastMacroList . lh_Head;

	while(Node -> mn_Succ)
	{
		if(Node == MacroNode)
			return(Offset);

		Offset++;

		Node = Node -> mn_Succ;
	}

	return(~0);
}

BYTE
SaveFastMacros(UBYTE *Name)
{
	struct IFFHandle	*Handle;
	BYTE			 Success = FALSE;

	if(Handle = (struct IFFHandle *)AllocIFF())
	{
		if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
		{
			InitIFFasDOS(Handle);

			if(!OpenIFF(Handle,IFFF_WRITE))
			{
				if(!PushChunk(Handle,'TERM',ID_CAT,IFFSIZE_UNKNOWN))
				{
					if(!PushChunk(Handle,'TERM',ID_FORM,IFFSIZE_UNKNOWN))
					{
						if(!PushChunk(Handle,0,'VERS',IFFSIZE_UNKNOWN))
						{
							struct TermInfo TermInfo;

							TermInfo . Version	= TermVersion;
							TermInfo . Revision	= TermRevision;

							if(WriteChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
							{
								if(PopChunk(Handle))
									Success = FALSE;
								else
								{
									if(!PushChunk(Handle,0,'WIND',sizeof(struct IBox)))
									{
										struct IBox SizeBox;

										if(FastWindow)
										{
											Left	= FastWindow -> LeftEdge;
											Top	= FastWindow -> TopEdge;
											Height	= FastWindow -> Height;
										}

										if(Height == -1)
											SizeBox . Height = HEIGHT;
										else
											SizeBox . Height = Height;

										if(Left == -1)
											SizeBox . Left = Screen -> Width - WIDTH;
										else
											SizeBox . Left = Left;

										if(Top == -1)
											SizeBox . Top = Screen -> WBorTop + Screen -> Font -> ta_YSize + 1;
										else
											SizeBox . Top = Top;

										if(WriteChunkBytes(Handle,&SizeBox,sizeof(struct IBox)) == sizeof(struct IBox))
										{
											if(PopChunk(Handle))
												Success = FALSE;
											else
											{
												struct MacroNode *Node;

												Node = (struct MacroNode *)FastMacroList . lh_Head;

												while(Node -> mn_Succ)
												{
													if(!PushChunk(Handle,'TERM',ID_FORM,IFFSIZE_UNKNOWN))
													{
														if(!PushChunk(Handle,0,'FAST',IFFSIZE_UNKNOWN))
														{
															if(WriteChunkBytes(Handle,Node -> mn_Macro,20) != 20)
															{
																Success = FALSE;

																break;
															}
															else
															{
																if(WriteChunkBytes(Handle,Node -> mn_Code,256) != 256)
																{
																	Success = FALSE;

																	break;
																}
																else
																{
																	if(PopChunk(Handle))
																	{
																		Success = FALSE;

																		break;
																	}
																	else
																		Success = TRUE;
																}
															}
														}

														if(Success)
														{
															if(PopChunk(Handle))
															{
																Success = FALSE;

																break;
															}
														}
													}

													Node = Node -> mn_Succ;
												}
											}
										}
									}
								}
							}
						}

						if(PopChunk(Handle))
							Success = FALSE;
					}

					if(PopChunk(Handle))
						Success = FALSE;
				}

				CloseIFF(Handle);
			}

			Close(Handle -> iff_Stream);
		}

		FreeIFF(Handle);
	}

	if(Success)
		SetProtection(Name,FIBF_EXECUTE);
	else
		DeleteFile(Name);

	return(Success);
}

VOID __regargs
MoveList(struct List *From,struct List *To)
{
	struct Node *Node,*NextNode;

	Node = From -> lh_Head;

	while(NextNode = Node -> ln_Succ)
	{
		Remove(Node);

		AddTail(To,Node);

		Node = NextNode;
	}
}

BYTE
LoadFastMacros(UBYTE *Name)
{
	STATIC ULONG Stops[6] =
	{
		'TERM','VERS',
		'TERM','FAST',
		'TERM','WIND'
	};

	struct List __aligned	 NewFastMacroList;
	LONG			 NewFastMacroCount = 0;
	struct IFFHandle	*Handle;
	BYTE			 Success = FALSE;
	struct MacroNode	*Node;
	struct ContextNode	*Chunk;
	struct IBox		 SizeBox;

	NewList(&NewFastMacroList);

	if(Handle = AllocIFF())
	{
		if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
		{
			InitIFFasDOS(Handle);

			if(!OpenIFF(Handle,IFFF_READ))
			{
				if(!StopChunks(Handle,&Stops[0],3))
				{
					while(!ParseIFF(Handle,IFFPARSE_SCAN))
					{
						Chunk = CurrentChunk(Handle);

						if(Chunk -> cn_ID == 'VERS')
						{
							struct TermInfo TermInfo;

							if(ReadChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
							{
								if((TermInfo . Version > TermVersion) || (TermInfo . Version == TermVersion && TermInfo . Revision > TermRevision) || (TermInfo . Version == 1 && TermInfo . Revision < 6))
									break;
							}
							else
								break;
						}

						if(Chunk -> cn_ID == 'WIND')
						{
							if(ReadChunkBytes(Handle,&SizeBox,sizeof(struct IBox)) == sizeof(struct IBox))
							{
								Left	= SizeBox . Left;
								Top	= SizeBox . Top;
								Height	= SizeBox . Height;
							}
							else
								break;
						}

						if(Chunk -> cn_ID == 'FAST')
						{
							if(Node = NewFastMacro("",""))
							{
								if(ReadChunkBytes(Handle,Node -> mn_Macro,20) == 20)
								{
									if(ReadChunkBytes(Handle,Node -> mn_Code,256) == 256)
									{
										AddTail(&NewFastMacroList,(struct Node *)Node);

										NewFastMacroCount++;

										Success = TRUE;
									}
									else
										break;
								}
								else
									break;
							}
							else
								break;
						}
					}

					if(Success)
					{
						if(NewFastMacroList . lh_Head -> ln_Succ)
						{
							ClearFastMacroList(&FastMacroList);

							MoveList(&NewFastMacroList,&FastMacroList);

							FastMacroCount = NewFastMacroCount;
						}
					}
					else
						ClearFastMacroList(&NewFastMacroList);
				}

				CloseIFF(Handle);
			}

			Close(Handle -> iff_Stream);
		}

		FreeIFF(Handle);
	}

	return(Success);
}
