/*
**	Clip.c
**
**	Clipboard support routines
**
**	Copyright © 1990-1997 by Olaf `Olsen' Barthel
**		All Rights Reserved
**
**	:ts=4
*/

#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()
{
	CloseIFFClip(ClipHandle);
	ClipHandle = NULL;

	FreeVecPooled(ClipBuffer);
	ClipBuffer = NULL;
}

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

LONG
GetClip(STRPTR Buffer,LONG Len)
{
	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(!ReadIFFBytes(ClipHandle,ClipBuffer,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(!ReadIFFBytes(ClipHandle,ClipBuffer,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 = OpenIFFClip(Unit,MODE_OLDFILE))
		{
			if(!(Error = 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(0);
					}
					else
						Error = ERROR_OBJECT_WRONG_TYPE;
				}
				else
					Error = ERROR_OBJECT_NOT_FOUND;
			}
		}
		else
			Error = IoErr();
	}
	else
		Error = ERROR_NO_FREE_STORE;

	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;
	APTR Store;

	Store = NULL;
	Bytes = 0;

	if(Handle = OpenIFFClip(Unit,MODE_OLDFILE))
	{
		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;
			}
		}

		CloseIFFClip(Handle);
	}

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

					Index		= Store;
					BytesRead	= 0;

					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(ReadIFFBytes(Handle,Index,Count))
								{
									Index		+= Count;
									BytesRead	+= Count;
								}
							}
						}
					}

					Bytes = BytesRead;
				}
			}

			CloseIFFClip(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;
		LONG Error;

		if(Handle = OpenIFFClip(Config->ClipConfig->ClipboardUnit,MODE_NEWFILE))
		{
			if(!(Error = PushChunk(Handle,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN)))
			{
				if(!(Error = PushChunk(Handle,0,ID_CHRS,Bytes + Size)))
				{
					if(WriteIFFBytes(Handle,Store,Bytes))
					{
						if(!WriteIFFBytes(Handle,Buffer,Size))
							Error = IoErr();
					}
					else
						Error = IoErr();

					if(!Error)
						Error = PopChunk(Handle);
				}

				if(!Error)
					Error = PopChunk(Handle);
			}

			CloseIFFClip(Handle);
		}
		else
			Error = IoErr();

		FreeVecPooled(Store);

		if(Error)
		{
			SetIoErr(Error);

			return(FALSE);
		}
		else
			return(TRUE);
	}
	else
		return(SaveClip(Buffer,Size));
}

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

BOOL
SaveClip(STRPTR Buffer,LONG Size)
{
	LONG Error;

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

		if(Handle = OpenIFFClip(Config->ClipConfig->ClipboardUnit,MODE_NEWFILE))
		{
			if(!(Error = PushChunk(Handle,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN)))
			{
				Error = AddIFFChunkBytes(Handle,ID_CHRS,Buffer,Size);
			}

			if(!Error)
				Error = PopChunk(Handle);

			CloseIFFClip(Handle);
		}
		else
			Error = IoErr();
	}
	else
		Error = 0;

	if(Error)
	{
		SetIoErr(Error);

		return(FALSE);
	}
	else
		return(TRUE);
}

	/* 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;

	Bytes = 0;

	if(Handle = OpenIFFClip(Config->ClipConfig->ClipboardUnit,MODE_OLDFILE))
	{
		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(ReadIFFBytes(Handle,Buffer,Size))
						Bytes = Size;
				}
			}
		}

		CloseIFFClip(Handle);
	}

	return(Bytes);
}

BOOL
WriteTranslatedToClip(struct IFFHandle *Handle,STRPTR Buffer,LONG Length)
{
	UBYTE LocalBuffer[256];
	LONG DestLen,i;
	LONG c;

	for(i = DestLen = 0 ; i < Length ; i++)
	{
		if(!(c = ISOConversion[Buffer[i]]))
			c = ' ';

		LocalBuffer[DestLen++] = c;

		if(DestLen == sizeof(LocalBuffer))
		{
			if(!WriteIFFBytes(Handle,LocalBuffer,DestLen))
				return(FALSE);

			DestLen = 0;
		}
	}

	if(DestLen > 0)
	{
		if(!WriteIFFBytes(Handle,LocalBuffer,DestLen))
			return(FALSE);
	}

	return(TRUE);
}
