/*
 *	Request.c - Copyright © 1991 by S.R. & P.C.
 *
 *	Created:	10 Mar 1991  17:09:34
 *	Modified:	20 Jul 1991  16:45:15
 *
 *	Make>> make
 */

#include "Global.h"
#include "proto/Request.h"
#include "proto/String.h"
#include "proto/File.h"

extern void setmem(void *mem, size_t size, long value);

extern struct ParMConfig ParMConfig;
extern struct Screen *Screen;
extern char *ReqTitle;


static struct IntuiText IText2 = {
	0,1,JAM1,
	2,1,
	NULL,
	(UBYTE *)"Leave",
	NULL
};

static struct MenuItem MenuItem2 = {
	NULL,
	0,9,
	94,9,
	ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP,
	0,
	(APTR)&IText2,
	NULL,
	'L',
	NULL,
	MENUNULL
};

static struct IntuiText IText1 = {
	0,1,JAM1,
	2,1,
	NULL,
	(UBYTE *)"Reset",
	NULL
};

static struct MenuItem MenuItem1 = {
	&MenuItem2,
	0,0,
	94,9,
	ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP,
	0,
	(APTR)&IText1,
	NULL,
	'R',
	NULL,
	MENUNULL
};

static struct Menu Menu1 = {
	NULL,
	0,0,
	0,0,
	MENUENABLED,
	NULL,
	&MenuItem1
};


static struct NewWindow NWS = {
	0,0,		/* window XY origin relative to TopLeft of screen */
	257,0,		/* window width and height */
	2,1,		/* detail and block pens */
	CLOSEWINDOW|GADGETUP|GADGETDOWN|MENUPICK|RAWKEY,		/* IDCMP flags */
	WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE+NOCAREREFRESH,	/* other window flags */
	NULL,		/* first gadget in gadget list */
	NULL,		/* custom CHECKMARK imagery */
	NULL,		/* window title */
	NULL,		/* custom screen pointer */
	NULL,		/* custom bitmap */
	5,5,		/* minimum width and height */
	-1,-1,		/* maximum width and height */
	CUSTOMSCREEN	/* destination screen type */
};


static char *Titles[] = {
	"Set Protect...",
	"Filters",
	"Select..."
};

static char *GadgetText1[] = {
	"Files: ",
	"Dirs: ",
	"Affect subdirs"
};

static short x1[] = { 8, 73, 135 };
static char *FileDirGadgetText[] = { "N", "Y", "?" };

static struct IntuiText FilesGadgetsIText = {
	3,0,JAM2,
	48,0,
	NULL,
	NULL,
	NULL
};

static struct IntuiText DirsGadgetsIText = {
	3,0,JAM2,
	40,0,
	NULL,
	NULL,
	NULL
};

static char *GadgetText2[] = {
	"  Ok  ",
	"Cancel",
	"Clear",
	"RWED"
};

static short x2[] = { 8, 199, 8, 57 };

static char *TextTab[] = {
	"Pattern:",
	"Min size:",
	"Max size:",
	"Since:",
	"Before:"
};

static char *ProtectGadgetText[] = { " ", "+", "-" };

static WORD ProtectGadgetsVectors[] = { 0, 0, 10, 0, 10, 11, 0, 11, 0, 0 };

static struct IntuiText ProtectGadgetsIText = {
	1,0,JAM2,
	2,2,
	NULL,
	NULL,
	NULL
};

static struct Border ProtectGadgetsBorder = {
	0,0,
	2,0,JAM2,
	5,
	ProtectGadgetsVectors,
	NULL
};


struct ReqGadgets {
	struct GadgetBlock Gadgets1[3];			/* Files, Dirs, and Affect subdirs gadgets */
	struct StringBlock StringGadgets[5];
	char Buffer[5][PATTERN_BUF_SIZE];
	char UndoBuffer[5][PATTERN_BUF_SIZE];
	struct GadgetBlock Gadgets2[4];			/* Ok, Cancel gadgets */
	struct Gadget Gadgets3[9];				/* protect gadgets */
	struct IntuiText Gadgets3IText[9];
};


/*  return pointer to the first non blank char in a string, or to the '\0' if
 *  the string is empty
 */

static char *FirstNonBlank(char *buf)
{
	while(*buf && *buf == ' ') buf++;
	return buf;
}


/* check if buffer is empty or not */

static BOOL IsEmpty(char *buf)
{
	return (*FirstNonBlank(buf)) ? FALSE : TRUE;
}


static BOOL String2Date(char *src, struct DateStamp *ds)
{
	struct DateTime *dt;
	BOOL Ok = TRUE;
	char *s1, *s2;
	char buf[PATTERN_BUF_SIZE];
	
	if (!(dt = AllocMem(sizeof(struct DateTime), MEMF_PUBLIC|MEMF_CLEAR)))
		return FALSE;
	strcpy(buf, src);
	s1 = s2 = FirstNonBlank(buf);
	if (*s1) {
		dt->dat_StrDate = s1;
		while(*s2 && *s2 != ' ') s2++;
		if (*s2) {
			*s2++ = '\0';
			s2 = FirstNonBlank(s2);
		}
		if (*s2) {
			dt->dat_StrTime = s2;
			if (StrtoStamp(dt))
				Ok = FALSE;
		}
		else if (StrtoStamp(dt)) {
			dt->dat_StrDate = NULL;
			dt->dat_StrTime = s1;
			if (StrtoStamp(dt))
				Ok = FALSE;
		}
		if (Ok)
			*ds = dt->dat_Stamp;
		else
			DisplayBeep(NULL);
	}
	FreeMem(dt, sizeof(struct DateTime));
	return Ok;
}


static void DoFileDirGadget(struct Window *IW, struct Gadget *G)
{
	G->GadgetID++;
	G->GadgetID %= 3;
	G->GadgetText->NextText->IText = (UBYTE *)FileDirGadgetText[G->GadgetID];
	RefreshGList(G, IW, NULL, 1);
}


static void MakeFileDirGadgets(struct ReqGadgets *Gads, struct Window *IW, short Flags)
{
	Gads->Gadgets1[0].Gadget.GadgetID = (Flags & (SI_ALL_FILES|SI_MATCH_FILES)) - 1;
	Gads->Gadgets1[0].Gadget.Flags = GADGHNONE;
	DoFileDirGadget(IW, &Gads->Gadgets1[0].Gadget);
	Gads->Gadgets1[1].Gadget.GadgetID = ((Flags & (SI_ALL_DIRS|SI_MATCH_DIRS)) >> 2) - 1;
	Gads->Gadgets1[1].Gadget.Flags = GADGHNONE;
	DoFileDirGadget(IW, &Gads->Gadgets1[1].Gadget);
}


static void DoProtectGadget(struct Window *IW, struct Gadget *G)
{
	G->GadgetID++;
	G->GadgetID %= 3;
	G->GadgetText->IText = (UBYTE *)ProtectGadgetText[G->GadgetID];
	RefreshGList(G, IW, NULL, 1);
}


static void RefreshProtect(struct ReqGadgets *Gads, struct Window *IW, short Flags, short State)
{
	struct Gadget *G;
	short i;

	for( i=0 ; i<9 ; i++ ) {
		G = &Gads->Gadgets3[i];
		if (Flags & 1<<i) {
			G->GadgetText->IText = (UBYTE *)ProtectGadgetText[State];
			G->GadgetID = State;			/* store state into GadgetID */
		}
	}
	RefreshGList(&Gads->Gadgets3[8], IW, NULL, 9);
}


static void MakeProtectGadgets(struct ReqGadgets *Gads, struct SelectInfo *SelectInfo, short StartY)
{
	struct Gadget *G;
	short i, x, y;

	for( i=0 ; i<4 ; i++ ) {
		y = (i<2) ? StartY + 15 : StartY;
		LinkGadget(&Gads->Gadgets2[i], GadgetText2[i], &NWS, x2[i], y);
		Gads->Gadgets2[i].Gadget.GadgetID = i+1;
		Gads->Gadgets2[i].Border.FrontPen = 2;
	}
	for( i=0, x=238 ; i<9 ; i++ ) {
		G = &Gads->Gadgets3[i];
		Gads->Gadgets3IText[i] = ProtectGadgetsIText;	/* Init IText structure */
		if (SelectInfo->si_PosProtect & 1<<i)
			G->GadgetID = 1;
		else if (SelectInfo->si_NegProtect & 1<<i)
			G->GadgetID = 2;
		else
			G->GadgetID = 0;
		G->NextGadget = NWS.FirstGadget;
		NWS.FirstGadget = G;
		G->LeftEdge = x;
		G->TopEdge = StartY-2;
		G->Width = 11;
		G->Height = 12;
		G->GadgetText = &Gads->Gadgets3IText[i];
		G->GadgetText->IText = (UBYTE *)ProtectGadgetText[G->GadgetID];
		G->Flags = GADGHNONE;
		G->Activation = GADGIMMEDIATE;
		G->GadgetType = BOOLGADGET;
		G->GadgetRender = (APTR)&ProtectGadgetsBorder;
		x -= 16;
	}
}


BOOL FiltersReq(struct SelectInfo *SelectInfo, short ReqType)
{
	struct ReqGadgets *Gads;
	struct Window *IW;
	struct IntuiMessage *IMsg;
	struct DateStamp *ds;
	struct Gadget *G;
	ULONG Class;
	USHORT Code, Qual;
	BOOL quit = FALSE;
	BOOL Ok;
	short NextString, y, i;
	char buf[PATTERN_BUF_SIZE];

	if (!(Gads = AllocMem(sizeof(struct ReqGadgets), MEMF_PUBLIC|MEMF_CLEAR)))
		return FALSE;
	NWS.FirstGadget = NULL;
	if (ReqType != PROTECT_REQ) {
		for( i=0 ; i<=ReqType ; i++ ) {
			LinkGadget(&Gads->Gadgets1[i], GadgetText1[i], &NWS, x1[i], 15);
			Gads->Gadgets1[i].Gadget.Activation = GADGIMMEDIATE;
			Gads->Gadgets1[i].Border.FrontPen = 2;
		}
		Gads->Gadgets1[0].Text.NextText = &FilesGadgetsIText;
		Gads->Gadgets1[1].Text.NextText = &DirsGadgetsIText;
		if (ReqType == SELECT_REQ) {
			if (SelectInfo->si_Flags & SI_AFFECT_SUBDIRS)
				Gads->Gadgets1[2].Gadget.Flags |= SELECTED;
			Gads->Gadgets1[2].Gadget.Activation = RELVERIFY|TOGGLESELECT;
		}
		for( i=0, y = 29 ; i<5 ; i++ ) {
			LinkStringGadget(&Gads->StringGadgets[i], Gads->Buffer[i], Gads->UndoBuffer[i], &NWS, 152, PATTERN_BUF_SIZE, 95, y);
			if (i==1 || i==2)
				Gads->StringGadgets[i].Gadget.Activation |= LONGINT;
			Gads->StringGadgets[i].Gadget.GadgetID = 10+i;
			Gads->StringGadgets[i].Border.FrontPen = 2;
			Gads->StringGadgets[i].Pairs[5] = 11;
			Gads->StringGadgets[i].Pairs[7] = 11;
			y += 14;
		}
		MakeProtectGadgets(Gads, SelectInfo, 110);
		NWS.Height = 137;
		strcpy(Gads->Buffer[0], SelectInfo->si_Pattern);
		if (SelectInfo->si_MinSize) {
			SPrintf(Gads->Buffer[1], "%ld", SelectInfo->si_MinSize);
			((struct StringInfo *)Gads->StringGadgets[1].Gadget.SpecialInfo)->LongInt = SelectInfo->si_MinSize;
		}
		if (SelectInfo->si_MaxSize) {
			SPrintf(Gads->Buffer[2], "%ld", SelectInfo->si_MaxSize);
			((struct StringInfo *)Gads->StringGadgets[2].Gadget.SpecialInfo)->LongInt = SelectInfo->si_MaxSize;
		}
		if (SelectInfo->si_Flags & SI_SINCEDATE)
			Date2String(&SelectInfo->si_SinceDate, Gads->Buffer[3]);
		if (SelectInfo->si_Flags & SI_BEFOREDATE)
			Date2String(&SelectInfo->si_BeforeDate, Gads->Buffer[4]);
		for( i=0 ; i<5 ; i++ )
			strcpy(Gads->UndoBuffer[i], Gads->Buffer[i]);
	}
	else {
		MakeProtectGadgets(Gads, SelectInfo, 25);
		NWS.Height = 52;
	}
	switch(ReqType) {
	case PROTECT_REQ:
		Menu1.MenuName = "Protect";
		break;
	case FILTERS_REQ:
		Menu1.MenuName = "Filters";
		break;
	case SELECT_REQ:
		Menu1.MenuName = "Select";
		break;
	}
	Menu1.Width = (strlen(Menu1.MenuName) << 3) + 12;
	NWS.Title = (UBYTE *)Titles[ReqType];
	NWS.Screen = Screen;
	Center(&NWS, NWS.Width/2, NWS.Height/2);
	if (!(IW = OpenWindow(&NWS))) {
		FreeMem(Gads, sizeof(struct ReqGadgets));
		return FALSE;
	}
	SetMenuStrip(IW, &Menu1);
	SetAPen(IW->RPort, 1);
	if (ReqType != PROTECT_REQ) {
		MakeFileDirGadgets(Gads, IW, SelectInfo->si_Flags);
		for( i=0, y=35 ; i<5 ; i++ ) {
			Move(IW->RPort, 8, y);
			Text(IW->RPort, TextTab[i], strlen(TextTab[i]));
			y += 14;
		}
		y = 105;
	}
	else
		y = 20;
	Move(IW->RPort, 8, y);
	Text(IW->RPort, "Protection:  C H S P A R W E D", 30);
	ActivateGadget(&Gads->StringGadgets[0].Gadget, IW, NULL);
	do {
		while (!quit) {
			WaitPort(IW->UserPort);
			while (IMsg = (struct IntuiMessage *)GetMsg(IW->UserPort)) {
				Class = IMsg->Class;
				Code = IMsg->Code;
				Qual = IMsg->Qualifier;
				/* Use raw keys to prevent ALT and CTRL convertions. Allow only Shift qualifiers */
				if (Class == RAWKEY) {
					Code = RawKeyToAscii(Code, Qual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT), IMsg->IAddress);
					if (Code != 0 && (Qual & ParMConfig.ShortCutQual) && !(Qual & IEQUALIFIER_REPEAT)) {
						Code = MakeMenuShortCut(&Menu1, Code);
						Class = MENUPICK;
					}
				}
				G = (struct Gadget *)IMsg->IAddress;
				ReplyMsg((struct Message *)IMsg);
				switch(Class) {
				case CLOSEWINDOW:
					Ok = FALSE;
					quit = TRUE;
					break;
				case MENUPICK:
					switch(ITEMNUM(Code)) {
					case 0:		/* Reset */
						setmem(Gads->Buffer, PATTERN_BUF_SIZE * 5, 0);
						setmem(Gads->UndoBuffer, PATTERN_BUF_SIZE * 5, 0);
						Gads->Gadgets1[0].Gadget.Flags |= SELECTED;
						Gads->Gadgets1[1].Gadget.Flags |= SELECTED;
						Gads->Gadgets1[2].Gadget.Flags &= ~SELECTED;
						RefreshGadgets(IW->FirstGadget, IW, NULL);
						RefreshProtect(Gads, IW, 0xFFFF, 0);
						switch(ReqType) {
						case SELECT_REQ:
							MakeFileDirGadgets(Gads, IW, SI_MATCH_FILES|SI_MATCH_DIRS);
							break;
						case FILTERS_REQ:
							MakeFileDirGadgets(Gads, IW, SI_ALL_FILES|SI_ALL_DIRS);
							break;
						}
						break;
					case 1:		/* Leave */
						Ok = FALSE;
						quit = TRUE;
						break;
					}
					break;
				case GADGETUP:
					NextString = 0;
					ds = NULL;
					switch(G->GadgetID) {
					case 1:		/* Ok */
						Ok = TRUE;
						quit = TRUE;
						break;
					case 2:		/* Cancel */
						Ok = FALSE;
						quit = TRUE;
						break;
					case 3:		/* Clear */
						RefreshProtect(Gads, IW, 0x00FF, 2);
						break;
					case 4:		/* RWED */
						RefreshProtect(Gads, IW, 0x000F, 1);
						break;
					case 13:
						ds = &SelectInfo->si_SinceDate;
						NextString = 4;
						break;
					case 14:
						ds = &SelectInfo->si_BeforeDate;
						break;
					default:
						NextString = G->GadgetID-10+1;
					}
					if (ds) {
						i = G->GadgetID-10;
						if (!IsEmpty(Gads->Buffer[i])) {
							if (String2Date(Gads->Buffer[i], ds)) {
								Date2String(ds, Gads->Buffer[i]);
								RefreshGList(&Gads->StringGadgets[i].Gadget, IW, NULL, 1);
							}
							else
								NextString = i;	/* Reactivate same gadget */
						}
					}
					if (G->GadgetID >= 10 && G->GadgetID <= 14 && (Qual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))) {
						Ok = TRUE;
						quit = TRUE;
					} else if (NextString)
						ActivateGadget(&Gads->StringGadgets[NextString].Gadget, IW, NULL);
					break;
				case GADGETDOWN:
					if (G == &Gads->Gadgets1[0].Gadget)
						DoFileDirGadget(IW, G);
					else if (G == &Gads->Gadgets1[1].Gadget)
						DoFileDirGadget(IW, G);
					else
						DoProtectGadget(IW, G);
					break;
				}
			}
		}
		if (Ok) {
			SelectInfo->si_Flags = 0;
			if (ReqType != PROTECT_REQ) {
				if (!IsEmpty(Gads->Buffer[3])) {
					if (!String2Date(Gads->Buffer[3], &SelectInfo->si_SinceDate)) {
						ActivateGadget(&Gads->StringGadgets[3].Gadget, IW, NULL);
						quit = FALSE;
						continue;
					}
					SelectInfo->si_SinceSecs = Date2Secs(&SelectInfo->si_SinceDate);
					SelectInfo->si_Flags |= SI_SINCEDATE;
				}
				if (!IsEmpty(Gads->Buffer[4])) {
					if (!String2Date(Gads->Buffer[4], &SelectInfo->si_BeforeDate)) {
						ActivateGadget(&Gads->StringGadgets[4].Gadget, IW, NULL);
						quit = FALSE;
						continue;
					}
					SelectInfo->si_BeforeSecs = Date2Secs(&SelectInfo->si_BeforeDate);
					SelectInfo->si_Flags |= SI_BEFOREDATE;
				}
				/* First clear pattern to avoid trouble in structure comparison */
				setmem(SelectInfo->si_Pattern, PATTERN_BUF_SIZE, 0);
				if (!IsEmpty(Gads->Buffer[0])) {
					strcpy(SelectInfo->si_Pattern, Gads->Buffer[0]);
					UStrcpy(buf, SelectInfo->si_Pattern);
					PreParse(buf, SelectInfo->si_PatTok);	/* tokenize Pattern for PatternMatch() */
					SelectInfo->si_Flags |= SI_NAME;
				}
				SelectInfo->si_MinSize = ((struct StringInfo *)Gads->StringGadgets[1].Gadget.SpecialInfo)->LongInt;
				SelectInfo->si_MaxSize = ((struct StringInfo *)Gads->StringGadgets[2].Gadget.SpecialInfo)->LongInt;
				if (SelectInfo->si_MinSize || SelectInfo->si_MaxSize)
					SelectInfo->si_Flags |= SI_SIZE;
				if (ReqType == SELECT_REQ && (Gads->Gadgets1[2].Gadget.Flags & SELECTED))
					SelectInfo->si_Flags |= SI_AFFECT_SUBDIRS;
				for( i=0 ; i<2 ; i++ )
					SelectInfo->si_Flags |= Gads->Gadgets1[i].Gadget.GadgetID << (i<<1);
			}
			SelectInfo->si_PosProtect = 0;
			SelectInfo->si_NegProtect = 0;
			for( i=0 ; i<9 ; i++ ) {
				G = &Gads->Gadgets3[i];
				/* state of Gadget is in GadgetID */
				switch(G->GadgetID) {
				case 1:
					SelectInfo->si_PosProtect |= 1<<i;
					SelectInfo->si_Flags |= SI_POSPROTECTION;
					break;
				case 2:
					SelectInfo->si_NegProtect |= 1<<i;
					SelectInfo->si_Flags |= SI_NEGPROTECTION;
					break;
				}
			}
		}
	} while(!quit && Ok);	/* quit may be FALSE again if there was an invalid date */
	ClearMenuStrip(IW);
	CloseWindowSafely(IW, NULL);
	FreeMem(Gads, sizeof(struct ReqGadgets));
	return Ok;
}


short C3GadRequest(char *PositiveText, char *MiddleText, char *fmt, char *Controls);
#pragma regcall(C3GadRequest(a0,a1,a2,a3))


short C3GadRequest(char *PositiveText, char *MiddleText, char *fmt, char *Controls)
{
	struct TRStructure TRS;

	setmem(&TRS, sizeof(struct TRStructure), 0);
	TRS.PositiveText = PositiveText;
	TRS.MiddleText = MiddleText;
	TRS.NegativeText = "Cancel";
	TRS.Text = fmt;
	TRS.Controls = Controls;
	TRS.Title = ReqTitle;
	TRS.KeyMask = 0xFFFF;
	return TextRequest(&TRS);
}


#asm

;short ThreeGadRequest(char *PositiveText, char *MiddleText, char *fmt,...)

	public	_ThreeGadRequest
	public	_C3GadRequest

_ThreeGadRequest:
	movem.l a2/a3,-(sp)
	move.l	12(sp),a0		;TR_PositiveText
	move.l	16(sp),a1		;TR_MiddleText
	move.l	20(sp),a2		;TR_Text
	lea.l	24(sp),a3		;TR_Controls
	jsr		_C3GadRequest
	movem.l (sp)+,a2/a3
	rts

#endasm

