/*
**	termFastMacros.c
**
**	Fast! macros support routines
**
**	Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* NewFastMacro(STRPTR Macro,STRPTR Code):
	 *
	 *	Create a new fast! macro node.
	 */

struct MacroNode *
NewFastMacro(STRPTR Macro,STRPTR Code)
{
	if(FastMacroCount + 1 < 10000)
	{
		struct MacroNode *Node;

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

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

			return(Node);
		}
	}

	return(NULL);
}

	/* RemFastMacro(struct MacroNode *Node):
	 *
	 *	Remove and deallocate a fast! macro node.
	 */

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

	FreeVec(Node);
}

	/* GetFastMacro(LONG Offset):
	 *
	 *	Get a fast! macro node from the global list by
	 *	its index number.
	 */

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);
}

	/* ClearFastMacroList(struct List *List):
	 *
	 *	Remove all nodes from the global fast! macro list
	 *	and free them on the way.
	 */

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

	Node = List -> lh_Head;

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

		FreeVec(Node);

		Node = NextNode;
	}
}

	/* GetFastMacroOffset(struct MacroNode *MacroNode):
	 *
	 *	Get the index number of a given node in the
	 *	global fast! macro list.
	 */

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);
}

	/* MoveList(struct List *From,struct List *To):
	 *
	 *	Move the contents of a list to a different list.
	 */

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;
	}
}

	/* SaveFastMacros(STRPTR Name):
	 *
	 *	Save the fast! macro list to a file.
	 */

BYTE
SaveFastMacros(STRPTR 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,ID_TERM,ID_CAT,IFFSIZE_UNKNOWN))
				{
					if(!PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN))
					{
						if(!PushChunk(Handle,0,ID_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,ID_WIND,sizeof(struct IBox)))
									{
										struct IBox SizeBox;

										if(FastWindow)
										{
											FastWindowLeft		= FastWindow -> LeftEdge;
											FastWindowTop		= FastWindow -> TopEdge;
											FastWindowHeight	= FastWindow -> Height;
										}

										if(FastWindowHeight == -1)
											SizeBox . Height = Window -> WScreen -> WBorTop + Window -> WScreen -> Font -> ta_YSize + 1 + 2 + SZ_Height(LISTVIEW_KIND,10,0) + 2 + 8;
										else
											SizeBox . Height = FastWindowHeight;

										if(FastWindowLeft == -1)
											SizeBox . Left = Window -> WScreen -> Width - (6 + SZ_Width(LISTVIEW_KIND,NULL,19,NULL) + 6);
										else
											SizeBox . Left = FastWindowLeft;

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

										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,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN))
													{
														if(!PushChunk(Handle,0,ID_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)
		AddProtection(Name,FIBF_EXECUTE);
	else
		DeleteFile(Name);

	return(Success);
}

	/* LoadFastMacros(STRPTR Name):
	 *
	 *	Restore the fast! macro list from a file.
	 */

BYTE
LoadFastMacros(STRPTR Name)
{
	STATIC ULONG Stops[6] =
	{
		ID_TERM,ID_VERS,
		ID_TERM,ID_FAST,
		ID_TERM,ID_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,3))
				{
					while(!ParseIFF(Handle,IFFPARSE_SCAN))
					{
						Chunk = CurrentChunk(Handle);

						if(Chunk -> cn_ID == 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 == ID_WIND)
						{
							if(ReadChunkBytes(Handle,&SizeBox,sizeof(struct IBox)) == sizeof(struct IBox))
							{
								FastWindowLeft		= SizeBox . Left;
								FastWindowTop		= SizeBox . Top;
								FastWindowHeight	= SizeBox . Height;
							}
							else
								break;
						}

						if(Chunk -> cn_ID == 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);
}
