/****************************************************************
**
**
**
**      Copyright (C) 1993 Jérôme Santini
**
**
**
*****************************************************************/

/****** Includes ************************************************/

#include "uiki:uikbase.h"
#include "uiki:uikglobal.h"
#include "uiki:uikobj.h"
#include "uiki:uikmacros.h"
#include "uiki:uik_protos.h"
#include "uiki:uik_pragmas.h"

#include "uiki:objstring.h"
#include "uiki:objrtfilereq.h"

#include <proto/exec.h>
#include <proto/reqtools.h>
#include <proto/dos.h>
#include <exec/libraries.h>
#include <dos/dostags.h>
#include <string.h>
#include <stdlib.h>
#include <clib/alib_stdio_protos.h>

#define OK_SIGNAL   SIGBREAKF_CTRL_D
#define FAIL_SIGNAL SIGBREAKF_CTRL_E
#define BREAK_C		SIGBREAKF_CTRL_C

#pragma tagcall ReqToolsBase rtReqHandlerTags 6C 80903

struct TagItem  stoptag[] =
{
	RTRH_EndRequest, REQ_CANCEL,
	TAG_DONE, NULL,
};

struct ExecBase *SysBase;
struct UIKBase *UIKBase;
struct ReqToolsBase *ReqToolsBase;
struct DosLibrary *DOSBase;

/*#define OUTPUT*/

#ifdef OUTPUT

void
print(char *c, long data)
{
	BPTR            handle;

	if (handle = Open("prt:", MODE_OLDFILE))
	{
		FPrintf(handle, "%s%08lx\n", c, data);
		Close(handle);
	}
}

#define PRINTF  Printf
#define PRINTF2  Printf
#define PUTS    PutStr

#else
#   define print(a,b)
#	define PRINTF(a,b)
#	define PRINTF2(a,b,c)
#	define PUTS(a)
#endif


/****** Prototypes **********************************************/

static int      GetFileName(struct UIKObjRTFileReq *obj, char *buffer);
static void     StringToReq(struct UIKObjRTFileReq *req, struct UIKObjStrGad *os);
static void     ReqToString(struct UIKObjRTFileReq *req, struct UIKObjStrGad *os);

/****************************************************************
 *
 *      Code
 *
 ****************************************************************/

/*------------------------------------------------------------------*/
/*--------------- Vecteurs divers ----------------------------------*/
/*------------------------------------------------------------------*/

/*
**	vecteur pour le parenrt si c'est un Toggle
*/
static void
ToggleVector(struct UIKObj *obj, struct UIKObj *req)
{
	if (req->Status == UIKS_STOPPED)
		UIK_Start(req);
	else
		UIK_Stop(req);
}

/*
** Vecteur qd OK ou CANCEL sur la requête
*/
static void
vecteur(struct UIKObjRTFileReq *obj)
{
	char            buffer[256];

	obj->vect = vecteur;

	if (obj->rc)				  /* OK ou return */
	{
		if (obj->OKFunc)
		{
			GetFileName(obj, buffer);
			(*obj->OKFunc) (obj, buffer);
		}
		if (obj->sg)
			ReqToString(obj, obj->sg);

	} else
	{							  /* CANCEL ou Close Gadget */
		if (obj->CancelFunc)
			(*obj->CancelFunc) (NULL, obj);
	}

	UIK_Stop(obj);
	PRINTF("vecteur %08lx (out)\n", obj->rc);
}

/*
**  Vecteur pour l'objet RTFR->sg String Gadget
*/
static void
StringKeys(struct UIKObjStrGad *objstr, struct UIKObjRTFR *req)
{
	struct IntuiMessage *imsg = objstr->UIK->IntuiMsg;

	if (imsg->Code & 0x80)
	{
		return;
	}							  /* touche relâchée */
	switch (imsg->Code)			  /* on peut avoir le code de la touche */
	{
		case 0x43:				  /* touche ENTER */
		case 0x44:				  /* touche RETURN */
		case 0x45:				  /* touche ESC */
		case 0x4c:				  /* flêche HAUT */
		case 0x4d:				  /* flêche BAS */
			StringToReq(req, objstr);
			break;
	}
}

/*------------------------------------------------------------------*/
/*--------------- Processus associé à la requête -------------------*/
/*------------------------------------------------------------------*/

long            __regargs
RemoveSegment(struct UIKObjRTFileReq *obj)
{
	long            retour = NULL;

	if (obj->son)
	{
		PRINTF("Son at %08lx\n", obj->son);
		Signal(obj->son, OK_SIGNAL);
		PUTS("Stop Wait\n");
		retour = Wait(OK_SIGNAL | FAIL_SIGNAL);
		PUTS("Stop Received\n");
		obj->son = NULL;
	}
	return (retour);
}

void            __asm
segment(register __d0 int l, register __a0 char *string)
{
	struct UIKObjRTFileReq *obj;
	struct TagItem *tag = NULL;
	long            signal = NULL;

	StrToLong(string, (ULONG *) & obj);

	obj->rthi = NULL;

	PRINTF(">>>>>>>>>>>>>>>>> Son at %08lx\n", obj->son);
    PUTS(">>>>>>>>>>>>>>>>> Objet ok (1)\n");

	obj->rc = (long)rtFileRequestA(obj->rtfr, obj->filename, obj->titre, obj->reqtag);

    obj->rc = CALL_HANDLER ;

    PRINTF2(">>>>>>>>>>>>>>>>> %08lx && %08lx\n",obj->rc,obj->rthi);

	if (obj->rc == CALL_HANDLER && obj->rthi)
	{
		Signal(obj->UIKTask, OK_SIGNAL);

		while (obj->rc == CALL_HANDLER)
		{

			if (obj->rthi->DoNotWait == FALSE)
			{
                PUTS(">>>>>>>>>>>>>>>>> Objet Wait\n");
				signal = Wait(OK_SIGNAL | obj->rthi->WaitMask);
                PUTS(">>>>>>>>>>>>>>>>> Objet Received\n");
            }

			if (signal & OK_SIGNAL)
				tag = stoptag;

            PUTS(">>>>>>>>>>>>>>>>> Objet ReqHandler\n");
			obj->rc = rtReqHandlerA(obj->rthi, signal, tag);
            PUTS(">>>>>>>>>>>>>>>>> Objet ReqHandler Done\n");

		}

		SetTaskPri(FindTask(0), 127);

		if (tag == NULL)		  /* stop provoqué par reqtools , et non par UIK */
		{
			/* UIK n'a pas besoin de nous arreter : on le fait de nous même */
			obj->son = NULL;

			/* envoyer message à UIK pour arreter l'objet */
			Signal(obj->UIKTask, 1L << obj->SigBit);
		} else
			/* Fin du processus provoquée par UIK ... prevenir qu'on est d'accord */
			Signal(obj->UIKTask, OK_SIGNAL);
	} else
	{
		SetTaskPri(FindTask(0), 127);
		Signal(obj->UIKTask, FAIL_SIGNAL);
	}

    PUTS(">>>>>>>>>>>>>>>>> Objet Fin \n");

}

/*------------------------------------------------------------------*/
/*--------------- Fonctions de l'objet --------- -------------------*/
/*------------------------------------------------------------------*/

static struct TagItem *__regargs
InsertTag(Tag tag, ULONG data, struct TagItem *list)
{
	struct TagItem *newtag,
	               *next,
	               *ptr;

	if (ptr = newtag = AllocateTagItems(2))
	{
		newtag->ti_Tag = tag;
		newtag->ti_Data = data;
		next = NextTagItem(&ptr);

		/* soit ajouter l'autre liste, soit conclure */
		if (list)
		{
			next->ti_Tag = TAG_MORE;
			next->ti_Data = (ULONG) list;
		} else
		{
			next->ti_Tag = TAG_DONE;
			next->ti_Data = NULL;
		}
		list = newtag;
	}
	return (list);
}

static int
StartRTFileReq(struct UIKObjRTFileReq *obj)
{
	long            signal,
	                retour = FALSE;
	char            arg[50];

	/* quel titre ? */
	if (obj->Obj.TitleFlags & TITLE_ADDR)
	{
		obj->titre = (char *)obj->Obj.Title;
	} else
	{
		if ((obj->Obj.TitleFlags & TITLE_IMAGE) == NULL)
			obj->titre = UIK_LangString(obj->Obj.UIK, obj->Obj.Title);
	}

	/*
	 ** lancer le processus de la requête
	 */
	sprintf(arg, "%ld", obj);	  /* ligne de commande */

	obj->son = CreateNewProcTags(NP_Entry, (ULONG) segment,
#ifdef OUTPUT
	                             NP_Output,Output(),
	                             NP_CloseOutput,FALSE,
#endif /* OUTPUT */
								 NP_Name, "rtFileReq_slave_process",
								 NP_WindowPtr, obj->Obj.w,
								 NP_Arguments, arg);

	PRINTF("Son at %08lx\n", obj->son);

	PUTS("Start Wait\n");
	signal = Wait(OK_SIGNAL | FAIL_SIGNAL);
	PUTS("Start Received\n");

	if (signal & OK_SIGNAL)
	{
		obj->vect = vecteur;
		if (obj->hook = UIK_AddVector(obj->Obj.UIK,
									  (int (*)())&obj->vect,
									  1L << obj->SigBit,
									  (ULONG) obj))
			retour = TRUE;
		else
			RemoveSegment(obj);

	}
	if (retour)
		if (obj->Obj.Parent->Id == UIKID_TOGLGAD)
			UIK_OTo_SelectToggle((struct UIKObjGad *)obj->Obj.Parent);

	return (retour);
}

static void
StopRTFileReq(struct UIKObjRTFileReq *obj)
{

	if (obj->Obj.Parent->Id == UIKID_TOGLGAD)
		UIK_OTo_UnselectToggle((struct UIKObjGad *)obj->Obj.Parent);

	PRINTF("obj at %08lx\n", obj);
	if (obj->hook)
	{
		UIK_RemoveVector(obj, obj->hook);
		obj->hook = NULL;
		obj->vect = NULL;
	}
	RemoveSegment(obj);
	PRINTF("stopvec %08lx (out)\n", obj->rc);
}

static void
RemoveRTFileReq(struct UIKObjRTFileReq *obj)
{
	PUTS("Remove In\n");
	if (obj->SigBit != -1)
	{
		FreeSignal(obj->SigBit);
		obj->SigBit = -1;
	}
	if (obj->sghook)
		UIK_RemoveVector((struct UIKObj *)obj->sg, obj->sghook);

	if (obj->tghook)
		UIK_RemoveVector(obj->Obj.Parent, obj->tghook);

	if (obj->hook)
		UIK_RemoveVector(obj, obj->hook);

	if (obj->rtfr)
		rtFreeRequest(obj->rtfr);

	if (obj->reqtag)
		FreeTagItems(obj->reqtag);

	if (obj->UIKBase)
		CloseLibrary(UIKBase);

	if (obj->DOSBase)
		CloseLibrary(DOSBase);

	if (obj->ReqToolsBase)
		CloseLibrary(ReqToolsBase);

	PUTS("Remove Out\n");
}

static int
AddRTFileReq(struct UIKObjRTFileReq *obj, struct TagItem *taglist)
{
	char           *initpath,
	               *pat;

	SysBase = (struct ExecBase *)*((long *)4);

	if (((struct Library *)SysBase)->lib_Version < 37)
		goto END_ERROR;

	if ((obj->SigBit = AllocSignal(-1)) == -1)
		goto END_ERROR;

	obj->DOSBase = DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 0);

	if (!(obj->UIKBase = (struct UIKBase *)OpenLibrary(UIKNAME, 0)))
		goto END_ERROR;
	if (!(obj->ReqToolsBase = (struct ReqToolsBase *)OpenLibrary(REQTOOLSNAME, 0)))
		goto END_ERROR;


#ifdef OUTPUT
    Flush(Output());
#endif

	UIKBase = obj->UIKBase;
	ReqToolsBase = obj->ReqToolsBase;

	if (obj->rtfr = rtAllocRequestA(RT_FILEREQ, NULL))
	{
		LONG            flags = FREQF_PATGAD,
		                data;

		/*
		 * gestion des tags
		 */

		obj->reqtag = InsertTag(RT_ReqHandler, (ULONG) & (obj->rthi), obj->reqtag);
		obj->reqtag = InsertTag(RTFI_AllowEmpty, TRUE, obj->reqtag);
		obj->reqtag = InsertTag(RTFI_Height, obj->Obj.Box.Height, obj->reqtag);
		obj->reqtag = InsertTag(RT_LeftOffset, obj->Obj.Box.Left, obj->reqtag);
		obj->reqtag = InsertTag(RT_TopOffset, obj->Obj.Box.Top, obj->reqtag);

        if((obj->Obj.ObjExt->TTA.tta_Flags & FPF_PROPORTIONAL) == FALSE )
    		obj->reqtag = InsertTag(RT_TextAttr,(ULONG)&(obj->Obj.ObjExt->TTA), obj->reqtag);

		data = GetTagData(UIKTAG_RTFR_ReqPos, REQPOS_TOPLEFTWIN, taglist);
		obj->reqtag = InsertTag(RT_ReqPos, data, obj->reqtag);

		if (pat = (char *)GetTagData(UIKTAG_RTFR_PATTERN, 0, taglist))
			strcpy(obj->rtfr->MatchPat, pat);

		if (initpath = (char *)GetTagData(UIKTAG_RTFR_INITPATH, 0, taglist))
			strcpy(obj->rtfr->Dir, initpath);

		if (initpath = (char *)GetTagData(UIKTAG_RTFR_FILE, 0, taglist))
			strcpy(obj->filename, initpath);

		if (obj->DirOnly = GetTagData(UIKTAG_RTFR_DirsOnly, 0, taglist))
			flags |= FREQF_NOFILES;

		obj->reqtag = InsertTag(RTFI_Flags, (ULONG) flags, obj->reqtag);

		/* tags pour l'objets */
		obj->OKFunc = (void (*)())GetTagData(UIKTAG_RTFR_OKFUNC, 0, taglist);
		obj->CancelFunc = (void (*)())GetTagData(UIKTAG_RTFR_CANCELFUNC, 0, taglist);
		obj->User1 = GetTagData(UIKTAG_RTFR_User1, 0, taglist);
		obj->User2 = GetTagData(UIKTAG_RTFR_User2, 0, taglist);
		obj->sg = (struct UIKObjStrGad *)GetTagData(UIKTAG_RTFR_StrGad, 0, taglist);

	}
	obj->UIKTask = FindTask(0);

	if (obj->sg)
	{
		ReqToString(obj, obj->sg);
		obj->sghook = UIK_AddVector((struct UIKObj *)obj->sg, (void *)StringKeys, RAWKEY, (ULONG) obj);
	}
	if (obj->Obj.Parent->Id == UIKID_TOGLGAD)
		obj->tghook = UIK_AddVector(obj->Obj.Parent, (void *)ToggleVector, GADGETUP, (ULONG) obj);

	return (1);
  END_ERROR:

	RemoveRTFileReq(obj);

	return (0);
}

/*------------------------------------------------------------------*/
/*--------------- Fonctions publiques ------------------------------*/
/*------------------------------------------------------------------*/

static int 
GetFileName(struct UIKObjRTFileReq *obj, char *buffer)
{
	char           *ptr = buffer;

	if (obj->rtfr)
	{
		ptr = stpcpy(buffer, obj->rtfr->Dir);
		if (ptr > buffer)
		{
			ptr--;
			if (*ptr++ != ':')
				if (obj->DirOnly == FALSE)
					*ptr++ = '/';
		}
	}
	if (obj->DirOnly == FALSE)
		ptr = stpcpy(ptr, obj->filename);

	return (ptr - buffer);
}

static void 
SetFileName(struct UIKObjRTFileReq *obj, char *name)
{

	char            buffer[256],
	                c;
	struct TagItem  tag[2];
	UBYTE           Status = obj->Status;
	long            l;

	UIK_Stop(obj);

	if (obj->DirOnly)
	{
		if (l = strlen(name))
		{
			c = name[l - 1];
			if (c != '/' && c != ':')
			{
				name[l] = '/';
				name[l + 1] = 0;
			}
		}
	}
	stcgfn(buffer, name);
	strcpy(obj->filename, buffer);

	stcgfp(buffer, name);

	/* Rétablir, au cas où ... */
	if (obj->DirOnly)
		name[l] = 0;

	tag[0].ti_Tag = RTFI_Dir;
	tag[0].ti_Data = (ULONG) buffer;
	tag[1].ti_Tag = TAG_DONE;

	rtChangeReqAttrA(obj->rtfr, tag);

	if (Status == UIKS_STARTED)
		UIK_Start(obj);

}

static void
ReqToString(struct UIKObjRTFileReq *req, struct UIKObjStrGad *os)
{
	char            buffer[256];
	long            l;

	if (os == NULL)
		os = req->sg;

	if (os)
	{
		l = GetFileName(req, buffer);

		if (l)
			UIK_OSt_Set(os, buffer, l);
	}
}

static void
StringToReq(struct UIKObjRTFileReq *req, struct UIKObjStrGad *os)
{
	char           *buffer;
	long            l;

	if (os == NULL)
		os = req->sg;

	if (os)
	{
		buffer = UIK_OSt_Get(os, &l);
		if (buffer)
		{
			buffer[l] = 0;
			SetFileName(req, buffer);
		}
	}
}

ULONG __far     fonctions[] =
{
	(ULONG) GetFileName,
	(ULONG) SetFileName,
	(ULONG) ReqToString,
	(ULONG) StringToReq,
};

/********************** Germe ************************/

static struct TagItem GermTagList[] =
{
	{UIKTAG_GEN_LastFuncId, UIKFUNC_RTFR_LastCmd},
	{TAG_END}
};

struct UIKObjGerm Germ =
{
	"UIKObj_rtFileReq",
	AddRTFileReq,				  /* int     (*AddVector)(); */
	StartRTFileReq,				  /* int     (*StartVector)(); */
	StopRTFileReq,				  /* void    (*StopVector)(); */
	RemoveRTFileReq,			  /* void    (*RemoveVector)(); */
	NULL,						  /* void    (*RefreshVector)(); */
	NULL,						  /* void    (*ResizeVector)(); */
	NULL,						  /* void    (*ExceptActVector)(); */
	NULL,						  /* void    (*ExceptInaVector)(); */
	NULL,						  /* void    (*ExceptMovVector)(); */
	NULL,						  /* void    (*ExceptKeyVector)(); */
	NULL,						  /* int     (*StartAfterVector)(); */
	NULL,						  /* int     (*SelectVector)(); */
	fonctions,					  /* ULONG   *ExtentedVectors; */
	GermTagList,				  /* struct TagItem *GermTagList; */
	20,							  /* UWORD   MinWidth; */
	20,							  /* UWORD   MinHeight; */
	OBJRTFileReq_BOX_STDWIDTH << 16 | OBJRTFileReq_BOX_STDHEIGHT,	/* ULONG
																	 * DefaultWidthHeight; */
	0,							  /* UWORD   ObjId; */
	sizeof(struct UIKObjRTFileReq),	/* UWORD   ObjSize; */
	BOX_SEMAPHORE,				  /* flags par defaut */
};
