/*
***************************************************************************
*
* Datei:
*	  RSysSaveWindow.c
*
* Inhalt:
*
*      --- Globale Routinen ---
*
*    void SaveWindows ( void );
*
*      --- Lokale  Routinen ---
*
*    static BYTE PutANNO ( struct IFFHandle *Handle );
*    static BYTE PutBMHD ( struct IFFHandle *Handle , struct Window *Window , UBYTE Compression );
*    static BYTE PutBODY ( struct IFFHandle *Handle , struct BitMap *BitMap , UBYTE Compression );
*    static BYTE PutCAMG ( struct IFFHandle *Handle , struct ViewPort *VPort );
*    static BYTE PutCMAP ( struct IFFHandle *Handle , struct ViewPort *VPort );
*    static BYTE SaveWindow ( STRPTR Name , struct Window *Window );
*    static int OpenSaveAWindowWindow ( void );
*    static LONG PackRow ( PLANEPTR *SourcePtr , register PLANEPTR Destination , LONG RowSize );
*    static PLANEPTR PutDump ( register PLANEPTR Destination , register LONG Count );
*    static PLANEPTR PutRun ( register PLANEPTR Destination , LONG Count , WORD Char );
*    static void CreateWinList ( int count );
*    static void ResetWinList ( void );
*
* Bemerkungen:
*	  Erzeugen einer IFF-Datei aus einem Window.
*
* Erstellungsdatum:
*	  07-Jan-93 	Rolf Böhme
*
* Änderungen:
*	  07-Jan-93 	Rolf Böhme	  Erstellung
*
***************************************************************************
*/

#include "RSys.h"

	/*
	 * Diese Routinen habe ich wieder mal aus der
	 * "Quellen-Fundgrube" von TERM entnommen.  Danke Olaf!	Aber
	 * einiges war leider falsch :-)
	 */

	/* A bitmap header. */

typedef struct
{
	UWORD		w,h;			/* raster width & height in pixels */
	WORD		x,y;			/* position for this image */
	UBYTE		nPlanes;		/* # source bitplanes */
	UBYTE		masking;		/* masking technique */
	UBYTE		compression;		/* compression algorithm */
	UBYTE		pad1;			/* UNUSED.  For consistency, put 0 here.*/
	UWORD		transparentColor;	/* transparent "color number" */
	UBYTE		xAspect,yAspect;	/* aspect ratio, a rational number x/y */
	WORD		pageWidth,pageHeight;	/* source "page" size in pixels */
} BitMapHeader;

	/* A single 8-bit colour register. */

typedef struct
{
	UBYTE		red,			/* red component, 0..255 */
			green,			/* green component, 0..255 */
			blue;			/* blue component, 0..255 */
} ColorRegister;


	/* Local packer data. */

static LONG		PackedBytes;
static BYTE		Buffer[MAXDAT + 1];

	/* PutDump(register PLANEPTR Destination,register LONG Count):
	 *
	 *	Output a byte dump.
	 */

static PLANEPTR
PutDump(register PLANEPTR Destination,register LONG Count)
{
	register PLANEPTR Source = (PLANEPTR)Buffer;

	*Destination++	 = Count - 1;
	 PackedBytes	+= Count + 1;

	while(Count--) *Destination++ = *Source++;

	return Destination;
}

	/* PutRun(register PLANEPTR Destination,LONG Count,WORD Char):
	 *
	 *	Output a byte run.
	 */

static PLANEPTR
PutRun(register PLANEPTR Destination,LONG Count,WORD Char)
{
	*Destination++	 = -(Count - 1);
	*Destination++	 = Char;
	 PackedBytes	+= 2;

	return Destination;
}

	/* PackRow(PLANEPTR *SourcePtr,register PLANEPTR Destination,LONG RowSize):
	 *
	 *	Pack a row of bitmap data using ByteRun compression,
	 *	based on the original "EA IFF 85" pack.c example code.
	 */

static LONG
PackRow(PLANEPTR *SourcePtr,register PLANEPTR Destination,LONG RowSize)
{
	register PLANEPTR Source = *SourcePtr;

	WORD	Buffered	= 1,
		RunStart	= 0;
	BYTE	Mode		= DUMP,
		LastChar,
		Char;

	PackedBytes = 0;

	Buffer[0] = LastChar = Char = *Source++;

	RowSize--;

	while(RowSize--)
	{
		Buffer[Buffered++] = Char = *Source++;

		if(Mode)
		{
			if((Char != LastChar) || (Buffered - RunStart > MAXRUN))
			{
				Destination	= PutRun(Destination,Buffered - 1 - RunStart,LastChar);
				Buffer[0]	= Char;
				Buffered	= 1;
				RunStart	= 0;
				Mode		= DUMP;
			}
		}
		else
		{
			if(Buffered > MAXDAT)
			{
				Destination	= PutDump(Destination,Buffered - 1);
				Buffer[0]	= Char;
				Buffered	= 1;
				RunStart	= 0;
			}
			else
			{
				if(Char == LastChar)
				{
					if(Buffered - RunStart >= MINRUN)
					{
						if(RunStart) Destination = PutDump(Destination,(LONG)RunStart);

						Mode = RUN;
					}
					else
					{
						if(!RunStart) Mode = RUN;
					}
				}
				else RunStart = Buffered - 1;
			}
		}

		LastChar = Char;
	}

	if(Mode) PutRun(Destination,Buffered - RunStart,LastChar);
	else
		PutDump(Destination,(LONG)Buffered);

	*SourcePtr = Source;

	return PackedBytes;
}

	/* PutANNO(struct IFFHandle *Handle):
	 *
	 *	Output `ANNO' chunk.
	 */

static BYTE
PutANNO(struct IFFHandle *Handle)
{
	extern char *v;
		WORD	Len;

	Len = strlen(&v[1]);

		/* Push the `ANNO' chunk on the stack. */

	if(!PushChunk(Handle,0,ID_ANNO,(long)Len))
	{
			/* Write the creator string. */

		if(WriteChunkBytes(Handle,&v[1],(long)Len) == Len)
		{
				/* Pop the `ANNO' chunk. */

			if(!PopChunk(Handle)) return TRUE;
		}
	}

	return FALSE;
}

	/* PutBMHD():
	 *
	 *	Output `BMHD' chunk.
	 */

static BYTE
PutBMHD(struct IFFHandle *Handle,struct Window *Window,UBYTE Compression)
{
	struct DisplayInfo DisplayInfo;

		/* Get the display aspect ratio. */

	if(GetDisplayInfoData(NULL,
								 (APTR)&DisplayInfo,
								 sizeof(struct DisplayInfo),
								 DTAG_DISP,
								 GetVPModeID(&Window -> WScreen -> ViewPort)))
	{
		BitMapHeader Header;

			/* Fill in the bitmap header. */

		Header . w			= Window -> Width;
		Header . h			= Window -> Height;
		Header . pageWidth		= Window /*-> WScreen*/ -> Width;
		Header . pageHeight		= Window /*-> WScreen*/ -> Height;
		Header . x			= Window -> LeftEdge;
		Header . y			= Window -> TopEdge;
		Header . nPlanes		= Window /*-> WScreen*/ -> RPort -> BitMap -> Depth;
		Header . masking		= mskNone;
		Header . compression		= Compression;
		Header . pad1			= 0;
		Header . transparentColor	= 0;
		Header . xAspect		= DisplayInfo . Resolution . x;
		Header . yAspect		= DisplayInfo . Resolution . y;

			/* Push the `BMHD' chunk on the stack. */

		if(!PushChunk(Handle,0,ID_BMHD,sizeof(BitMapHeader)))
		{
				/* Write the bitmap header. */

			if(WriteChunkBytes(Handle,&Header,sizeof(BitMapHeader)) == sizeof(BitMapHeader))
			{
					/* Pop the `BMHD' chunk. */

				if(!PopChunk(Handle)) return TRUE;
			}
		}
	}

	return FALSE;
}

	/* PutCMAP(struct IFFHandle *Handle,struct ViewPort *VPort):
	 *
	 *	Output `CMAP' chunk, only 4-bit colour registers
	 *	are supported so far.
	 */

static BYTE
PutCMAP(struct IFFHandle *Handle,struct ViewPort *VPort)
{
		/* Push the `CMAP' chunk on the stack. */

	if(!PushChunk(Handle,0,ID_CMAP,3 * VPort -> ColorMap -> Count))
	{
		ColorRegister	Colour;
		LONG		i;
		ULONG		Value,
				R,G,B;

			/* Read and convert all the
			 * ColorMap entries (4 bit colour
			 * components only).
			 */

		for(i = 0 ; i < VPort -> ColorMap -> Count ; i++)
		{
				/* Read colour value. */

			Value = GetRGB4(VPort -> ColorMap,i);

				/* Split the value into components. */

			R = (Value >> 8) & 0xF;
			G = (Value >> 4) & 0xF;
			B = (Value		) & 0xF;

				/* Store the colour components. */

			Colour . red	= (R << 4) | R;
			Colour . green	= (G << 4) | G;
			Colour . blue	= (B << 4) | B;

				/* Write the colours. */

			if(WriteChunkBytes(Handle,&Colour,3) != 3) return(FALSE);
		}

			/* Pop the `CMAP' chunk. */

		if(!PopChunk(Handle)) return TRUE;
	}

	return FALSE;
}

	/* PutCAMG(struct IFFHandle *Handle,struct ViewPort *VPort):
	 *
	 *	Output `CAMG' chunk.
	 */

static BYTE
PutCAMG(struct IFFHandle *Handle,struct ViewPort *VPort)
{
	if(!PushChunk(Handle,0,ID_CAMG,sizeof(ULONG)))
	{
		ULONG ViewModes = GetVPModeID(VPort),ulongsize = sizeof(ULONG);

		if(WriteChunkBytes(Handle,&ViewModes,ulongsize) == ulongsize)
		{
			if(!PopChunk(Handle)) return TRUE;
		}
	}

	return FALSE;
}

	/* PutBODY(struct IFFHandle *Handle)
	 *
	 *	Output `BODY' chunk.
	 */

static BYTE
PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap,UBYTE Compression)
{
	BYTE Success = FALSE;

	PLANEPTR *Planes;

		/* Allocate temporary bitplane pointers. */

	if(Planes = (PLANEPTR *)MyAllocVec(BitMap -> Depth * sizeof(PLANEPTR *),MEMF_ANY | MEMF_CLEAR, NO_KILL))
	{
		register LONG i;

			/* Copy the bitplane pointers. */

		for(i = 0 ; i < BitMap -> Depth ; i++) Planes[i] = BitMap -> Planes[i];

			/* Are we to compress the data? */

		if(Compression == cmpByteRun1)
		{
			PLANEPTR PackBuffer;

				/* Allocate line compression buffer. */

			if(PackBuffer = (PLANEPTR)MyAllocVec(BitMap -> BytesPerRow * 2,MEMF_ANY, NO_KILL))
			{
					/* Push the `BODY' chunk on the stack. */

				if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
				{
					register LONG	PackedBytes,
							j;

						/* So far, we are quite successful,
						 * any write access to fail will
						 * cause `Success' to drop to FALSE.
						 */

					Success = TRUE;

						/* Compress all the rows. */

					for(i = 0 ; Success && i < BitMap -> Rows ; i++)
					{
							/* Compress all the planes. */

						for(j = 0 ; Success && j < BitMap -> Depth ; j++)
						{
								/* Do the compression. */

							PackedBytes = PackRow(&Planes[j],PackBuffer,(LONG)BitMap -> BytesPerRow);

								/* Write the compressed data. */

							if(WriteChunkBytes(Handle,PackBuffer,PackedBytes) != PackedBytes)
								Success = FALSE;
						}
					}

						/* Pop the `BODY' chunk. */

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

					/* Free the line compression buffer. */

				MyFreeVec(PackBuffer);
			}
		}
		else
		{
				/* Push the `BODY' chunk on the stack. */

			if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
			{
				register LONG j;

					/* So far, we are quite successful,
					 * any write access to fail will
					 * cause `Success' to drop to FALSE.
					 */

				Success = TRUE;

					/* Compress all the rows. */

				for(i = 0 ; Success && i < BitMap -> Rows ; i++)
				{
						/* Compress all the planes. */

					for(j = 0 ; Success && j < BitMap -> Depth ; j++)
					{
							/* Write the row. */

						if(WriteChunkBytes(Handle,Planes[j],(long)BitMap -> BytesPerRow) != BitMap -> BytesPerRow)
							Success = FALSE;
						else
							Planes[j] += BitMap -> BytesPerRow;
					}
				}

					/* Pop the `BODY' chunk. */

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

			/* Free the temporary bitplane pointers. */

		MyFreeVec(Planes);
	}

		/* Return the result. */

	return Success;
}

	/* SaveWindow(STRPTR Name,struct Window *Window):
	 *
	 *	Save the contents of a window to a file.
	 */

static BYTE
SaveWindow(STRPTR Name,struct Window *Window)
{
	struct RastPort		*RPort;
	BYTE			 Success = FALSE,
				 NewFile = FALSE;

	if(IFFParseBase = OpenLibrary((STRPTR)"iffparse.library",0))
	{
			/* Allocate a dummy rastport, we will need only
			 * to copy the contents of the window into the
			 * bitmap.
			 */

		if(RPort = (struct RastPort *)MyAllocVec(sizeof(struct RastPort),MEMF_ANY, NO_KILL))
		{
			struct BitMap *BitMap;

				/* Initialize the rastport with defaults. */

			InitRastPort(RPort);

				/* Allocate a bitmap. */

			if(BitMap = (struct BitMap *)MyAllocVec(sizeof(struct BitMap),MEMF_ANY, NO_KILL))
			{
				WORD i;

					/* Put it into the rastport. */

				RPort -> BitMap = BitMap;

					/* Initialize it with the window dimensions. */

					/*
					 * An dieser Stelle ist der RastPort des Fensters
					 * zu nehmen, NICHT der des Screens, zu dem das
					 * Fenster gehört!
					 */
				InitBitMap(BitMap,
							  (long)Window -> RPort -> BitMap -> Depth,
							  (long)(Window -> Width),
							  (long)Window -> Height);

					/* Flag success so any allocation
					 * to fail in the bitplane allocation
					 * loop will indicate failure.
					 */

				Success = TRUE;

					/* Allocate all the bitplanes necessary. */

				for(i = 0 ; Success && i < BitMap -> Depth ; i++)
				{
					if(!(BitMap -> Planes[i] = AllocRaster((long)Window -> Width,(long)Window -> Height)))
						Success = FALSE;
				}

					/* Did we get all the planes we wanted? */

				if(Success)
				{
					struct IFFHandle *Handle;

						/* Copy the window contents to the
						 * local bitmap.
						 */
					if(NOT(Window->Flags & WFLG_BACKDROP)) WindowToFront(Window);

					Delay(10);

						/*
						 * ClipBlit() arbeitet nicht korrekt! Ich habe
						 * die Routine durch BltBitMap() ersetzt
						 */
					/*
					 * ClipBlit(Window -> RPort,0,0,RPort,0,0,(long)Window -> Width,(long)Window -> Height,0xC0);
					 */

					BltBitMap(Window->RPort->BitMap,
								 (long)Window -> LeftEdge,(long)Window -> TopEdge,BitMap,
								 0,0,(long)Window -> Width,(long)Window -> Height,0xC0,0xFF,NULL);

						/* Reset the success indicator. */

					Success = FALSE;

						/* Allocate an iff handle. */

					if(Handle = AllocIFF())
					{
							/* Open a file for write access. */

						if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
						{
								/* Remember that we succeeded
								 * in creating a new file.
								 */

							NewFile = TRUE;

								/* Tell iffparse.library that it's
								 * a plain AmigaDOS file handle.
								 */

							InitIFFasDOS(Handle);

								/* Open the file for writing. */

							if(!OpenIFF(Handle,IFFF_WRITE))
							{
									/* Push parent chunk on the
									 * stack.
									 */

								if(!PushChunk(Handle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN))
								{
										/* Output all the chunk data. */

									if(PutANNO(Handle))
									{
										UBYTE Compression;

											/* Don't compress the bitmap if
											 * isn't really worth it.
											 */
										if(BitMap -> BytesPerRow > 4) Compression = cmpByteRun1;
										else
											Compression = cmpNone;

										if(PutBMHD(Handle,Window,Compression))
										{
											if(PutCMAP(Handle,&Window -> WScreen -> ViewPort))
											{
												if(PutCAMG(Handle,&Window -> WScreen -> ViewPort))
												{
													if(PutBODY(Handle,BitMap,Compression))
													{
															/* Pop the parent chunk
															 * from the stack.
															 */

														if(!PopChunk(Handle)) Success = TRUE;
													}
												}
											}
										}
									}
								}

									/* Close the iff handle. */

								CloseIFF(Handle);
							}

								/* Close the file. */

							if(!Close(Handle -> iff_Stream)) Success = FALSE;
						}

							/* Free the iff handle. */

						FreeIFF(Handle);
					}
				}

					/* Free all bitplanes. */

				for(i = 0 ; i < BitMap -> Depth ; i++)
				{
					if(BitMap -> Planes[i]) FreeRaster(BitMap -> Planes[i],(long)Window -> Width,(long)Window -> Height);
				}

					/* Free the bitmap. */

				MyFreeVec(BitMap);
			}

				/* Free the rastport. */

			MyFreeVec(RPort);
		}

			/* If successful, clear the `executable' bit. */

		if(Success) SetProtection(Name,FIBF_EXECUTE);
		else
		{
				/* Delete the remains of the file. */

			if(NewFile) DeleteFile(Name);
		}

		CloseLibrary(IFFParseBase);
	}
	else Success = FALSE;

		/* Return the result. */

	return Success;
}

struct winlist
{
	struct Node node;
	struct Window *win;
	char name[MAXFULLNAME];
} *windows = NULL;

struct List WinList;

static struct Window 		  *SaveAWindowWnd = NULL;
static struct Gadget 		  *SaveAWindowGList = NULL;
static struct Gadget 		  *SaveAWindowGadgets[3];
static UWORD						SaveAWindowLeft = 178;
static UWORD						SaveAWindowTop = 38;
static UWORD						SaveAWindowWidth = 258;
static UWORD						SaveAWindowHeight = 121;
static UBYTE					  *SaveAWindowWdt = (UBYTE *)NAME " " VERSION " - Save window";

static UWORD SaveAWindowGTypes[] = {
	LISTVIEW_KIND,
	BUTTON_KIND,
	BUTTON_KIND
};

static struct NewGadget SaveAWindowNGad[] = {
	8, 18, 241, 80, (UBYTE *)"Windows", NULL, GD_WindowsLVGad, PLACETEXT_ABOVE, NULL, NULL,
	8, 103, 113, 13, (UBYTE *)"IFF File", NULL, GD_SaveIFFGad, PLACETEXT_IN, NULL, NULL,
	128, 103, 121, 13, (UBYTE *)"Rescan windows", NULL, GD_ResetWinGad, PLACETEXT_IN, NULL, NULL
};

static ULONG *SaveAWindowGTags[] = {
	(ULONG *)(GTLV_ShowSelected), (ULONG *)NULL,(ULONG *)(GTLV_Labels), (ULONG *)&WinList, (ULONG *)(TAG_DONE),
	(ULONG *)(TAG_DONE),
	(ULONG *)(TAG_DONE)
};

	/*
	 * OpenSaveAWindowWindow() öffnet ein Fenster mit einem
	 * ListView und zwei Gadgets zu Auswahl eines zu speichernden
	 * Fensters
	 */
static int
OpenSaveAWindowWindow( void )
{
	struct NewGadget	ng;
	struct Gadget	*g;
	UWORD		lc, tc;
	UWORD		wleft = SaveAWindowLeft, wtop = SaveAWindowTop, ww, wh;
	int gl[] = {GD_WindowsLVGad - GD_WindowsLVGad};

   AdjustWindowDimensions(Scr, SaveAWindowLeft, SaveAWindowTop, SaveAWindowWidth, SaveAWindowHeight,
                               &wleft, &wtop, &ww, &wh);

	if ( ! ( g = CreateContext( &SaveAWindowGList ))) return 1L;

	for( lc = 0, tc = 0; lc < SaveAWindow_CNT; lc++ )
   {
		CopyMem((char * )&SaveAWindowNGad[ lc ], (char * )&ng, (long)sizeof( struct NewGadget ));

		ng.ng_VisualInfo = VisualInfo;
		ng.ng_TextAttr	 = Font;
		ng.ng_LeftEdge	 = OffX + ComputeX( ng.ng_LeftEdge );
		ng.ng_TopEdge	 = OffY + ComputeY( ng.ng_TopEdge );
		ng.ng_Width		 = ComputeX( ng.ng_Width );
		ng.ng_Height 	 = ComputeY( ng.ng_Height);

		SaveAWindowGadgets[ lc ] = g = CreateGadgetA((ULONG)SaveAWindowGTypes[ lc ], g, &ng, ( struct TagItem * )&SaveAWindowGTags[ tc ] );

		makelabelvisible(SaveAWindowGadgets[lc]);

		while( SaveAWindowGTags[ tc ] ) tc += 2;
		tc++;

		if ( NOT g ) return 2L;
	}

	if ( ! ( SaveAWindowWnd = OpenWindowTags( NULL,
				WA_Left,	wleft,
				WA_Top,		wtop,
				WA_Width,	ww,
				WA_Height,	wh,
				WA_IDCMP,	LISTVIEWIDCMP|
				BUTTONIDCMP|
				IDCMP_CLOSEWINDOW|
				IDCMP_VANILLAKEY|
				IDCMP_REFRESHWINDOW,
				WA_Flags,	WFLG_DRAGBAR|
				WFLG_DEPTHGADGET|
				WFLG_CLOSEGADGET|
				WFLG_SMART_REFRESH|
				WFLG_ACTIVATE|
				WFLG_RMBTRAP,
				WA_Title,	SaveAWindowWdt,
				WA_PubScreenFallBack,TRUE,
				WA_PubScreen, Scr,
				TAG_DONE )))
	return 4L;

	RefreshRastPort(SaveAWindowWnd,SaveAWindowGadgets,gl, 1, FALSE, SaveAWindowGList);

	return NULL;
}

	/*
	 * CreateWinList() erzeugt eine Liste von Fenstertiteln und
	 * Adressen
	 */
static void
CreateWinList(int count)
{
	ULONG lock;
	struct Window *win;
	struct Screen *scr;
	char help[MAXFULLNAME];
	int	i = 0;

	DPOS;
	MyFreeVec(windows);

	windows = (struct winlist *) MyAllocVec(count * sizeof(struct winlist),
														 MEMF_ANY | MEMF_CLEAR, KILL);

	lock = LockIBase(NULL);

	for (scr = IntuitionBase->FirstScreen; scr && (i < count); scr = scr->NextScreen)
		for (win = scr->FirstWindow; win && (i < count); win = win->NextWindow)
		{
			windows[i].node.ln_Name = windows[i].name;
			windows[i].node.ln_Type = NT_USER;

			windows[i].win = win;

			if ((char *)win->Title) strncpy(help,(char *)win->Title, MAXFULLNAME - 1);
			else
				help[0] = STRINGEND;

			sprintf(windows[i].name,"0x%08lx %s",windows[i].win,help);

			i++;
		}

	UnlockIBase(lock);

	for (i = 0; i < count; i++) AddTail(&WinList, &windows[i].node);

	return;
}

	/*
	 * ResetWinList() erneuert die Window-Liste
	 */
static void
ResetWinList(void)
{
	register int cntwin;

	DPOS;
	InitListView(SaveAWindowWnd,SaveAWindowGadgets[GD_WindowsLVGad - GD_WindowsLVGad],NULL,0);

	NewList(&WinList);

	cntwin = CountIntuiObjects((int)WINDOWS);

	CreateWinList(cntwin);

	InitListView(SaveAWindowWnd,SaveAWindowGadgets[GD_WindowsLVGad - GD_WindowsLVGad],&WinList,0);

	EnableGadget(SaveAWindowWnd,SaveAWindowGadgets[GD_SaveIFFGad - GD_WindowsLVGad],FALSE);

	return;
}

	/*
	 * SaveWindows() bietet eine Benutzeroberfläche an und
	 * verwaltet die Benutzereingaben
	 */
void
SaveWindows(void)
{
	struct IntuiMessage *message;
	ULONG class,
			code;
	APTR	object;
	struct Node *clickednode = NULL;
	struct Window *printwin;
	int id;

	DPOS;

   HandleHelp(MN_SaveWindows);

	Flags.quit_sw = 0;

	NewList(&WinList);

	windows = NULL;

	if (OpenASysWindow(OpenSaveAWindowWindow,NO_KILL))
	{
		PrintInfo("Save windows", SPEAK, 0);

      LockMainWindow(LOCK);

		ResetWinList();

		do
		{
			Wait(1L << SaveAWindowWnd->UserPort->mp_SigBit);

			while ((message = (struct IntuiMessage *) GT_GetIMsg(SaveAWindowWnd->UserPort)) != NULL)
			{
				class = message->Class;
				code = message->Code;
				object = message->IAddress;

				GT_ReplyIMsg(message);

				switch(class)
				{
					case IDCMP_CLOSEWINDOW:
						Flags.quit_sw = 1;
						break;

					case IDCMP_GADGETUP:
						id = ((struct Gadget *)object)->GadgetID;

						switch(id)
						{
							case GD_WindowsLVGad:
								if(clickednode = GetNode(&WinList,code))
									EnableGadget(SaveAWindowWnd,SaveAWindowGadgets[GD_SaveIFFGad - GD_WindowsLVGad],
													 TRUE);

								printwin = ((struct winlist *)clickednode)->win;

								if(NOT(CheckWindow(printwin)))
								{
									ErrorHandle(clickednode->ln_Name, WINDOW_ERR, FIND_FAIL, NO_KILL);
									clickednode = NULL;
									ResetWinList();
								}

								break;

							case GD_SaveIFFGad:
								if(clickednode)
								{
									if (GetFile(SaveAWindowWnd,"RAM:",
													"RSys-Window.IFF","#?.IFF",
													"Select IFF-File for saving Window",
													"Save"))
									{
										printwin = ((struct winlist *)clickednode)->win;

										if(CheckWindow(printwin))
										{
											if(NOT(SaveWindow((STRPTR)_fullpath,printwin)))
												ErrorHandle(_fullpath, FILE_ERR, WRITE_FAIL,NO_KILL);
										}
										else
											ErrorHandle(clickednode->ln_Name, WINDOW_ERR, FIND_FAIL, NO_KILL);

										ResetWinList();
									}
								}
								break;

							case GD_ResetWinGad:
								clickednode = NULL;
								ResetWinList();
								break;
						}
						break;

					case IDCMP_VANILLAKEY:
						if((char)code == ESC) Flags.quit_sw = 1;
						break;
				}
			}
		} while (NOT(Flags.quit_sw));

		CloseASysWindow(&SaveAWindowWnd, &SaveAWindowGList, NULL);

		MyFreeVec(windows);

      LockMainWindow(UNLOCK);
	}

	return;
}
