/*
**	Clip.c
**
**	Clipboard support routines
**
**	Copyright © 1990-1996 by Olaf `Olsen' Barthel
**		All Rights Reserved
*/

#ifndef _GLOBAL_H
#include "Global.h"
#endif

STATIC struct IFFHandle	*ClipHandle;
STATIC STRPTR		 ClipBuffer,
			 ClipIndex;
STATIC LONG		 ClipSize,
			 ClipLength;

	/* CloseClip():
	 *
	 *	Close clipboard handle, stop reading.
	 */

VOID
CloseClip()
{
	if(ClipHandle)
	{
		CloseIFF(ClipHandle);

		if(ClipHandle -> iff_Stream)
			CloseClipboard((struct ClipboardHandle *)ClipHandle -> iff_Stream);

		FreeIFF(ClipHandle);

		ClipHandle = NULL;
	}

	FreeVecPooled(ClipBuffer);
	ClipBuffer = NULL;
}

	/* GetClip(STRPTR Buffer,LONG Len,BOO Filter):
	 *
	 *	Read text data from clipboard and put it into the supplied buffer.
	 */

LONG
GetClip(STRPTR Buffer,LONG Len,BOOL Filter)
{
	LONG	BytesPut = 0;
	LONG	c;

		/* Is the read buffer already exhausted? */

	if(!ClipLength)
	{
			/* Is there still any data to read? */

		if(ClipSize)
		{
			LONG Size = MIN(ClipSize,1024);

				/* Try to read the data and return failure if necessary. */

			if(ReadChunkBytes(ClipHandle,ClipBuffer,Size) != Size)
				return(-1);
			else
			{
				ClipSize	-= Size;
				ClipLength	 = Size;
				ClipIndex	 = ClipBuffer;
			}
		}
		else
		{
				/* We just parsed a single chunk, now go on and
				 * look for another one.
				 */

			if(!ParseIFF(ClipHandle,IFFPARSE_SCAN))
			{
				struct ContextNode *ContextNode = CurrentChunk(ClipHandle);

				if(ContextNode -> cn_Type == ID_FTXT)
				{
					LONG Size;

					ClipSize	= ContextNode -> cn_Size;
					Size		= MIN(ClipSize,1024);

					if(ReadChunkBytes(ClipHandle,ClipBuffer,Size) != Size)
						return(-1);
					else
					{
						ClipSize	-= Size;
						ClipLength	 = Size;
						ClipIndex	 = ClipBuffer;
					}
				}
				else
					return(-1);
			}
			else
				return(-1);
		}
	}

	while(ClipLength && BytesPut < Len)
	{
		ClipLength--;

		switch(c = *ClipIndex++)
		{
			case '\r':

				break;

			default:

				if(IsPrintable[c])
				{
					*Buffer++ = c;
					BytesPut++;
				}

				break;
		}
	}

	return(BytesPut);
}

	/* OpenClip():
	 *
	 *	Open the clipboard for sequential reading.
	 */

LONG
OpenClip(LONG Unit)
{
	LONG Error;

	CloseClip();

	if(ClipBuffer = (STRPTR)AllocVecPooled(1024,MEMF_ANY))
	{
		if(ClipHandle = AllocIFF())
		{
			if(ClipHandle -> iff_Stream = (ULONG)OpenClipboard(Unit))
			{
				InitIFFasClip(ClipHandle);

				if(!OpenIFF(ClipHandle,IFFF_READ))
				{
					if(!StopChunk(ClipHandle,ID_FTXT,ID_CHRS))
					{
						if(!ParseIFF(ClipHandle,IFFPARSE_SCAN))
						{
							struct ContextNode *ContextNode = CurrentChunk(ClipHandle);

							if(ContextNode -> cn_Type == ID_FTXT)
							{
								ClipSize	= ContextNode -> cn_Size;
								ClipLength	= 0;

								return(CLIPERR_NONE);
							}
							else
								Error = CLIPERR_NOTEXT;
						}
						else
							Error = CLIPERR_NOTEXT;
					}
					else
						Error = CLIPERR_IFF;
				}
				else
					Error = CLIPERR_OPEN;
			}
			else
				Error = CLIPERR_OPEN;
		}
		else
			Error = CLIPERR_MEM;
	}
	else
		Error = CLIPERR_MEM;

	CloseClip();

	return(Error);
}

	/* GetClipContents(LONG Unit,APTR *Buffer,LONG *Size):
	 *
	 *	Merge text contents of the clipboard into a single string.
	 */

BOOL
GetClipContents(LONG Unit,APTR *Buffer,LONG *Size)
{
	struct IFFHandle	*Handle;
	LONG			 Bytes = 0;
	APTR			 Store = NULL;

	if(Handle = AllocIFF())
	{
		if(Handle -> iff_Stream = (ULONG)OpenClipboard(Unit))
		{
			InitIFFasClip(Handle);

			if(!OpenIFF(Handle,IFFF_READ))
			{
				if(!StopChunk(Handle,ID_FTXT,ID_CHRS))
				{
					struct ContextNode *Node;

					while(!ParseIFF(Handle,IFFPARSE_SCAN))
					{
						Node = CurrentChunk(Handle);

						if(Node -> cn_Type == ID_FTXT)
							Bytes += Node -> cn_Size;
					}
				}

				CloseIFF(Handle);
			}

			if(Bytes)
			{
				if(!OpenIFF(Handle,IFFF_READ))
				{
					if(!StopChunk(Handle,ID_FTXT,ID_CHRS))
					{
						if(Store = AllocVecPooled(Bytes,MEMF_ANY))
						{
							STRPTR			 Index		= Store;
							LONG			 BytesRead	= 0;
							struct ContextNode	*Node;

							while(!ParseIFF(Handle,IFFPARSE_SCAN) && BytesRead < Bytes)
							{
								Node = CurrentChunk(Handle);

								if(Node -> cn_Type == ID_FTXT)
								{
									LONG Count = Node -> cn_Size;

									if(BytesRead + Count > Bytes)
										Count = Bytes - BytesRead;

									if(Count > 0)
									{
										if((Count = ReadChunkBytes(Handle,Index,Count)) > 0)
										{
											Index		+= Count;
											BytesRead	+= Count;
										}
									}
								}
							}

							Bytes = BytesRead;
						}
					}

					CloseIFF(Handle);
				}
			}

			CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream);
		}

		FreeIFF(Handle);
	}

	if(Store && !Bytes)
	{
		FreeVecPooled(Store);

		Store = NULL;
	}

	*Buffer	= Store;
	*Size	= Bytes;

	return((BOOL)(Store != NULL));
}

	/* AddClip(STRPTR Buffer,LONG Size):
	 *
	 *	Merge previous clipboard contents with new text,
	 *	then store the new string in the clipboard.
	 */

BOOL
AddClip(STRPTR Buffer,LONG Size)
{
	LONG	Bytes;
	APTR	Store;

	if(GetClipContents(Config -> ClipConfig -> ClipboardUnit,&Store,&Bytes))
	{
		struct IFFHandle	*Handle;
		BOOL			 Success = FALSE;

		if(Handle = AllocIFF())
		{
			if(Handle -> iff_Stream = (ULONG)OpenClipboard(Config -> ClipConfig -> ClipboardUnit))
			{
				InitIFFasClip(Handle);

				if(!OpenIFF(Handle,IFFF_WRITE))
				{
					if(!PushChunk(Handle,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN))
					{
						if(!PushChunk(Handle,0,ID_CHRS,IFFSIZE_UNKNOWN))
						{
							if(WriteChunkBytes(Handle,Store,Bytes) == Bytes)
							{
								if(WriteChunkBytes(Handle,Buffer,Size) == Size)
								{
									if(!PopChunk(Handle))
										Success = TRUE;
								}
							}
						}
					}

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

					CloseIFF(Handle);
				}

				CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream);
			}

			FreeIFF(Handle);
		}

		FreeVecPooled(Store);

		return(Success);
	}
	else
		return(SaveClip(Buffer,Size));
}

	/* SaveClip(STRPTR Buffer,LONG Size):
	 *
	 *	Send a given text buffer to the clipboard.
	 */

BOOL
SaveClip(STRPTR Buffer,LONG Size)
{
	BOOL Success = FALSE;

	if(Size > 0)
	{
		struct IFFHandle *Handle;

		if(Handle = AllocIFF())
		{
			if(Handle -> iff_Stream = (ULONG)OpenClipboard(Config -> ClipConfig -> ClipboardUnit))
			{
				InitIFFasClip(Handle);

				if(!OpenIFF(Handle,IFFF_WRITE))
				{
					if(!PushChunk(Handle,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN))
					{
						if(!PushChunk(Handle,0,ID_CHRS,IFFSIZE_UNKNOWN))
						{
							if(WriteChunkBytes(Handle,Buffer,Size) == Size)
							{
								if(!PopChunk(Handle))
									Success = TRUE;
							}
						}
					}

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

					CloseIFF(Handle);
				}

				CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream);
			}

			FreeIFF(Handle);
		}
	}

	return(Success);
}

	/* LoadClip(STRPTR Buffer,LONG Size):
	 *
	 *	Put the contents of the clipboard into a given
	 *	buffer. Note that only the first FTXT chunk will
	 *	be read. Since this code will only be called by
	 *	the clipboard server process which serves the
	 *	string gadget editing hook, this will hopefully
	 *	not be fatal. If you want more data to be read,
	 *	including multiple FTXT chunks, use the OpenClip(),
	 *	GetClip(), CloseClip() combo above.
	 */

LONG
LoadClip(STRPTR Buffer,LONG Size)
{
	struct IFFHandle	*Handle;
	LONG			 Bytes = 0;

	if(Handle = AllocIFF())
	{
		if(Handle -> iff_Stream = (ULONG)OpenClipboard(Config -> ClipConfig -> ClipboardUnit))
		{
			InitIFFasClip(Handle);

			if(!OpenIFF(Handle,IFFF_READ))
			{
				if(!StopChunk(Handle,ID_FTXT,ID_CHRS))
				{
					if(!ParseIFF(Handle,IFFPARSE_SCAN))
					{
						struct ContextNode *ContextNode = CurrentChunk(Handle);

						if(ContextNode -> cn_Type == ID_FTXT)
						{
							if(Size > ContextNode -> cn_Size)
								Size = ContextNode -> cn_Size;

							if(ReadChunkRecords(Handle,Buffer,Size,1))
								Bytes = Size;
						}
					}
				}

				CloseIFF(Handle);
			}

			CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream);
		}

		FreeIFF(Handle);
	}

	return(Bytes);
}
