/*
 * This file is part of the FEddi package
 *
 * Personal use allowed under the terms of the
 *
 *              GNU GENERAL PUBLIC LICENSE Version 2
 *              (see LICENSE for the complete text)
 *
 *-------------------------------------------------------------------
 *
 *    ENTER AT YOUR OWN RISK !!
 *
 * This source is without any documentation and can drive you mad.
 * In case of sudden epileptic seizures please call your doctor.
 *
 */

#include <stdlib.h>
#include <ncurses.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include "regex.h"
#include "charset.h"
#include "proc.h"
#include "structs.h"
#include "functs.h"
#include "colors.h"
#include "mbsearch.h"

extern MsgHdrType *MsgHdr;
extern WINDOW *wTxt, *wHlp;
extern LineListType *MsgTxt;
extern int curMsg, MsgLines, curLine;

extern void loadtxt(int);

char MBSSearchString[80]="";
char MBSString[400]="", MBSFoundString[80]="";
int MBSFields=0, MBSActualField=0, MBSFoundMsg=-1;
int MBSStringPosX=0, MBSStringPosY=0;
struct re_pattern_buffer MBSExpression;
struct re_registers MBSRegisters;

int startsearch()
{
	WINDOW *win;
	char search[80];
	int in=0, fr=0, to=0, sj=0, tx=0, ign=0;
	if ((win=openask(4,80,LINES/2+2,0,"Start Search",COL_Menu))!=NULL)
	{
		strcpy(search,MBSSearchString);
		mvwaddstr(win,2,2,"enter empty line to cancel search");
		if (!inputline(win,wHlp,1,1,78,search,NULL,0,0))
		{
			mvwaddstr(win,2,2,"in From To Subject teXt (Ignore case)");
			wrefresh(win);
			while (in!=10 && in!=27)
			{
				switch ((in=getchn()))
				{
					case 0x1b:
						getch();
						break;
					case 'f':
					case 'F':
						fr=1-fr;
						if (fr)
							wcolon(win,COL_MenuHigh);
						else
							wcolon(win,COL_Menu);
						mvwaddstr(win,2,5,"From");
						wrefresh(win);
						break;
					case 't':
					case 'T':
						to=1-to;
						if (to)
							wcolon(win,COL_MenuHigh);
						else
							wcolon(win,COL_Menu);
						mvwaddstr(win,2,10,"To");
						wrefresh(win);
						break;
					case 's':
					case 'S':
						sj=1-sj;
						if (sj)
							wcolon(win,COL_MenuHigh);
						else
							wcolon(win,COL_Menu);
						mvwaddstr(win,2,13,"Subject");
						wrefresh(win);
						break;
					case 'x':
					case 'X':
						tx=1-tx;
						if (tx)
							wcolon(win,COL_MenuHigh);
						else
							wcolon(win,COL_Menu);
						mvwaddstr(win,2,21,"teXt");
						wrefresh(win);
						break;
					case 'i':
					case 'I':
						if ((ign=1-ign))
							wcolon(win,COL_MenuHigh);
						else
							wcolon(win,COL_Menu);
						mvwaddstr(win,2,27,"Ignore case");
						wrefresh(win);
						break;
				}
			}
			if (in==10)
				if (initsearch(search,fr,to,sj,tx,ign)) donesearch();
		} else
			donesearch();
		delwin(win);
		touchwin(wTxt);
		wrefresh(wTxt);
		if (in==10)
			return 1;
		else
			return 0;
	}
	Beep();
	return 0;
}

int initsearch(char *s, int fr, int to, int sj, int tx, int ign)
{
	if (fr) MBSActualField=1;
		else if (to) MBSActualField=2;
			else if (sj) MBSActualField=3;
				else if (tx) MBSActualField=4;
					else return 1;
	strcpy(MBSSearchString,s);
	memset(&MBSRegisters,0,sizeof(struct re_registers));
	MBSFields=(fr?1:0)+(to?2:0)+(sj?4:0)+(tx?8:0);
	MBSString[0]=0;
	MBSFoundMsg=-1;
	MBSStringPosX=-1;
	MBSStringPosY=0;
	memset(&MBSExpression,0,sizeof(struct re_pattern_buffer));
	if (ign) MBSExpression.translate=(unsigned char *)RE_ICASE_TRANS_MAP;
	re_set_syntax(RE_SYNTAX_POSIX_EGREP);
	re_compile_pattern(MBSSearchString,strlen(MBSSearchString),&MBSExpression);
	return 0;
}

void donesearch()
{
	MBSSearchString[0]=0;
	MBSFields=0;
	MBSString[0]=0;
	MBSActualField=0;
}

void freeRegs()
{
	free(MBSRegisters.start);
	free(MBSRegisters.end);
	memset(&MBSRegisters,0,sizeof(struct re_registers));
}

int searchnext(int cur, int new)
{
	int i, pos, j, ocm, old, oldx, oldy, oldf;
	char *oldstring;
	old=MBSActualField;
	oldf=MBSFoundMsg;
	oldy=MBSStringPosY;
	oldx=MBSStringPosX;
	oldstring=strdup(MBSString);
	if (cur!=MBSFoundMsg || new)
	{
		if (MBSFields&1) MBSActualField=1;
			else if (MBSFields&2) MBSActualField=2;
				else if (MBSFields&4) MBSActualField=3;
					else if (MBSFields&8) MBSActualField=4;
		MBSString[0]=0;
		MBSFoundMsg=-1;
		MBSStringPosX=-1;
		MBSStringPosY=-1;
	}
	if (MBSSearchString[0] && MBSFields)
		for (i=cur; i<TotalMsgs; i++)
		{
			MBSFoundMsg=i;
			if (MsgHdr[i].Deleted) continue;
			if ((MBSFields&1) && MBSActualField==1)
			{
				if (MBSString[0]==0)
				{
					strcpy(MBSString,MsgHdr[i].WhoFrom);
					MBSStringPosX=0;
				} else
					MBSStringPosX++;
				pos=re_search(&MBSExpression,MBSString,strlen(MBSString),
						MBSStringPosX,strlen(MBSString)-MBSStringPosX,&MBSRegisters);
				if (pos!=-1)
				{
					MBSStringPosX=pos;
					strncpy(MBSFoundString,&(MsgHdr[i].WhoFrom[MBSRegisters.start[0]]),
							MBSRegisters.end[0]-MBSRegisters.start[0]);
					MBSFoundString[MBSRegisters.end[0]-MBSRegisters.start[0]]=0;
					freeRegs();
					free(oldstring);
					return i;
				}
				MBSString[0]=0;
			}
			if (MBSActualField==1) MBSActualField++;
			if ((MBSFields&2) && MBSActualField==2)
			{
				if (MBSString[0]==0)
				{
					strcpy(MBSString,MsgHdr[i].WhoTo);
					MBSStringPosX=0;
				} else
					MBSStringPosX++;
				pos=re_search(&MBSExpression,MBSString,strlen(MBSString),
						MBSStringPosX,strlen(MBSString)-MBSStringPosX,&MBSRegisters);
				if (pos!=-1)
				{
					MBSStringPosX=pos;
					strncpy(MBSFoundString,&(MsgHdr[i].WhoTo[MBSRegisters.start[0]]),
							MBSRegisters.end[0]-MBSRegisters.start[0]);
					MBSFoundString[MBSRegisters.end[0]-MBSRegisters.start[0]]=0;
					freeRegs();
					free(oldstring);
					return i;
				}
				MBSString[0]=0;
			}
			if (MBSActualField==2) MBSActualField++;
			if ((MBSFields&4) && MBSActualField==3)
			{
				if (MBSString[0]==0)
				{
					strcpy(MBSString,MsgHdr[i].Subj);
					MBSStringPosX=0;
				} else
					MBSStringPosX++;
				pos=re_search(&MBSExpression,MBSString,strlen(MBSString),
						MBSStringPosX,strlen(MBSString)-MBSStringPosX,&MBSRegisters);
				if (pos!=-1)
				{
					MBSStringPosX=pos;
					strncpy(MBSFoundString,&(MsgHdr[i].Subj[MBSRegisters.start[0]]),
							MBSRegisters.end[0]-MBSRegisters.start[0]);
					MBSFoundString[MBSRegisters.end[0]-MBSRegisters.start[0]]=0;
					freeRegs();
					free(oldstring);
					return i;
				}
				MBSString[0]=0;
			}
			if (MBSActualField==3) MBSActualField++;
			if ((MBSFields&8) && MBSActualField==4)
			{
				if (MBSString[0]==0)
				{
					ocm=curMsg;
					curMsg=i;
					loadtxt(0);
					curMsg=ocm;
					MBSStringPosY=0;
				}
				for (j=MBSStringPosY; j<MsgLines; j++)
				{
					if (MBSString[0]==0)
					{
						strcpy(MBSString,MsgTxt[j].line);
						MBSStringPosX=0;
					} else
						MBSStringPosX++;
					pos=re_search(&MBSExpression,MBSString,strlen(MBSString),
							MBSStringPosX,strlen(MBSString)-MBSStringPosX,&MBSRegisters);
					if (pos!=-1)
					{
						MBSStringPosX=pos;
						MBSStringPosY=j;
						strncpy(MBSFoundString,&(MsgTxt[j].line[MBSRegisters.start[0]]),
								MBSRegisters.end[0]-MBSRegisters.start[0]);
						MBSFoundString[MBSRegisters.end[0]-MBSRegisters.start[0]]=0;
						freeRegs();
						free(oldstring);
						return i;
					}
					MBSString[0]=0;
				}
			}
			MBSActualField=1;
		}
	MBSActualField=old;
	MBSFoundMsg=oldf;
	MBSStringPosY=oldy;
	MBSStringPosX=oldx;
	strcpy(MBSString,oldstring);
	free(oldstring);
	freeRegs();
	loadtxt(0);
	return -1;
}

int searchprev(int cur, int new)
{
	int i, pos, j, ocm, old, oldx, oldy, oldf;
	char *oldstring;
	old=MBSActualField;
	oldf=MBSFoundMsg;
	oldy=MBSStringPosY;
	oldx=MBSStringPosX;
	oldstring=strdup(MBSString);
	if (cur!=MBSFoundMsg)
	{
		if (MBSFields&8) MBSActualField=4;
			else if (MBSFields&4) MBSActualField=3;
				else if (MBSFields&2) MBSActualField=2;
					else if (MBSFields&1) MBSActualField=1;
		MBSString[0]=0;
		MBSFoundMsg=-1;
		MBSStringPosX=-1;
		MBSStringPosY=-1;
	}
	if (MBSSearchString[0] && MBSFields)
		for (i=cur; i>=0; i--)
		{
			MBSFoundMsg=i;
			if (MsgHdr[i].Deleted) continue;
			if ((MBSFields&8) && MBSActualField==4)
			{
				if (MBSString[0]==0)
				{
					ocm=curMsg;
					curMsg=i;
					loadtxt(0);
					curMsg=ocm;
					MBSStringPosY=MsgLines-1;
				}
				for (j=MBSStringPosY; j>=0; j--)
				{
					if (MBSString[0]==0)
					{
						strcpy(MBSString,MsgTxt[j].line);
						MBSStringPosX=strlen(MBSString);
					} else
						MBSStringPosX--;
					pos=re_search(&MBSExpression,MBSString,strlen(MBSString),
							MBSStringPosX,-MBSStringPosX,&MBSRegisters);
					if (pos!=-1)
					{
						MBSStringPosX=pos;
						MBSStringPosY=j;
						strncpy(MBSFoundString,&(MsgTxt[j].line[MBSRegisters.start[0]]),
								MBSRegisters.end[0]-MBSRegisters.start[0]);
						MBSFoundString[MBSRegisters.end[0]-MBSRegisters.start[0]]=0;
						freeRegs();
						free(oldstring);
						return i;
					}
					MBSString[0]=0;
				}
			}
			if (MBSActualField==4) MBSActualField--;
			if ((MBSFields&4) && MBSActualField==3)
			{
				if (MBSString[0]==0)
				{
					strcpy(MBSString,MsgHdr[i].Subj);
					MBSStringPosX=strlen(MBSString);
				} else
					MBSStringPosX--;
				pos=re_search(&MBSExpression,MBSString,strlen(MBSString),
						MBSStringPosX,-MBSStringPosX,&MBSRegisters);
				if (pos!=-1)
				{
					MBSStringPosX=pos;
					strncpy(MBSFoundString,&(MsgHdr[i].Subj[MBSRegisters.start[0]]),
							MBSRegisters.end[0]-MBSRegisters.start[0]);
					MBSFoundString[MBSRegisters.end[0]-MBSRegisters.start[0]]=0;
					freeRegs();
					free(oldstring);
					return i;
				}
				MBSString[0]=0;
			}
			if (MBSActualField==3) MBSActualField--;
			if ((MBSFields&2) && MBSActualField==2)
			{
				if (MBSString[0]==0)
				{
					strcpy(MBSString,MsgHdr[i].WhoTo);
					MBSStringPosX=strlen(MBSString);
				} else
					MBSStringPosX--;
				pos=re_search(&MBSExpression,MBSString,strlen(MBSString),
						MBSStringPosX,-MBSStringPosX,&MBSRegisters);
				if (pos!=-1)
				{
					MBSStringPosX=pos;
					strncpy(MBSFoundString,&(MsgHdr[i].WhoTo[MBSRegisters.start[0]]),
							MBSRegisters.end[0]-MBSRegisters.start[0]);
					MBSFoundString[MBSRegisters.end[0]-MBSRegisters.start[0]]=0;
					freeRegs();
					free(oldstring);
					return i;
				}
				MBSString[0]=0;
			}
			if (MBSActualField==2) MBSActualField--;
			if ((MBSFields&1) && MBSActualField==1)
			{
				if (MBSString[0]==0)
				{
					strcpy(MBSString,MsgHdr[i].WhoFrom);
					MBSStringPosX=strlen(MBSString);
				} else
					MBSStringPosX--;
				pos=re_search(&MBSExpression,MBSString,strlen(MBSString),
						MBSStringPosX,-MBSStringPosX,&MBSRegisters);
				if (pos!=-1)
				{
					MBSStringPosX=pos;
					strncpy(MBSFoundString,&(MsgHdr[i].WhoFrom[MBSRegisters.start[0]]),
							MBSRegisters.end[0]-MBSRegisters.start[0]);
					MBSFoundString[MBSRegisters.end[0]-MBSRegisters.start[0]]=0;
					freeRegs();
					free(oldstring);
					return i;
				}
				MBSString[0]=0;
			}
			MBSActualField=4;
		}
	MBSActualField=old;
	MBSFoundMsg=oldf;
	MBSStringPosY=oldy;
	MBSStringPosX=oldx;
	strcpy(MBSString,oldstring);
	free(oldstring);
	freeRegs();
	loadtxt(0);
	return -1;
}
