#include "sumstl.h"

#define SELBIT   1
#define HELPBIT  2

#define ClearBits(bits) UMSSelectTags(acc,UMSTAG_SelWriteLocal,TRUE,UMSTAG_SelUnset,bits,TAG_DONE)
#define SetBits(mask,match,bits) UMSSelectTags(acc,UMSTAG_SelReadLocal,TRUE,UMSTAG_SelMask,mask,UMSTAG_SelMatch,match,UMSTAG_SelWriteLocal,TRUE,UMSTAG_SelSet,bits,TAG_DONE)

#define TYPE_SPECIAL 0
#define TYPE_STRING  1
#define TYPE_UFLAG   2
#define TYPE_GFLAG   3
#define TYPE_DATE    4
#define TYPE_AGE     5

#define DT_EQUAL  0
#define DT_LOWER  1
#define DT_HIGHER 2
#define DT_LOWEQ  3
#define DT_HIGHEQ 4

struct Filter
{
	UBYTE *keyword;
	LONG type;
	LONG tagorflag;
	VOID (* __regargs specialfunc)(APTR acc,UBYTE *value,LONG bit,BOOL not);
};


VOID __regargs SelMsgNumFunc(APTR acc,UBYTE *value,LONG bit,BOOL not)
{
	char *c;
	int from,to;

	from = atol(value);
	to   = (c=strchr(value,'-')) ? atol(c+1) : from;

	if (from>to) return;

	if (not)
	{
		ClearBits(HELPBIT);

		UMSSelectTags(acc,
		 UMSTAG_SelQuick     ,TRUE,
		 UMSTAG_SelWriteLocal,TRUE,
		 UMSTAG_SelStart     ,from,
		 UMSTAG_SelStop      ,to+1,
	    UMSTAG_SelSet       ,HELPBIT,
		 TAG_DONE);

		SetBits(HELPBIT,0,bit);
	}
	else
	{
		UMSSelectTags(acc,
		 UMSTAG_SelQuick     ,TRUE,
		 UMSTAG_SelWriteLocal,TRUE,
		 UMSTAG_SelStart     ,from,
		 UMSTAG_SelStop      ,to+1,
	    UMSTAG_SelSet       ,bit,
		 TAG_DONE);
	}
}


static struct Filter Filter[] =
{
	{ "GROUP="      ,TYPE_STRING,UMSTAG_WGroup       , NULL },
	{ "TOUSER="    ,TYPE_STRING,UMSTAG_WToName      , NULL },
	{ "FROMUSER="  ,TYPE_STRING,UMSTAG_WFromName    , NULL },
	{ "SUBJECT="   ,TYPE_STRING,UMSTAG_WSubject     , NULL },

	{ "DATE<="     ,TYPE_DATE  ,DT_LOWEQ            , NULL },
	{ "DATE>="     ,TYPE_DATE  ,DT_HIGHEQ           , NULL },
	{ "DATE="      ,TYPE_DATE  ,DT_EQUAL            , NULL },
	{ "DATE>"      ,TYPE_DATE  ,DT_HIGHER           , NULL },
	{ "DATE<"      ,TYPE_DATE  ,DT_LOWER            , NULL },

	{ "AGE<="      ,TYPE_AGE   ,DT_HIGHEQ           , NULL },
	{ "AGE>="      ,TYPE_AGE   ,DT_LOWEQ            , NULL },
	{ "AGE="       ,TYPE_AGE   ,DT_EQUAL            , NULL },
	{ "AGE>"       ,TYPE_AGE   ,DT_LOWER            , NULL },
	{ "AGE<"       ,TYPE_AGE   ,DT_HIGHER           , NULL },

	{ "ARCHIVE"    ,TYPE_UFLAG ,UMSUSTATF_Archive   , NULL },
	{ "JUNK"       ,TYPE_UFLAG ,UMSUSTATF_Junk      , NULL },
	{ "POSTPONED"  ,TYPE_UFLAG ,UMSUSTATF_PostPoned , NULL },
	{ "SELECTED"   ,TYPE_UFLAG ,UMSUSTATF_Selected  , NULL },
	{ "OLD"        ,TYPE_UFLAG ,UMSUSTATF_Old       , NULL },
	{ "WRITEACCESS",TYPE_UFLAG ,UMSUSTATF_Selected  , NULL },
	{ "READACCESS" ,TYPE_UFLAG ,UMSUSTATF_ReadAccess, NULL },
	{ "VIEWACCESS" ,TYPE_UFLAG ,UMSUSTATF_ViewAccess, NULL },
	{ "OWNER"      ,TYPE_UFLAG ,UMSUSTATF_Owner     , NULL },
	{ "DELETED"    ,TYPE_GFLAG ,UMSGSTATF_Deleted   , NULL },
	{ "EXPIRED"    ,TYPE_GFLAG ,UMSGSTATF_Expired   , NULL },
	{ "EXPORTED"   ,TYPE_GFLAG ,UMSGSTATF_Exported  , NULL },
	{ "ORPHAN"     ,TYPE_GFLAG ,UMSGSTATF_Orphan    , NULL },
	{ "LINK"       ,TYPE_GFLAG ,UMSGSTATF_Link      , NULL },
	{ "HARDLINK"   ,TYPE_GFLAG ,UMSGSTATF_HardLink  , NULL },

	{ "MSGNUM="    ,TYPE_SPECIAL,0,SelMsgNumFunc },

	{ NULL        ,0            ,0               , NULL }
};


struct Filter *FindFilter(UBYTE *name)
{
	struct Filter *f;
	for (f=Filter;f->keyword;f++)
		if (!strnicmp(name,f->keyword,strlen(f->keyword))) return(f);
	return(NULL);
}


UBYTE *cutspaces(UBYTE *str)
{
	#define ISSPACE(c) ((c)==' ' || (c)=='\t')
   UBYTE *s=str+strlen(str);

   while (s!=str)
   {
      s--;
      if (ISSPACE(*s))
         *s=0;
      else
         break;
   }
	while (ISSPACE(*str)) str++;
   return(str);
}


BOOL Filter2(APTR acc,LONG prebit,UBYTE *x,LONG bit)
{
	struct Filter *f;
	BOOL not;
	UBYTE *str;

	x=cutspaces(x);

	if (*x=='!')
	{
		not=TRUE;
		x++;
	}
	else
	{
		not=FALSE;
	}

	if (!(f=FindFilter(x))) return(FALSE);

	str = x + strlen(f->keyword);

	if (f->type==TYPE_STRING)
	{
		if (not)
		{
			ClearBits(HELPBIT);

			UMSSelectTags(acc,
			 UMSTAG_SelQuick     ,TRUE,
			 UMSTAG_SelWriteLocal,TRUE,
			 UMSTAG_SelSet       ,HELPBIT,
			 f->tagorflag        ,(f->tagorflag!=UMSTAG_WGroup || stricmp(str,"Netmail")) ? str : NULL,
			 TAG_DONE);

			SetBits(prebit|HELPBIT,prebit,bit);
		}
		else
		{
			UMSSelectTags(acc,
			 UMSTAG_SelQuick     ,TRUE,
			 UMSTAG_SelWriteLocal,TRUE,
			 UMSTAG_SelSet       ,bit,
			 f->tagorflag           ,(f->tagorflag!=UMSTAG_WGroup || stricmp(str,"Netmail")) ? str : NULL,
			 TAG_DONE);
		}
	}
	else if (f->type==TYPE_UFLAG)
	{
		UMSSelectTags(acc,
		 UMSTAG_SelQuick     ,TRUE,
		 UMSTAG_SelWriteLocal,TRUE,
		 UMSTAG_SelMask      ,f->tagorflag,
		 UMSTAG_SelMatch     ,not ? 0 : f->tagorflag,
		 UMSTAG_SelSet       ,bit,
		 TAG_DONE);
	}
	else if (f->type==TYPE_GFLAG)
	{
		UMSSelectTags(acc,
		 UMSTAG_SelQuick     ,TRUE,
		 UMSTAG_SelWriteLocal,TRUE,
		 UMSTAG_SelReadGlobal,TRUE,
		 UMSTAG_SelMask      ,f->tagorflag,
		 UMSTAG_SelMatch     ,not ? 0 : f->tagorflag,
		 UMSTAG_SelSet       ,bit,
		 TAG_DONE);
	}
	else if (f->type==TYPE_DATE || f->type==TYPE_AGE)
	{
		LONG secs = f->type==TYPE_DATE ? DateToSeconds(str) : (CurrentSeconds()/(24*60*60) - atol(str))*(24*60*60);

		if (secs>0)
		{
			if (f->tagorflag==DT_HIGHEQ)
			{
				UMSSelectTags(acc,
				 UMSTAG_SelQuick     ,TRUE,
				 UMSTAG_SelWriteLocal,TRUE,
				 UMSTAG_SelDate      ,secs,
			    UMSTAG_SelSet       ,bit,
				 TAG_DONE);
			}
			else if (f->tagorflag==DT_LOWER)
			{
				UMSSelectTags(acc,
				 UMSTAG_SelQuick     ,TRUE,
				 UMSTAG_SelWriteLocal,TRUE,
				 UMSTAG_SelDate      ,secs,
				 UMSTAG_SelSet       ,HELPBIT,
				 TAG_DONE);

				SetBits(prebit|HELPBIT,prebit,bit);
			}
			else if (f->tagorflag==DT_HIGHER)
			{
				UMSSelectTags(acc,
				 UMSTAG_SelQuick     ,TRUE,
				 UMSTAG_SelWriteLocal,TRUE,
				 UMSTAG_SelDate      ,secs + 24*60*60,
			    UMSTAG_SelSet       ,bit,
				 TAG_DONE);
			}
			else if (f->tagorflag==DT_LOWEQ)
			{
				UMSSelectTags(acc,
				 UMSTAG_SelQuick     ,TRUE,
				 UMSTAG_SelWriteLocal,TRUE,
				 UMSTAG_SelDate      ,secs + 24*60*60,
			    UMSTAG_SelSet       ,HELPBIT,
				 TAG_DONE);

				SetBits(prebit|HELPBIT,prebit,bit);
			}
			else if (f->tagorflag==DT_EQUAL)
			{
				UMSSelectTags(acc,
				 UMSTAG_SelQuick     ,TRUE,
				 UMSTAG_SelWriteLocal,TRUE,
				 UMSTAG_SelDate      ,secs,
			    UMSTAG_SelSet       ,bit,
				 TAG_DONE);

				UMSSelectTags(acc,
				 UMSTAG_SelQuick     ,TRUE,
				 UMSTAG_SelWriteLocal,TRUE,
				 UMSTAG_SelDate      ,secs + 24*60*60-1,
			    UMSTAG_SelUnset     ,bit,
				 TAG_DONE);
			}
		}
	}
	else if (f->type==TYPE_SPECIAL && f->specialfunc)
	{
		f->specialfunc(acc,str,bit,not);
	}
	else
	{
		return(FALSE);
	}

	return(TRUE);
}


VOID Filter1(APTR acc,LONG prebit,UBYTE *buf,LONG bit)
{
	UBYTE *arg,*c;

	for (arg=buf ; arg ; arg = c ? c+1 : NULL)
	{
		if (c=strchr(arg,'|')) *c=0;
		Filter2(acc,prebit,arg,bit);
	}
}


LONG UmsFilter(APTR acc,UBYTE *exp,BOOL cont)
{
	UBYTE *buf,*arg,*c;
	LONG prebit=0,bit=4,mask=0;

	if (!cont) ClearBits(SELBIT);

	if (!(buf=strdup(exp))) return(-1);

	for (arg=buf; arg ; arg = c ? c+1 : 0 , prebit|=bit,bit<<=1)
	{
		if (c=strchr(arg,'&')) *c=0;
		Filter1(acc,prebit,arg,bit);
		mask|=bit;
	}

	free(buf);

	ClearBits(HELPBIT);
	return(SetBits(mask,mask,SELBIT));
}
