{*************************************************************************
 ***                                                                   ***
 ***                    DIRECTORY SEARCH OBJECTS                       ***
 ***                                                                   ***
 *************************************************************************}
{A way of analysing the directory list for mailshots, reports, etc}
{Provides two objects - one that creates an extracted list based on
search criteria.  This can then be viewed and modified just like any other
directory list.  The second one actually does the output, and is separate
so we can do it for any normal list as well.}
{$I compdirs}

unit KDirRpts;

INTERFACE

uses devices, jimmys, reports, dattime, scodes, jimprint, objects;

type
	{Search & Output types for shortcut keys to do report}
	PDirectorySearchOptions = ^TDirectorySearchOptions;
	TDirectorySearchOptions = record
		TaggedOnly : boolean; {whether to ignore non-tagged}
		FullDirectory : boolean; {whether to use basefitype passed as parameter}

		{basic detail checking}
		Name    : string[20];{}
		Address : string[20];
		Tel			: string[20];{}
		DOReg 	: TDateRange;
		CatCodes 	: string[7];

		{History detail checking}
		Date : TDateRange;
		QNoteCode : TScode;
		LetterCode : TScode;

		{extras - eg membership?}
	end;


	PDirectoryPrintOptions = ^TDirectoryPrintOptions;
	TDirectoryPrintOptions = record
		Tag 	: boolean; {Tag those found}
		List 	: boolean; {extract to list}

		{various kinds of "printed" output - label, full, summary, mailshot, etc}
		Editor : word;
		Target : word;
		DeviceName : string[8];
		PrintAs : word;
		Header : string[8];
		Form : string[8];
		MarkHistory : boolean; {mailshots - mark history as letter sent?}
		SortKey : string[30];  {which order to print in}
	end;

	{Skeleton object for all directory searches.  Pass SearchOptions and
	override MatchItem, EnterCriteria(eaSearch), presearch, etc if need be}
	PDirectoryReport =^TDirectoryReport;
	TDirectoryReport = object(TJimmyReport)

		SearchOptions : pointer;
		PrintOptions 	: TDirectoryPrintOptions;

		constructor Init(NTitle, NDescMsg : string;
												NBasefiType : byte; NStart, NEnd : longint;
												NSearch : pointer;
												NPrint : PDirectoryPrintOptions);
		procedure CommonInit; virtual;
		destructor Done; virtual;

		function EnterCriteria(eaType : word) : word; virtual;

		procedure PostSearch(command : word); virtual;

		function IsSortKey : boolean; virtual; {is there a sort key entered}
		function GetItemKey(Item : PObject) : string; virtual;

		procedure PreOutput; virtual ;
		procedure PostOutput; virtual ;
		procedure OutputItem(item : PObject; ItemNo : longint); virtual;
	end;

	{making up a special index list given a search criteria}
	PDirectorySearch =^TDirectorySearch;
	TDirectorySearch = object(TDirectoryReport)

		constructor Init(NTitle, NDescMsg : string;
												NBasefiType : byte; NStart, NEnd : longint;
												NSearch : PDirectorySearchOptions;
												NPrint : PDirectoryPrintOptions);

		function EnterCriteria(eaType : word) : word; virtual;

		procedure SetSearchRange; virtual;
		procedure PreSearch(command : word); virtual;

		function MatchItem(Item : PObject) : boolean;      virtual;
	end;

const
	paLabel 	= 0;
	paFull 		= 1;
	paSummary = 2;
	paMailshot = 3;

	paNothing = 9; {dummy to tell report not to produce anything, eg when tagging found}


IMPLEMENTATION

uses tuiedit,
			global,
			views,
			inpfname, editfile,
			kdirctry, kperson, kcompany, kqnote, address, kletter,
			labels,
			app,
			tuimsgs,
			indexes,
			jimhooks,
			{$IFDEF kwplink} kwplink, {$ENDIF}
			files,
			dialogs,
			printers, faxes,
			tasks,
			kamsetup,
			inpdnt,
			minilib;

{const
	foStdLtr	 	= 0; {mailshot}
{	foLabel 		= 1;
	foList 			= 2;{}


{************************************************************************
 ***                                                                  ***
 ***                    GENERAL DIRECTORY REPORT OBJECT               ***
 ***                                                                  ***
 ************************************************************************}
constructor TDirectoryReport.Init;
begin
	inherited Init(NTitle, NDescMsg);

	BasefiType := NBasefiType;
	StartRec := NStart;
	EndRec := NEnd;

	AskForSearch := NSearch=nil;
	SearchOptions := NSearch;

	AskForOutput := NPrint=nil;
	if not AskForOutput then PrintOptions := NPrint^;

	OnceOnly := (not AskForOutput) and (not AskForSearch); {important! to stop it from looping forever...}
end;

procedure TDirectoryReport.CommonInit;
begin
	inherited CommonInit;

	with PrintOptions do begin
		Tag 	:= False;
		List 	:= False;

		{various kinds of "printed" output - label, full, summary, mailshot, etc}
		Editor 	:= edInternal; {$IFDEF kwplink} {Editor := edWP51;{} {$ENDIF}
		PrintAs := paSummary; {summary}
		MarkHistory := False;

		SortKey := '';
	end;

	SCodeCollection[scDirectoryCategory]^.LogOn;
	SCodeCollection[scEvents]^.LogOn;

	AliasOptions := aoNoPrint;
end;

destructor TDirectoryReport.Done;
begin
	SCodeCollection[scDirectoryCategory]^.LogOff;
	SCodeCollection[scEvents]^.LogOff;
	inherited Done;
end;





{***********************************************************************
 ***                  USER ENTRY                                     ***
 ***********************************************************************{}
procedure LinkPrintAs(const Linker : PInputLinker; const CallingView : PView); far;
var	PrintAs : word;
		FormLine : PInputFName;
		HeaderLine : PInputFName;
		MarkLine : PInputBoolean;

begin
{	Linker^.SourceView[1]^.GetData(Editor);{}
	Linker^.SourceView[2]^.GetData(PrintAs);
	HeaderLine := PInputFname(Linker^.TargetView[1]);
	FormLine := PInputFname(Linker^.TargetView[2]);
	MarkLine := PInputBoolean(Linker^.TargetView[3]);

{	case Editor of
		edInternal : begin
			FormLine^.Path := FormsPath;
			FormLine^.FileEditor := EditTextFile;
			HeaderLine^.Path := FormsPath;
			HeaderLine^.FileEditor := EditTextFile;
		end;
{		{$IFDEF kwplink}
{		edWP51 : begin
			FormLine^.Path := WPSetup.FormsPath;
			FormLine^.FileEditor := EditWPFile;
			HeaderLine^.Path := WPSetup.FormsPath;
			HeaderLine^.FileEditor := EditWPFile;
		end;
		{$ENDIF}
{	end;{}

	case PrintAs of
		paFull : begin
			FOrmLine^.Ext := 'FRM';
			FormLine^.MustInputToClose := False;

			HeaderLine^.SetState(sfDisabled, False);
			HeaderLine^.Ext := 'HDR HD1';

			MarkLine^.SetState(sfDisabled, True);
		end;
		paLabel : begin
			FOrmLine^.Ext := 'FRM';
			FormLine^.MustInputToClose := False;

			HeaderLine^.SetState(sfDisabled, True);

			MarkLine^.SetState(sfDisabled, True);
		end;
		paSUmmary : begin
			FOrmLine^.Ext := 'FRM';
			FormLine^.MustInputToClose := False;

			HeaderLine^.SetState(sfDisabled, False);
			HeaderLine^.Ext := 'HDR HD1';

			MarkLine^.SetState(sfDisabled, True);
		end;
		paMailShot : begin
			FormLine^.Ext := 'FRM STL';
			FormLine^.MustInputToClose := True;

			HeaderLine^.SetState(sfDisabled, False);
			HeaderLine^.Ext := 'HDR HD1';

			MarkLine^.SetState(sfDisabled, False);
		end;
	end;

	MarkLine^.DrawView;
	HeaderLine^.DrawView;
	FormLine^.DrawView;
end;




function TDirectoryReport.EnterCriteria;
var EditBox : PEditBox;
		Bounds,R : TRect;
		Control,W : word;
		PrintAsLinker : PInputLinker;
		DeviceFormLinker : PInputLinker;

begin
	EditBox := nil;
	Control := cmOK;

	case eaType of
		{=================== OUTPUT TYPE ==================================}
		eaOutput, eaOutputNow : begin
			{Ask for type of print}
			Bounds.Assign(0,0,42,20);
			New(EditBox, init(Bounds, 'Print Options', @Self));

			New(PrintASLinker, init(@LInkPrintAs,EditBox));
{			PrintAsLinker^.ForceInitLink := True;{see checkinitlinks below}

			with EditBox^ do begin
				Options := Options or ofCentered;

				{skip these two - set by special reports, eg Tag Selected, etc
				InsTitledField(15,1, 1,1, 'Tag Found', New(PInputBoolean,init(Bounds)));
				InsTitledField(15,2, 1,1, 'List Found', New(PInputBoolean,init(Bounds)));{}
				Insert(New(PSkipBytes, init(sizeof(Boolean)*2)));

				AddStdDevFormFields(EditBox, DeviceFormLinker);

				{-- set editor default ---}
				W := S2Num(ProgramSetup.Get(siDefedType, N2Str(edInternal)));
				PCluster(DeviceFormLinker^.SourceView[svEditor])^.SetData(W);

				{disable email & fax, for reports...}
				with PCluster(DeviceFormLinker^.SourceView[svTarget])^ do
					EnableMask := EnableMask and not exp2(ptFax) and not exp2(ptemail);


				InsTitledField( 3,9, 15,4, '', New(PERadioButtons, init(Bounds,
{																						NewSitem('Nothing',{}
																						NewSItem('~L~abel',
																						NewSItem('F~u~ll',
																						NewSItem('~S~ummary',
																						NewSItem('~M~ailshot',
																						nil)))))));
				PrintAsLinker^.SetSourceView(Current, 2);

				InsTitledField(30,11, 8,1, '~H~eader', New(PInputFName, init(Bounds, 8, 'HDR HD1', FormsPath,True,EditTextFile)));
				PrintAsLinker^.SetTargetView(Current, 1);{}
				DeviceFormLinker^.SetTargetView(Current, tvForm1);

				InsTitledField(30,12, 8,1, '~F~orm',   New(PInputFName, init(Bounds, 8, 'FRM', FormsPath,True,EditTextFile)));
				PrintAsLinker^.SetTargetView(Current, 2);{}
				DeviceFormLinker^.SetTargetView(Current, tvForm2);

				InsTitledField(20,14, 1,1, 'Mark History', New(PInputBoolean, init(Bounds)));
				PrintAsLinker^.SetTargetView(Current, 3);
				Current^.SetState(SfDisabled, True);

				InsTitledField(20,15,18,1, 'Sort B~y~',	New(PInputFormCodeLine, init(Bounds,30)));

				InsOKButton(Size.X-21, Size.Y-3, @PrintOptions);
{				Insert(New(POurBUtton, init(Size.X-21,Size.Y-3, 'O~K~', cmOK, bfDefault+bfGetData+bfClose, @PrintOptions)));
				POurButton(Current)^.kbType := kbFinish;{}

				InsCancelButton(Size.X-11, Size.Y-3);

				EndInit;

				SetData(PrintOptions);{}

				CheckInitLinks(True);

				Control := Desktop^.ExecView(EditBox);

{				if (Control=cmOK) and not IsSortKey then Control := cmPrint; {print immediate}

				dispose(EditBox, done);
			end; {with}
		end; {eaOutput}
	end; {case search}

	EnterCriteria := Control;

end;




{***********************************************************************
 ***                  SEARCH/FIND/ETC                                ***
 ***********************************************************************{}

procedure TDirectoryReport.PostSearch;
begin
	DoDone := False; if NumMatched=0 then DoDone := True; {so inherited does none-found message}

	inherited PostSearch(Command);
end;


{*******************************************************
 ***               SORTING                           ***
 *******************************************************}
function TDirectoryReport.IsSortKey;
begin IsSortKey := delspaceR(PrintOptions.SortKey)<>''; end;

function TDirectoryReport.GetItemKey;
begin
	WorkFormCodes^.Clear;
	PJimmy(Item)^.SetFormCodes(WorkFormCodes);

	GetItemKey := WorkFormCodes^.QDecodeStr(PrintOptions.Sortkey);
end;



{**********************************************************************
 ***                   OUTPUT ALL                                   ***
 **********************************************************************{}
procedure TDirectoryReport.PreOutput;

	procedure SetOutputDevice;
	begin
		OutputDevice := SetDeviceFrom(PrintOptions.Editor, PrintOptions.Target, PrintOptions.DeviceName);

		{$IFDEF kwplink}
		{-- set wordperfect to batch all output ---}
		if OutputDevice = pointer(WPStream) then begin
			OutputDevice^.AutoSend := False; {so it all gets batched up}
			PWPStream(OutputDevice)^.KeepOpen := True;  {so all printing gets done at end only}
		end;
		{$ENDIF}
	end;


begin
	if PrintOptions.List then begin
		{does output while searching - clear special index}
		FileAdmin(fiSpecialDirIdx)^.LogOn;

		{clear}
		Stream(fiSpecialDirIdx)^.Seek(0);
		Stream(fiSpecialDirIdx)^.Truncate;
	end;

	case PrintOptions.PrintAs of
		paLabel : begin
			if (PrintOptions.Editor<>edWP51) and (PRintOptions.Target=ptPrint) then
				{labels - need formatting before printing}
				New(OutputDevice, init('Label',WorkPath + 'LABEL.NOW'))
			else
				SetOutputDevice;
			OutputDevice^.StartPrint('','');
		end;

		paSummary : begin
			{summary}
			SetOutputDevice;
			Header1 := PrintOptions.Header;
			Header2 := 'REPORT';
			inherited PreOutput;
		end;
		paFull,paMailshot : SetOutputDevice;
	else
		OutputDevice := nil;
	end;
end;

procedure TDirectoryReport.PostOutput;
begin
	if (ProBox^.Command=cmCancel) or (NumMatched=0) then
		OutputDevice^.AutoSend := False; {mostly for WP/fax stream}

	if PrintOptions.List then begin
		{--- Create List "Output" ---}
		FileAdmin(fiSpecialDirIdx)^.LogOff;
		if (NumMatched>0) and (ProBox^.Command <>cmCancel) then begin
			RunTask(DesktopTasks, cmStartSpecialDirList);
			OnceOnly := True; {don't go round again}
		end;
	end;

	{$IFDEF kwplink}
	{Need to turn off keepopen for the summaries, etc, below}
	if (PrintOptions.Editor = edWP51) and PWPStream(OutputDevice)^.KeepOpen then
		PWPStream(OutputDevice)^.KeepOpen := False;
	{$ENDIF}

	case PrintOptions.PrintAs of
		paLabel : begin
			if (PrintOptions.Editor<>edWP51) and (PRintOptions.Target=ptPrint) then begin
				{labels}
				OutputDevice^.EndPrint;
				Dispose(OutputDevice, done);
				OutputDevice := nil;
				if ProBox^.Command<>cmCancel then PrintLabels(WorkPath+'LABEL.NOW');  {See labels}
			end;
		end;
		paSummary : begin
			inherited PostOutput;
		end;
	end;

	{$IFDEF kwplink}
	if (PrintOptions.Editor = edWP51) and (PrintOptions.Target<>ptView) then begin
		if OutputDevice^.IsOpen then OutputDevice^.Close; {eg after mailshot}

		{autosend is switched off so that we only do one print, when everything is done}
		if (NumMatched>0) and (ProBox^.Command<>cmCancel) and (not PWPStream(OutputDevice)^.AutoSend) then
			PWPStream(OutputDevice)^.Send;
	end;
	{$ENDIF}

	if (PrintOptions.Target = ptView) and (ProBox^.Command<>cmCancel) and (NumMatched>0) then begin
		if OutputDevice^.IsOpen then OutputDevice^.Close;
		{$IFDEF kwplink}
		if PrintOptions.Editor = edWP51 then
			CallWP(OutputDevice^.DosFileName,'')
		else
		{$ENDIF}
			EditTextFile(OutputDevice^.DosFileName, '');
	end;

	if (OutputDevice<>nil) and (not OutputDevice^.Permanant) then
		dispose(OutputDevice, done);

end;

{***********************************************************************
 ***                   OUTPUT ITEM                                   ***
 ***********************************************************************{}
{Creates new index file}

procedure TDirectoryReport.OutputItem;
var DirectoryItem : PDirectoryItem;
		IndexItem : PIndexItem;

		PrintType : TJimmyPrintType;
		PrintAs : PSItem;
		PrintAsLink : pointer;
		PrevLetter, Letter : PLetter;

begin
	if PrintOptions.Tag then begin
		{=== TAG ITEM ===============}
		PDirectoryItem(Item)^.Tag := True;
		PutJimmy(PDirectoryItem(Item));
	end;

	if PrintOptions.List then begin
		{=== COPY TO LIST ========}
		DirectoryItem := PDirectoryItem(Item); {shorthand}

		{create indexitem}
		New(IndexItem, init);
		IndexItem^.Idx2Dat := DirectoryItem^.RecNo;
		IndexItem^.ixType := 99;  {mark as zero - o/w thinks it's the main list}
		IndexItem^.KeyString := DirectoryItem^.GetIndexKey(1);

		{store - will be in alphabetical order}
		Stream(fiSpecialDirIdx)^.PutAt(Stream(fiSpecialDirIdx)^.NoRecs, IndexItem);

		dispose(IndexItem, done);
	end;

	case PrintOptions.PrintAs of
		paLabel : begin

			{label}
			if PrintOptions.Form='' then
				PJimmy(Item)^.PrintLabel(OutputDevice,0)
			else
				PJimmy(Item)^.PrintForm(OutputDevice, PrintOptions.Form+'.FRM');

			OutputDevice^.writeln(#12); {end of label marker}
		end;
		paFull : begin
			if (delspaceR(PrintOptions.Header)='') and (delspaceR(PrintOptions.Form)='') then begin
				PJimmy(Item)^.GetDefaultPrintType(PrintType, PrintAs, PrintAsLink);
				PJimmy(Item)^.PrintFull(OutputDevice, PrintType.PrintAs);
			end else begin
				PJimmy(Item)^.SetFormCodes(OutputDevice^.FormCodes);
				OutputDevice^.StartPrint(PrintOptions.Form, '');
				PJimmy(Item)^.PrintForm(OutputDevice, PrintOptions.Form+'.FRM');
				OutputDevice^.EndPrint;
			end;
		end;
		paSummary : begin
			if delspaceR(PrintOptions.Form)='' then begin
				PJimmy(Item)^.GetDefaultPrintType(PrintType, PrintAs, PrintAsLink);
				PJimmy(Item)^.PrintSummary(OutputDevice, PrintType.PrintAs);
			end else
				PJimmy(Item)^.PrintForm(OutputDevice, PrintOptions.Form+'.FRM');
		end;
		paMailshot : begin
			{====== STANDARD LETTER =========}
			New(Letter, init(nil));

			with Letter^ do begin
				if PJimmy(Item)^.srType=srCompany then begin
					ToCoy := PJimmy(Item)^.REcNo;
					ToAdd := PDirectoryItem(Item)^.AddressID;
				end else begin
					ToWho := PJimmy(Item)^.REcNo;
					ToAdd := PDirectoryItem(Item)^.AddressID;
					if PJimmy(Item)^.srType=srPerson then begin
						ToCoy := PPerson(Item)^.ContactFor;
{done auto now in tperson.load						if (ToAdd = -1) and (ToCoy<>-1) then begin
							Company := PDirectoryItem(GetJimmy(ToCoy));
							ToAdd := Company^.AddressID;
							dispose(Company, done);
						end;{}
					end;
				end;

				EditorType := PrintOptions.Editor;

				Header 	:= PrintOptions.Header; {ought to have an option for this}
				StdForm := PrintOptions.Form;

				Codes := 'MS'; {mailshot}

				GetDefaultPrintType(PrintType, PrintAs, PrintAsLink);

				{don't do this if we're doing a "print while searching",numatched = itemno}
				{$IFDEF kwplink}
				if Stage <> rsSearching then
					if (PrintOptions.Editor = edWP51) and (PWPStream(OutputDevice)^.KeepOpen) and (ItemNo=(NumMatched-1)) then
						PWPStream(OutputDevice)^.KeepOpen := False; {so it closes the stream & doesn't do a ff onthe last page}
				{$ENDIF}

				PrintFull(OutputDevice, PrintType.PrintAs);

				if PrintOptions.MarkHistory then begin
					{check to see if already in list - eg in case of reprint due to error}
					FileAdmin(fiHooks)^.LogOn;
					PrevLetter := PLetter(HookFile^.GetFirst(PDirectoryItem(Item)^.Ptr2History, srLetter));
					FileAdmin(fiHooks)^.LogOff;
					if (PrevLetter=nil) or ((PrevLetter^.Date.Days<>Today.Days) or (PrevLetter^.StdForm<>Letter^.StdForm)) then begin
						OnPrinting(PrintType); {set sent date/status, etc}
						StoreSelf;{}
					end;
					if PrevLetter<>nil then dispose(PrevLetter, done);
				end;

							{as we're batching the letters up, need to put a page-break at the end}
{				if PrintOptions.Editor = edWP51 then if ItemNo<(NumMatched-1) then with OutputDevice^ do begin
					Open;
					FeedPage;
					Close;
				end;{}

				dispose(Letter, done);
			end; {with letter}

		end; {paMailshot}
	end; {case}

end;


{***************************************************************
 ***                                                          **
 ***                SEARCH DIRECTORY                          **
 ***                                                          **
 ***************************************************************}

constructor TDirectorySearch.Init;
begin
	inherited Init(NTitle, NDescMsg, NBasefiType, NStart, NEnd, NSearch, NPrint);

	if SearchOptions = nil then begin
		SearchOptions := New(PDirectorySearchOptions);

		with PDirectorySearchOptions(SearchOptions)^ do begin
			TaggedOnly := False;
			FullDirectory := False;

			Name 		:= '';
			Address := '';
			Tel 		:= '';
			CatCodes := '';
			QNoteCode := '';
			LetterCode := '';

			DoReg.Start.Clear;
			DoReg.Finish.Clear;
			Date.Start.Clear;
			Date.Finish.Clear;
		end;
	end;
end;

function TDirectorySearch.EnterCriteria;
var EditBox : PEditBox;
		Bounds,R : TRect;

begin
	EditBox := nil;
	EnterCriteria := cmOK;

	case eaType of
		{=================== SEARCH ==================================}
		eaSearch : begin
			Bounds.Assign(0,0,50,18);
			New(EditBox, init(Bounds,ucase(Title)+' SEARCH',Desktop));

			{Ask for search parameters, ie edit box}
			with EditBox^ do begin
				Options := Options or ofCentered;

				Insert(New(PSkipBytes, init(2))); {taggedonly/fulldirectory}

				InsTitledField( 12, 2, 20, 1, '~N~ame',  New(PInputELine, init(R, 20)));{}
				InsTitledField( 12, 3, 20, 1, 'Address', New(PInputELine, Init(R, 20)));
				InsTitledField( 12, 4, 20, 1, '~T~el', New(PInputELine, Init(R, 20)));{}
				Insert(New(PSkipBytes, init(2))); {for beginning of daterange}
				InsTitledField( 12, 6, 10, 1, 'DOReg', New(PInputDate, init(R)));
				InsTitledField( 26, 6, 10, 1, '-', New(PInputDate, init(R)));
				InsTitledField( 12, 9, 32, 1, 'C~a~t Codes',  New(PInputSCLine, Init(R, 7, scDirectoryCategory)));

				Insert(New(PSkipBytes, init(2))); {for beginning of daterange}
				InsTitledField( 12,11, 10, 1, '~E~vent Date', New(PInputDate, init(R)));
				InsTitledField( 26,11, 10, 1, '-', New(PInputDate, init(R)));

				InsTitledField( 12,12, 32, 1, '~Q~uickNote',  New(PInputSCode, Init(R, scEvents)));
				InsTitledField( 12,13, 32, 1, '~L~etter',  New(PInputSCode, Init(R, scEvents)));

				SetData(PDirectorySearchOptions(SearchOptions)^);{}

{				Insert(New(POurBUtton, init(Size.X-21,Size.Y-3, 'O~K~', cmOK, bfDefault+bfGetData+bfClose, @SearchOptions)));
				POurButton(Current)^.kbType := kbFinish;{}
				InsOKButton(Size.X-21, Size.Y-3, SearchOptions);
				InsCancelButton(Size.X-11, Size.Y-3);

				EndInit;

				EnterCriteria := Desktop^.ExecView(EditBox);

				dispose(EditBox, done);
			end; {with}
		end; {eaSearch}
	else {case}
		EnterCriteria := inherited EnterCriteria(eaType);
	end;
end;

{***********************************************************************
 ***                  SEARCH/FIND/ETC                                ***
 ***********************************************************************{}
procedure TDirectorySearch.PreSearch;
begin
	if PDirectorySearchOptions(SearchOptions)^.FullDirectory then
		BasefiType := fiFullDirIdx; {o/w use value passed in .init}

	inherited PreSearch(Command);
end;


procedure TDirectorySearch.SetSearchRange;
begin
	if PDirectorySearchOptions(SearchOptions)^.FullDirectory or ((StartRec=-1) and (EndRec=-1)) then
		inherited SetSearchRange; {sets to basefitype start/end, o/w use the values passed in .init}
end;


{*******************************************************
 ***               CHECK MATCH                       ***
 *******************************************************}
{* we have to be slightly careful here - with the old construct, ie:
for all tel numbers,
	if match,
		for all address lines,
			if match
				set ok.

we slow the procedure down considerably if no tel number restriction is
entered; because for each tel number we end up doing an address check...

similarly we do checks for nothing entered to save time}

function TDirectorySearch.MatchItem;
var Tel : word;
		M : boolean;
		S1,S2 : string;
		Hook : PHook;
		Letter : Pletter;
		HistoryNote : PHistoryNote;
		Add : PAddress; {don't get this confused with PDirectoryItem(Item)^.Address}
		Company : PDirectoryItem;
		TestItem : PDirectoryItem;
		Search : PDirectorySearchOptions;

begin
	M := inherited MatchItem(Item); {checks for alias}

	Search := PDirectorySearchOptions(SearchOptions); {shorthand}

	with PDirectoryItem(Item)^ do begin
{		TestItem := PDirectoryItem(item); {shortcut}

		if M then M := not Search^.TaggedOnly or {item.}Tag;

		{Check search codes}
		{split srchcode into both codes, if present}
		S2 := Search^.CatCodes;
		S1 := SplitByWord(S2); {split off first word}

		if (S1<>'') and
				(Pos(' '+S1+' ', ' '+{item.}GetCategories+' ')=0) then M := False;

		if (S2<>'') and
				(Pos(' '+S2+' ', ' '+{Item.}GetCategories+' ')=0) then M := False;

		{check date reg}
		if not Search^.DOReg.inRange({ITem.}DOREg) then M := False;

		{Check name}
		if (Search^.Name<>'') and (pos(ucase(Search^.Name), ' '+ucase({Item.}GetName(naFull,0))+' ')=0) then M := False;

		{check tel numbers}
		if Search^.Tel <> '' then begin
			M := False;
			for Tel := 1 to 4 do
				if ComparePartialStrings(Search^.Tel, {Item.}GetTelNum(Tel)) then M := True;
		end;

		{Check at least a match in the address}
		if (M = True) and (Search^.Address<>'') then begin {don't bother if false or nothing entered}
			{beware that the addresses get disposed of when the directoryitem they
			are associated with get disposed of - "Add" is a pointer not meant to
			be disposed of}
			{use directory items address, or contact for's if this one blank/nil}
			Add := GetAddress;
			Company := nil;

			if (Add=nil) or (Add^.Blank) then begin
				if (PDirectoryItem(Item)^.srType = srPerson) then
					Company := PDirectoryItem(GetJimmy(PPerson(Item)^.ContactFor));
				if (PDirectoryItem(Item)^.srType = srCompany) then
					Company := PDirectoryItem(GetJimmy(PCompany(Item)^.DeptFor));

				if Company<>nil then Add := Company^.GetAddress;
			end;

			if Add=nil then
				M := False
			else
				if Add^.Search(Search^.Address)=0 then M := False;

			if Company<>nil then dispose(Company, done);
		end;

		{Check history for event matching}
		if (M=True) and
				(not Search^.Date.Blank or (Search^.QNoteCode<>'') or (Search^.LetterCode<>'')) then begin

			M := False;
			FileAdmin(fiHooks)^.LogOn;

			if (Search^.QNoteCode='') and (Search^.LetterCode='') then begin

				{anything within date range will be fine, look at keys of hooks}
				Hook := HookFile^.GetFirstHook({Item}GetFirstHookPtr(hkHistory), 0);
				while (Hook<>nil) and (Hook^.GetKey<-Search^.Date.Start.Days) do begin
					M := (Hook^.GetKey>=-Search^.Date.Start.Days) and
								(Hook^.GetKey<=-Search^.Date.Finish.Days);
					dispose(Hook, done);
					if M then Hook := nil else Hook := HookFile^.GetHookFrom(True);
				end;
				if Hook<>nil then dispose(Hook, done);

			end else begin

				{search for specific type of quicknote}
				if Search^.QNoteCode<>'' then begin

					M := False;
					HistoryNote := PHistoryNote(HookFile^.GetFirst({Item.}GetFirstHookPtr(hkHistory), srHistoryNote));

					while (HistoryNote<>nil) and (HistoryNote^.Date.Days>Search^.Date.Start.Days) do begin

						M := Search^.Date.inRange(HistoryNote^.Date) and
							((Search^.QNoteCode='') or (delspace(Search^.QnoteCode)=delspace(HistoryNote^.Code)));

						dispose(HistoryNote, done);
						if M=False then HistoryNote := PHistoryNote(HookFile^.GetNextJimmy) else HistoryNote := nil;
					end;
					if HistoryNote<>nil then dispose(HistoryNote, done);
				end; {quick note}

				{search for specific type of letter}
				if Search^.LetterCode<>'' then begin

					M := False;
					Letter := PLetter(HookFile^.GetFirst({Item.}GetFirstHookPtr(hkHistory), srLetter));

					while (Letter<>nil) and (Letter^.Date.Days>Search^.Date.Start.Days) do begin

						M := Search^.Date.inRange(Letter^.Date) and
								(pos(' '+delspace(Search^.LetterCode)+' ', ' '+Letter^.Codes+' ')>0);

						dispose(Letter, done);
						if M=False then Letter := PLetter(HookFile^.GetNextJimmy) else Letter := nil;
					end;
					if Letter<>nil then dispose(Letter, done);
				end; {quick note}

			end; {not just date}

			FileAdmin(fiHooks)^.LogOff;
		end; {if something in histroy to search}


	end; {with item}

	MatchItem := M;
end;




const
	MakeListPrintOptions : TDIrectoryPrintOptions = (
		Tag 	: False;
		List 	: True;

		Editor 	: 0;
		Target  : ptPrint;
		DeviceName : '';
		PrintAs : paNothing;
		Header 	: '';
		Form   	: '';
		MarkHistory : False;
		SortKey : '');


procedure MakeSpecialList; far;
var Search : TDirectorySearch;
begin
	with Search do begin
		Init('DIRECTORY SEARCH','',fiFullDirIdx,-1,-1,nil,@MakeListPrintOptions);
		OnSearchOKDo := cmPrint;
		DoSearch;
		Done;
	end;
end;



procedure DoDirectorySearch; far;
var Search : TDirectorySearch;
begin
	Search.Init('DIRECTORY SEARCH','',fiFullDirIdx,-1,-1,nil,nil);
	Search.DoSearch;
	Search.Done;
end;

{*********************************************************
 ***                 INITIALISE                        ***
 *********************************************************}
begin
	RegisterTask(DesktopTasks, cmDirectoryReport, @DoDirectorySearch);
	RegisterTask(DesktopTasks, cmMakeSpecialDirList, @MakeSpecialList);
end.

