/******************************************************************
** acl.c: Contient la gestion des requètes ASL, du clipboard, et **
**        support à la locale.library. Écrit par T.Pierron.      **
**        10-Déc-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>

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

UBYTE *NoASL=MSG_NOASL_STR;

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

	if(!FR)
		if( !(FR = (void *) AllocAslRequest(ASL_FontRequest,NULL)) ) {
			puts(NoASL);
			return NULL;
		}

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

struct IntuiText MsgTxt={ 0,0,JAM1,0,0,NULL,NULL,0};
struct IntuiText Ack={ 0,0,JAM1,0,0,NULL,MSG_BUTTON1_STR,0};
struct IntuiText Nac={ 0,0,JAM1,0,0,NULL,MSG_BUTTON2_STR,0};

BYTE avert(UBYTE *msg)
{
	MsgTxt.IText=msg;
	return AutoRequest( window,&MsgTxt,AslBase?&Ack:NULL,&Nac,NULL,NULL,320,72 );
}

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

	for(nb=Offset; ; p++)
	{
		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 (max-len>>1);
	/* if neg, align pos to max: */
	if(pos<0) pos+=max;
	if(pos<0) return 0;
	if(pos+len>max) return max-len;
	return pos;
}

/****************************************************************
** Procédures d'entrées-sorties avec le Clipboard.device. Tiré **
** d'un exemple des RKM, modifié et optimisé par l'auteur.     **
****************************************************************/


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

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

	DeleteExtIO((struct IOStdReq *)ior);
	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);
}

#define WriteBuf(Buf,Val,Type)	*((Type *)Buf)++=Val
UBYTE Buffer[71];

/* Write a string of text to the clipboard.device (max 50 chars!): */
int CBWriteFTXT(struct IOClipReq *ior,UBYTE *string)
{
	UBYTE *p;
	ULONG slen;
	int success;

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

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

	/* Create the IFF header information */
	WriteBuf(p,ID_FORM,ULONG);			/* "FORM"             */
	WriteBuf(p,slen+12,ULONG);			/* + "[size]FTXTCHRS" */
	WriteBuf(p,ID_FTXT,ULONG);			/* "FTXT"             */
	WriteBuf(p,ID_CHRS,ULONG);			/* "CHRS"             */
	WriteBuf(p,slen,ULONG);				/* string length      */
	CopyMem(string,p,slen);

	/* Write buffer to clipboard: */
	ior->io_Data    = (STRPTR)Buffer;
	ior->io_Length  = p-Buffer+slen;
	ior->io_Command = CMD_WRITE;
	DoIO( (struct IORequest *) ior);

	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(Buffer,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);
			Buffer[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 (50 lines !)									**
****************************************************************/


/* All strings affected: */
extern UBYTE *GadTxt[],*Errors[],*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,5,sizeof(UBYTE *),MSG_STRGAD,
	Errors,6,sizeof(UBYTE *),MSG_BADOS,
	popmsg,4,sizeof(UBYTE *),MSG_CODE,
	&newmenu->nm_Label,22,sizeof(struct NewMenu),MSG_MENUTITLE,
	&Request.es_Title,3,sizeof(UBYTE *),MSG_ABOUT,
	&newbroker.nb_Name,3,sizeof(UBYTE *),MSG_COMMONAME,
	(UBYTE **)&FileTags[7],1,0,MSG_ASLTITLE,
	&NoASL,1,0,MSG_NOASL,
	&Ack.IText,1,0,MSG_BUTTON1,
	&Nac.IText,1,0,MSG_BUTTON2,
};

void *catalog=NULL;

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