/***************************************************************
** acl.c: Contain managment of ASL requesters, clipboard and  **
**        locale.library support. Written by T.Pierron.       **
**        10-Dec-1999                                         **
***************************************************************/


#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <libraries/commodities.h>
#include <libraries/gadtools.h>
#include <libraries/asl.h>
#include <dos/dosasl.h>
#include <exec/io.h>
#include <devices/clipboard.h>
#include <libraries/locale.h>
#include <string.h>

#include "cmap.h"
#define	CATCOMP_STRINGS
#define  CATCOMP_NUMBERS
#include "cmap_strings.h"


extern struct IntuitionBase *IntuitionBase;
extern struct AslBase *AslBase;
extern struct Window *window;
struct FontRequester	*FR=NULL;

/* ASL Font requester tags: */
ULONG FileTags[] = {
	ASLFO_Window,NULL,
	ASLFO_Screen,NULL,
	ASLFO_SleepWindow,TRUE,
	ASLFO_TitleText,(ULONG) MSG_ASLTITLE_STR,
	ASLFO_MaxHeight,255,
	TAG_DONE
};

/*** Try to open a ASL font requester: ***/
struct TTextAttr *open_asl( void )
{
	FileTags[1] = (ULONG) window;
	FileTags[3] = (ULONG) IntuitionBase->ActiveScreen;

	if(!FR)
		if( !(FR = (void *) AllocAslRequest(ASL_FontRequest,NULL)) ) {
			puts(Errors[6]);
			return NULL;
		}

	if( AslRequest((APTR) FR,FileTags) )
		return &FR->fo_TAttr;
	else
		/* User hit cancel or close gadget! */
		return NULL;
}

struct EasyStruct FontReq = {
	sizeof(struct EasyStruct),0,
	NULL,	NULL,	NULL
};
extern struct EasyStruct Request;

BYTE avert( STRPTR msg )
{
	if( FontReq.es_Title == NULL )
	{
		FontReq.es_Title = Request.es_Title;
		FontReq.es_TextFormat = msg;
		if( AslBase == NULL )
			FontReq.es_GadgetFormat = strchr( FontReq.es_GadgetFormat, '|' ) + 1;
	}
	/* Something goes wrong: the font seems too big, so inquiring for a more **
	** convenient font... only if ASL library is present, otherwise quit.    */
	return (BYTE) EasyRequestArgs( window, &FontReq, NULL, NULL );
}

/*** Convert a geometry string, describing windows positions: ***/
void Parse_geometry(UBYTE *p)
{
	extern WORD Offset[];
	BYTE sign=FALSE;
	WORD *nb;

	for(nb=Offset; ; p++)
	{
		/* Sorry for this crap routine... */
		if(*p>='0' && *p<='9')
			for(*nb=0; *p>='0' && *p<='9'; *nb*=10, *nb += *p++ - '0');

		switch(*p)
		{
			case '-': sign=TRUE; break;
			case '+': break;
			case 0:
			case ',': if(sign) *nb = - *nb; nb++; sign=FALSE;
			          if(*p && nb-Offset<4) break;
			default:  return;
		}
	}
}

/*** Adjust position to what user wants: ***/
WORD Adjust_pos(WORD pos, WORD max, WORD len)
{
	/* if 0x7FFF center between 0 and max: */
	if(pos==0x7FFF) return (WORD)(max-len>>1);
	/* if neg, align pos to max: */
	if(pos<0) pos+=max-len+1;
	if(pos<0) return 0;
	if(pos+len>max) return (WORD)(max-len);
	return pos;
}

/****************************************************************
** I/O procedures handling Clipboard.device. Taken from an ex- **
** ample of RKM, modify and optimize by the Author.            **
****************************************************************/


#define MAKE_ID(a,b,c,d) ((a<<24L) | (b<<16L) | (c<<8L) | d)

#define ID_FORM MAKE_ID('F','O','R','M')
#define ID_FTXT MAKE_ID('F','T','X','T')
#define ID_CHRS MAKE_ID('C','H','R','S')

/* prototypes */
struct IOClipReq	*CBOpen			( ULONG );
void					CBClose			(struct IOClipReq *);
int					CBWriteFTXT		(struct IOClipReq *, UBYTE *);
int					CBQueryFTXT		(struct IOClipReq *);
void					CBReadCHRS		(struct IOClipReq *, UBYTE *,WORD Max);
void					CBReadDone		(struct IOClipReq *);


/*** Try to open the clipboard: ***/
struct IOClipReq *CBOpen(ULONG unit)
{
	struct MsgPort *mp;
	struct IOStdReq *ior = NULL;

	if( (mp = (void *) CreatePort(0L,0L)) &&
	    (ior=(struct IOStdReq *)CreateExtIO(mp,sizeof(struct IOClipReq))) &&
	    (!OpenDevice("clipboard.device",unit,ior,0L)) )
		return (struct IOClipReq *)ior;

	if(ior) DeleteExtIO(ior);
	if(mp)  DeletePort(mp);
	return NULL;
}

/*** Try to close it: ***/
void CBClose(struct IOClipReq *ior)
{
	struct MsgPort *mp = ior->io_Message.mn_ReplyPort;

	CloseDevice((struct IOStdReq *)ior);
	DeleteExtIO((struct IOStdReq *)ior);
	DeletePort(mp);
}

/** Nasty, but required for strict-ANSI compiler **/
typedef union
{
	char  *ptr8;
	short *ptr16;
	long  *ptr32;
}	PTR;
UBYTE Buffer[20];

/*** Write a string of text to the clipboard.device: ***/
int CBWriteFTXT(struct IOClipReq *ior,UBYTE *string)
{
	PTR   p;
	ULONG slen;
	char  odd;

	if((slen = strlen(string))==0)	return FALSE;
	odd = slen&1;							/* pad byte */

	/* initial set-up for Offset, Error, and ClipID */
	ior->io_Offset = 0;
	ior->io_Error  = 0;
	ior->io_ClipID = 0;
	p.ptr8 = Buffer;

	/* Create the IFF header information */
	*(p.ptr32)++ = ID_FORM;				/* "FORM"             */
	*(p.ptr32)++ = slen+12+odd;		/* + "[size]FTXTCHRS" */
	*(p.ptr32)++ = ID_FTXT;				/* "FTXT"             */
	*(p.ptr32)++ = ID_CHRS;				/* "CHRS"             */
	*(p.ptr32)++ = slen;					/* string length      */

	/* Write header to clipboard: */
	ior->io_Data    = (STRPTR)Buffer;
	ior->io_Length  = (UBYTE *)p.ptr8-Buffer;
	ior->io_Command = CMD_WRITE;
	DoIO( (struct IORequest *) ior);

	/* Write the content of string: */
	ior->io_Data    = (STRPTR)string;
	ior->io_Length  = slen+odd;
	DoIO( (struct IORequest *) ior);

	/* Tell the clipboard that we are done writing: */
	ior->io_Command=CMD_UPDATE;
	DoIO( (struct IORequest *) ior);

	/* Check if io_Error was set by any of the preceding IO requests */
	return ior->io_Error ? FALSE : TRUE;
}

#define Tab(Buf,Type,n)		((Type *)Buf)[n]

/*** Check if there is TXT in the clipboard: ***/
int CBQueryFTXT(struct IOClipReq *ior)
{
	/* initial set-up for Offset, Error, and ClipID */
	ior->io_Offset = 0;
	ior->io_Error  = 0;
	ior->io_ClipID = 0;

	/* Look for "FORM[size]FTXT" */
	ior->io_Command = CMD_READ;
	ior->io_Data    = (STRPTR)Buffer;
	ior->io_Length  = 12;
	DoIO( (struct IORequest *) ior);

	if( (ior->io_Actual == 12L) &&					/* Do we have at least 12 bytes ? */
	    (Tab(Buffer,ULONG,0) == ID_FORM) &&		/* Does it starts with "FORM" ? */
	    (Tab(Buffer,ULONG,2) == ID_FTXT) )			/* Is it "FTXT" ? */
		return TRUE;

	/* It's not "FORM[size]FTXT", so tell clipboard we are done */
	CBReadDone(ior);
	return FALSE;
}


/*** Reads the next CHRS chunk from clipboard ***/
void CBReadCHRS(struct IOClipReq *ior,UBYTE *buf, WORD Max)
{
	ULONG size;

	/* Find next CHRS chunk */
	ior->io_Command = CMD_READ;
	ior->io_Data    = (STRPTR)buf;
	ior->io_Length  = 8L;
	for(;;)
	{
		/* Read the chunk ID and its length: */
		DoIO( (struct IORequest *) ior);

		/* Have get enough data ? */
		if (ior->io_Actual != 8) break;

		/* Get buffer size, and pad it if odd: */
		size = Tab(buf,ULONG,1);
		if(size & 1) size++;

		/* Is it a CHRS chunk ? */
		if(Tab(buf,ULONG,0) == ID_CHRS)
		{
			if(size >= Max) size=Max-1;
			ior->io_Length  = size;

			DoIO( (struct IOStdReq *) ior);
			buf[size] = 0;
			break;
		}
		/* If not, skip to next chunk */
		else
			ior->io_Offset += size;
	}
	CBReadDone(ior);
}

/*** Tell clipboard we are done reading ***/
void CBReadDone(struct IOClipReq *ior)
{
	ior->io_Command = CMD_READ;
	ior->io_Data    = (STRPTR)Buffer;
	ior->io_Length  = sizeof(Buffer)-2;

	/* falls through immediately if io_Actual == 0 */
	while (ior->io_Actual)
		if (DoIO( (struct IORequest *) ior)) break;
}

/**********************************************
**				Locale.library support 				**
**********************************************/


/* All strings affected: */
extern UBYTE *GadTxt[],*popmsg[];
extern struct NewMenu newmenu[];
extern struct EasyStruct Request;
extern struct NewBroker newbroker;

struct Vars {
	UBYTE **msg;			/* Message to change */
	UBYTE nb;				/* Nb contiguous msg to change */
	WORD  size;				/* Size of contiguous memory */
	WORD	NumStr;			/* Id string from catalog */
} TabVars[]={
	{ GadTxt+3,            4,  sizeof(STRPTR),         MSG_COPY      },
	{ Errors,              9,  sizeof(STRPTR),         MSG_BADOS     },
	{ popmsg,              4,  sizeof(STRPTR),         MSG_CODE      },
	{ &newmenu[0].nm_Label,  17, sizeof(struct NewMenu), MSG_MENUTITLE },
	{ &Request.es_Title,   3,  sizeof(STRPTR),         MSG_ABOUT     },
	{ &newbroker.nb_Title, 2,  sizeof(STRPTR),         MSG_DESCLINE1 },
};

void *catalog=NULL;

/*** Translate all messages of the application: ***/
void Translate_srings( void )
{
	if(catalog=(void *)OpenCatalogA(NULL,"CharMap.catalog",NULL))
	{
		union { UBYTE **pptr; UBYTE *ptr; } mes;
		struct Vars *p;
		WORD n;
		/* All necessary information is contained in our table: */
		for(p=TabVars; p<TabVars+sizeof(TabVars)/sizeof(struct Vars); p++)
			for(n=0,mes.pptr=p->msg; n<p->nb; mes.ptr += p->size )
				if(*mes.pptr!=NM_BARLABEL && *mes.pptr!=0)		/* Newmenus barlabel string */
					*mes.pptr = (UBYTE *) GetCatalogStr(catalog,p->NumStr++,*mes.pptr), n++;

		FileTags[7] = (ULONG) GetCatalogStr(catalog, MSG_ASLTITLE, FileTags[7]);
		FontReq.es_GadgetFormat = (STRPTR) GetCatalogStr(catalog, MSG_CHOOSEQUIT, 
				FontReq.es_GadgetFormat);
	}
}

