{****************************************************************************
 ***                                                                      ***
 *** New Fabbo Singing Dancing OOP                                        ***
 ***                      GENERAL EVENT                                   ***
 ***                                                                      ***
 *** M Hill                                                      Dec 1992 ***
 ****************************************************************************}
{$I compdirs}  {Compiler directives}

unit KDiary;

INTERFACE
uses	jimmys, {parent}
			menus,
			jimindxs,
			files,
			tuilist, inpdnt,
			drivers,
			global, views, objects, scodes, dattime, forms, tuiedit, notes, devices;

{**************************************************************
 ***                                                        ***
 ***               DEFINE EVENT OBJECT                      ***
 ***                                                        ***
 **************************************************************}
const
 TDiaryIndexSize = 40;

 {repeater types}
{ reNone = $00;{}
 reDaily = $00;
 reWeekly = $01;
 reFortnightly = $02;
 reMonthly = $03;
 reYearly = $04;

type

	PDiaryEvent = ^TDiaryEvent;
	TDiaryEvent = object(TJimmy)

		ForWho 		: longint;
		AtAdd			: longint; {where address id}
		ByWho 		: longint;

		Date      : TDate;
		Time      : TTime;
		Duration	: TTime;
		LeadTime	: TTime;

		What      : TScode;
		Notes			: PFreeTextData;{}

		Alarm			: boolean; {will go beep beep in diary at time minus leadtime}
		ToDo			: boolean; {marks as continuously renewed until outcome marked}
		Outcome   : string[12];

		Dat2Idx		: longint; {pointer to index}
		Dat2ToDoIdx : longint; {pointer to coy todo index}
		Dat2UserIdx : longint; {pointer to by's diary}
		Dat2UserToDoIdx : longint; {pointer to by's todo}

	 {-- Methods --}
	 constructor Init(Param : PJimmyInitParam);
	 procedure CommonInit; virtual;
	 destructor Done; virtual;

		function srtype : word; virtual;

		{Display/edit/print}
		function DisplayLine(ListForWho : longint; lstype : byte; Maxlen : integer; View : word) : string; virtual;
		function GetName(naType : byte; Maxlen : integer) : string; virtual; {used for various displays/prints -}
		procedure MakeEditBox(var EditBox : PEditBox; Caller : PView); virtual;

		procedure SetFormCodes(const FormCodes : PFormCodeCollection); virtual;
		procedure Print(prType : word; Device : PDevicestream); virtual;

		constructor Load(var S : TDataStream);
		procedure   StoreFields(var S : TDataSTream);              virtual;
		function RecSize : word; virtual;

		{Other Jimmy ID ptrs - for fixit, etc}
		function NumIDs : byte; virtual; {the number of jimmy ID ptrs in the data}
		function GetJimmyID(const jiType : byte) : PLongint; virtual; {each jimmy ID}

		{--- Indexing ----}
		function NumixTypes : byte; virtual;
		procedure GetIndex(const ixType : byte; var IdxRec : Plongint; var fiType : byte); virtual;
		function GetIndexKey(const ixType : byte) : string; virtual;

		{--- for diary, creating a new one for repeaters ---}
		procedure DoRepeater(const NewDate : TDate; const DeltaDays : integer); virtual;
		{-- Hooking to others -----}
{		function NumHookTo : byte;
		procedure GetHookTo(const htType : byte; var HookToID : PLongint; var hkType : byte; var Key : longint); virtual;{}
	end;

	{for regular, repeating events}
	PDiaryRepeater = ^TDiaryRepeater;
	TDiaryRepeater = object(TJimmy)

		StartDate : TDate;
		EndDate : TDate;

		Frequency : word; {see above - weekly, monthly, etc}

		JimmyID : longint; {pointer to jimmy to be repeated}

		Ptr2RptIdx : longint; {Pointer to repeater index}

	 {-- Methods --}
	 constructor Init(Param : PJimmyInitParam);

		{Display/edit/print}
		function DisplayLine(ListForWho : longint; lstype : byte; Maxlen : integer; View : word) : string; virtual;
		procedure MakeEditBox(var EditBox : PEditBox; Caller : PView); virtual;

		constructor Load(var S : TDataStream);
		procedure   StoreFields(var S : TDataSTream);              virtual;
		function RecSize : word; virtual;
		function srtype : word; virtual;

		{Other Jimmy ID ptrs - for fixit, etc}
		function NumIDs : byte; virtual; {the number of jimmy ID ptrs in the data}
		function GetJimmyID(const jiType : byte) : PLongint; virtual; {each jimmy ID}

		{diary/indexing}
		{--- Indexing ----}
		function NumixTypes : byte; virtual;
		procedure GetIndex(const ixType : byte; var IdxRec : Plongint; var fiType : byte); virtual;
		function GetIndexKey(const ixType : byte) : string; virtual;
	end;


	PDiaryView = ^TDiaryView;
	TDiaryView = object(TIndexedJimmyListView)

		PageDate : TDate;
		constructor Init(var Bounds: TRect; const NfiType : word; NPageDate : TDate; ForWho : longint);
		destructor Done; virtual;

		procedure CheckRepeaters;

		procedure SetRange; virtual;
		procedure HandleEvent(Var Event : Tevent); virtual;

		procedure DateChanged;
		procedure NotifyChangeOfDate; virtual;

		procedure PageUp; virtual;
		procedure PageDown; virtual;

		procedure PrintDay;
		procedure PrintWeek;
	end;

	PDiaryToDoView = ^TDiaryToDoView;
	TDiaryToDoView = object(TDiaryView)
		constructor Init(var Bounds: TRect; const NfiType : word; NPageDate : TDate; ForWho : longint);
		procedure SetRange; virtual;
	end;

type
	PDayDiary = ^TDayDiary;
	TDayDiary = object(TListWindow)
{		DiaryView : PDiaryView;{ List points to this}
		ToDoView : PDiaryToDoView;
		Calendar : PCalendarView;
		constructor Init(Bounds : TRect; ForWho : longint);
		procedure SizeLimits(var Min,Max: TPoint); virtual;
		{$IFDEF MSDOS} procedure Idle; virtual;{$ENDIF}
	end;


{===== AUTOMATIC ACTION =================}
{The date & time of the first Automatic Actions
are stored in memory, so that we can keep an eye
on it for alarms, etc, without continuously checking
the disk}
var
	{Auto-actions are basically repeaters, that get carried out
	when viewing the diary, and thus are dependant on the diary's
	view date, not the actual one}
	AutoActionTime : TTime;
	AutoActionDate : TDate;

	AlarmTime : TTime;
	AlarmDate : TDate;

	{DON'T USE INDEX POINTERS TO THE FIRST ITEM as I originally was going to
	do, as this will screw up if you do a hole-creator...}


IMPLEMENTATION

uses 	kdirctry, dialogs,
			printers,
			inpjimmy, inplist,
			tuimsgs,
			tuijimmy,
			lstrings,
			help,
			app, tuiapp, tasks, tui,
			indexes,
			{$IFDEF kusers} kusers, {$ENDIF}
			multcurr,
			jimhooks,
			minilib;


{***************************************************************
 **                                                           **
 **                 STD DIARY EVENT                           **
 **                                                           **
 ***************************************************************}

constructor TDiaryEvent.Init;
var DirItem : PJimmy;
begin
	inherited Init;
	Date.SetToToday;
	Time.Clear;
	Duration.Clear;
	LeadTime.Clear;

	ByWho := -1; {$IFDEF kusers} if CurrentUser<>nil then ByWho := CurrentUser^.RecNo; {$ENDIF}
	ForWho := -1;
	AtADd := -1;

	if Param <> nil then begin
		if Param^.ListView<>nil then begin
			if Param^.ListView^.lsType = lsDiary then begin
				Date.SetToDate(PDiaryView(Param^.ListView)^.PageDate);
				if PDiaryView(Param^.ListView)^.SubIndexString<>'' then
					ByWho := UnpakLint(PDiaryView(Param^.ListView)^.SubIndexString);
			end;
		end else begin
			ForWho := Param^.ForWho;
		end;
		if ForWho<>-1 then begin
			DirItem := GetJimmy(ForWho);
			AtAdd := PDirectoryItem(DirItem)^.AddressID;
			dispose(DirItem, done);
		end;
	end;
end;

procedure TDiaryEvent.CommonInit;
begin
	inherited CommonInit;
	New(Notes, init);{}
	SCodeCollection[scEvents]^.LogOn;
	SCodeCollection[scOutcomes]^.LogOn;
end;

destructor TDiaryEvent.Done;
begin
	SCodeCollection[scEvents]^.LogOff;
	SCodeCollection[scOutcomes]^.LogOff;
	Dispose(Notes, done);{}
	inherited Done;
end;


 {==== CREATE DISPLAY-LINE-FORMAT STRING ============}
function TDiaryEvent.DisplayLine;
var S,SS,Name : string;
	 Indent : byte;
	 I : integer;
	 B : boolean;
	 ForDir : PDirectoryItem;

begin
	{First line}
	if ForWho<>-1 then begin
		ForDir := PDirectoryItem(JimmyStream^.GetAt(ForWho));
		Name := ForDir^.GetName(naFull,0);
		if Outcome='' then Name := Name+' '+ForDir^.GetTelNum(1); {add tel number if outcome not specified - ie not yet done}
		dispose(ForDir, done);
	end else
		Name := '';

	if lsType = lsDiary then begin
		Indent := 6;
		S := SetLength(Time.Digit5,Indent); {just time required}
	end else begin
		Indent := 9;
		S := SetLength(Date.Digit8,Indent);
	end;

	{add code}
	SS := ucase(ExpandScode(scEVents, What));
	if (SS<>'') and (Name<>'') then
		S := S + SS + ' '+Name+CR+space(Indent)
	else
		if (SS<>'') or (Name<>'') then
			S := S + SS + Name + CR + space(Indent);

	if not Notes^.Loaded then Notes^.LoadText;
	LSReWidth(Notes^.Text, Maxlen-Indent-1);	 {rewidth to fit maxlen}
	for I := 1 to MinOf(2,LSNumLines(Notes^.Text)) do S := S+LSGetLine(Notes^.Text, I)+CRLF+Space(Indent);

	{Codes}
	SS := ExpandScode(scOutcomes, Outcome);    if SS<>'' then S := S+ SS+CR+space(Indent);

	if pos(CR,S)>0 then begin {more than one line, so remove last indent & CR}
		while S[length(S)]<>CR do S := Copy(S,1,length(S)-1); {remove indent}
		S := Copy(S,1,length(S)-1); {remove last CR}
	end;

	DisplayLine := S;
end;

function TDiaryEvent.GetName;
begin
	GetName := Date.Digit8+' '+ExpandScode(scEvents, What)+' '+GetJimmyIDName(ForWho, naRef, 0);
end;


procedure TDiaryEvent.DoRepeater;
begin
	inherited DoRepeater(NewDate, DeltaDays);
	Date.SetToDate(NewDate);
end;

{*****************************************
 ***        SCREEN INPUT BOX           ***
 *****************************************}
procedure LinkAddress(const Linker : PInputLinker; const CallingView : PView); far;
var	ForLine : PInputJimmy;
		AddLine : PInputHookedJimmy;
begin
	ForLine := PInputJimmy(CallingView);
	AddLine := PInputHookedJimmy(Linker^.TargetView[1]);

	{set address from whichever - person/coy}
	if ForLine^.GetJimmy<>nil then
		if PDirectoryItem(ForLine^.GetJimmy)^.AddressID<>-1 then begin
			AddLine^.SetData(PDirectoryItem(ForLine^.GetJimmy)^.AddressID);
			AddLine^.DrawView;
		end;

	AddLine^.SetParent(ForLine^.ID); {address line should give towho's addresses, not companies}
end;


procedure TDiaryEvent.MakeEditBox;
var	R: TRect;
		ForLine, ByLine,TypeLine,OutLine : PView;
		AddressLinker : PInputLinker;

begin
	if not Notes^.Loaded then Notes^.LoadText;{}

	R.Assign(0, 0, 43, 19);
	CentreOnView(R, Caller);
	EditBox := New(PJimmyEditBox, Init(R, 'Diary Event',Caller, @Self));

	inherited MakeEditBox(EditBox, Caller);

	New(AddressLinker, init(@LinkAddress, EditBox));
	AddressLinker^.ForceInitLink := True;{}

	with EditBox^ do begin
		InsTitledField(9,  1,30, 1, '~F~or',  New(PInputDirectory, init(R, 30, fiFullDirIdx, lsDirectory,'')));
		AddressLinker^.SetSourceView(Current, 1);
{		PInputELine(Current)^.MustInputToClose := True;{}
		ForLine := Current;

		InsTitledField(9,  2,30, 1,'~A~ddress',New(PInputHookedJimmy, init(R, 30, hkAddress, lsAddresses, 0, -1)));
		PINputJimmy(Current)^.ListOptions := PInputJimmy(Current)^.ListOptions and not loAutoList;
		AddressLinker^.SetTargetView(Current, 1);{}

		InsTitledField(9,  3,30, 1, '~B~y',  New(PInputDirectory, init(R, 30, fiCatDirIdx, lsDirectory, 'STA')));
		ByLine := Current;

		InsTitledField(9,  5,10, 1, '~D~ate', New(PinputDate, Init(R)));
		InsTitledField(9,  6, 5, 1, 'Time', New(PinputTime, Init(R,itHM)));

		InsTitledField(32, 5, 5, 1, 'Duration', New(PinputTime, Init(R,itHM)));
		InsTitledField(32, 6, 5, 1, 'Lead Time', New(PinputTime, Init(R,itHM)));

		InsTitledField(9,  8,30, 1, 'T~y~pe',New(PinputSCode, Init(R, scEvents)));{}
		TypeLine := Current;
		InsTitledField(9,  9,30, 4, '~N~otes', New(PInputFreeText, Init(R, 500, 28, nil)));{}

		InsTitledField(9, 14, 1, 1, '~A~larm', New(PinputBoolean, init(R)));
		InsTitledField(9, 15, 1, 1, '~T~odo', New(PinputBoolean, init(R)));
		InsTitledField(21,14,18, 1, 'O~u~tcome', New(PinputSCLine, Init(R, 12, scOutcomes)));
		OutLine := Current;

		{-- Buttons --}
		Insert(New(PJimmyOKButton, Init(20,Size.Y-3, @Self)));
		InsCancelButton(31,Size.Y-3);

		EndInit;

		{try and automatically pick out which line would be best to focus on}
		if ForWho = -1 then
			ForLine^.Focus
		else
			if ByWho = -1 then
				ByLine^.Focus
			else
				if What = '' then
					TypeLine^.Focus
				else
					OutLine^.Focus;

	end;
end;


{*****************************************
 ***     STREAMING DEFINITIONS         ***
 *****************************************}

const
	{--- Required for Stream ----}
	RDiaryEvent : TStreamRec = (
		ObjType : srDiaryEvent;
		VmtLink : Ofs(TypeOf(TDiaryEvent)^);
		Load : @TDiaryEvent.Load;
		Store : @TDiaryEvent.Store
	);


function TDiaryEvent.RecSize;
begin RecSize := 80; end;

function TDiaryEvent.srType;
begin
	srtype := srDIaryEvent;
end;


constructor TDiaryEvent.Load(var S : TDataStream);
var B : byte;
		Ver : byte;
		Rpt : word;
		L : longint;
		OldTime : record Hr,Min : byte; end;

begin
	S.Read(Ver, 1);

	case Ver of
		5 : begin
			{added more indexing (for personal diaries), where, and
			removed repeater}
			inherited Load(S);

			S.Read(ForWho, 4);
			S.Read(AtAdd, 4);
			S.Read(ByWho, 4);
			Date.Load(S);
			Time.Load(S);
			Duration.Load(S);
			LeadTime.Load(S);
			S.Read(What, sizeof(What));
			Notes^.Load(S);{}
			S.Read(B, 1);
			if (B and $01)>0 then Alarm := True else Alarm := False;
			if (B and $02)>0 then Todo  := True else Todo := False;
			S.Read(Outcome, sizeof(Outcome));{}
		end;

		4 : begin
			CommonInit;

			S.Read(LockTerminal, 1);
			S.Read(Deleted, 1);
			S.Read(Dat2Idx, 4);
			S.Read(Dat2ToDoIdx, 4);
			S.Read(L, 4); {repeater pointer}
			Dat2UserTodoIdx := -1;
			Dat2UserIdx := -1;

			S.Read(ForWho, 4);
			S.Read(ByWho, 4);
			Date.Load(S);
			Time.Load(S);
			Duration.Load(S);
			LeadTime.Load(S);
			S.Read(What, sizeof(What));
			Notes^.Load(S);{}
			S.Read(B, 1);
			if (B and $01)>0 then Alarm := True else Alarm := False;
			if (B and $02)>0 then Todo  := True else Todo := False;
			S.Read(Outcome, sizeof(Outcome));{}
		end;
		3 : begin
			CommonInit;

			{-- added repeat ---}
			S.Read(LockTerminal, 1);
			S.Read(Dat2Idx, 4);
			S.Read(Dat2ToDoIdx, 4);
			S.Read(L, 4);
			Dat2UserTodoIdx := -1;
			Dat2UserIdx := -1;

			S.Read(ForWho, 4);
			S.Read(ByWho, 4);
			Date.Load(S);
			S.Read(OldTime,2); with Time do begin Hour := OldTime.Hr; Min := OldTime.Min; end;
			S.Read(OldTime,2); with Duration do begin Hour := OldTime.Hr; Min := OldTime.Min; end;
			S.Read(OldTime,2); with LeadTime do begin Hour := OldTime.Hr; Min := OldTime.Min; end;
			S.Read(What, sizeof(What));
			Notes^.Load(S);{}
			S.Read(B, 1);
			if (B and $01)>0 then Alarm := True else Alarm := False;
			if (B and $02)>0 then Todo  := True else Todo := False;
			S.Read(Outcome, sizeof(Outcome));{}
			S.Read(Rpt, 2);
		end;
		2 : begin
			CommonInit;

			S.Read(LockTerminal, 1);
			S.Read(Dat2Idx, 4);
			Dat2Todoidx := -1;
			Dat2UserTodoIdx := -1;
			Dat2UserIdx := -1;
			S.Read(ForWho, 4);
			S.Read(ByWho, 4);
			Date.Load(S);
			S.Read(OldTime,2); with Time do begin Hour := OldTime.Hr; Min := OldTime.Min; end;
			S.Read(OldTime,2); with Duration do begin Hour := OldTime.Hr; Min := OldTime.Min; end;
			S.Read(OldTime,2); with LeadTime do begin Hour := OldTime.Hr; Min := OldTime.Min; end;
			S.Read(What, sizeof(What));
			Notes^.Load(S);{}
			S.Read(B, 1);
			if (B and $01)>0 then Alarm := True else Alarm := False;
			if (B and $02)>0 then Todo  := True else Todo := False;
			S.Read(Outcome, sizeof(Outcome));{}
		end;
		1 : begin
			CommonInit;

			LockTerminal := 0;
			Dat2Idx := -1;
			Dat2Todoidx := -1;
			Dat2UserTodoIdx := -1;
			Dat2UserIdx := -1;
			S.Read(ForWho, 4);
			S.Read(ByWho, 4);
			Date.Load(S);
			S.Read(OldTime,2); with Time do begin Hour := OldTime.Hr; Min := OldTime.Min; end;
			S.Read(OldTime,2); with Duration do begin Hour := OldTime.Hr; Min := OldTime.Min; end;
			S.Read(OldTime,2); with LeadTime do begin Hour := OldTime.Hr; Min := OldTime.Min; end;
			S.Read(What, sizeof(What));
			Notes^.Load(S);{}
			S.Read(B, 1);
			if (B and $01)>0 then Alarm := True else Alarm := False;
			if (B and $02)>0 then Todo  := True else Todo := False;
			S.Read(Outcome, sizeof(Outcome));{}
		end;
	else
		ProgramError('Version '+N2Str(Ver)+' not understood'#13'TDiaryEvent.Load',hcInternalErrorMsg);
		fail;
	end;
end;

procedure TDiaryEvent.StoreFields(var S : TDataStream);
var	B : byte;
		Ver : byte;

begin
	Ver := 5; S.Write(Ver, 1);

	inherited StoreFields(S);

	S.Write(ForWho, 4);
	S.Write(AtAdd, 4);
	S.Write(ByWho, 4);
	Date.Store(S);
	Time.Store(S);
	Duration.Store(S);
	LeadTime.Store(S);
	S.Write(What, sizeof(What));
	Notes^.store(S);{}
	B := 0;
	if Alarm then B := B or $01;
	if Todo  then B := B or $02;
	S.WRite(B, 1);
	S.Write(Outcome, sizeof(Outcome));{}
end;

{============== POINTERS TO OTHER JIMMYS===================}
function TDiaryEvent.NumIDs;
begin NumIDs := 3; end;

function TDiaryEvent.GetJImmyID;
begin
	case jiType of
		1 : GetJimmyID := @ForWho;
		2 : GetJImmyID := @AtAdd;
		3 : GetJimmyID := @ByWho;
	else
		GetJimmyID := nil;
	end;
end;

{============ INDEXING ========================}
function TDiaryEvent.Numixtypes;
begin Numixtypes := 4; end;

procedure TDiaryEvent.GetIndex;
begin
	inherited getIndex(ixType, IdxRec, fiType);

	case ixType of
		1 : begin	IdxRec := @Dat2Idx;					fiType := fiDiaryIdx;	end;
		2 : begin IdxRec := @Dat2ToDoIdx;			fiType := fiDiaryToDoIdx;	end;
		3 : begin IdxRec := @Dat2UserIdx;			fiType := fiStaffDiaryIdx;	end;
		4 : begin	IdxRec := @Dat2UsertodoIdx;	fiType := fiStaffDiaryToDoIdx; end;
	end;
end;

function TDiaryEvent.GetIndexKey;
var Key : String;
begin
	GetIndexKey := '';
	case ixType of
		1 :	if not Todo or (not Time.blank) or (OutCome<>'') then GetIndexKey := Date.AsKey+Time.AsKey(itHM);
		2 :	if Todo and (Outcome='') 				then GetIndexKey := Date.AsKey+Time.AsKey(itHM);
		3,4 :
			if ByWho<>-1 then begin
				Key := GetIndexKey(ixType-2);
				if Key<>'' then GetIndexKey := PakLint(ByWho)+Key;
			end;
	end;
end;

{-- Hooking to others -----}
{procedure TDiaryEvent.NumHookTo;
begin NumHookTo := 1; end;

procedure TDiaryEvent.GetHookTo;
begin
	inherited GetHookTo(htType, HookToID, hkType, Key);
	if Date.Blank then Key := SortKeyStart   {Make sure appears at beginning}
{	else Key := -Date.Days;  {Reverse Sort on date}
{end;



{********************************************
 ***             SET FORM CODES           ***
 ********************************************}
procedure TDiaryEvent.SetFormCodes;
var S : string;
begin
	if not Notes^.Loaded then Notes^.LoadText;

	with FormCodes^ do begin
		SetStr('DT', Date.Digit10);
		{Changed date - see if date has changed from prev, if not.. hmmm.
		if GetCode('CDT') =                                              }
		S := ExpandSCode(scEvents, What) + #13#10 + LS2String(Notes^.Text);
		SetStr('TEXT', S);
	end;
end;


{********************************************
 ***             PRINT                    ***
 ********************************************}
procedure TDiaryEvent.Print;
var S : string;
		I : integer;
		ForDir : PDirectoryItem;

begin
	if not Notes^.Loaded then Notes^.LoadText;{}

	if (prType and pmScope) = prDaily then begin

		{======= PRINT FULL DETAILS FOR A DAILY APPT SHEET ================}
		{Check to see if *likely* to run over page, and do a new page if nec (so
		trying to keep in discrete lumps}
		Device^.CheckForNewPage(1 + LSNumLines(Notes^.Text)+2);{}

		{Get directory item's name & tel num}
		if ForWho<>-1 then begin
			ForDir := PDirectoryItem(JimmyStream^.GetAt(ForWho));
			S := ForDir^.GetName(naFull,0)+' '+ForDir^.GetTelNum(1);
			dispose(ForDir, done);
		end else
			S := '';

		{First line}
		Device^.Writeln(Time.Digit5+' '+ucase(ExpandScode(scEVents,What))+' '+S);

		{Notes}
		for I := 1 to LSNumLines(Notes^.Text) do Device^.Writeln(space(11)+LSGetLine(Notes^.Text, I));{}

		S := ExpandScode(scOutcomes, Outcome);{}
		if S<>'' then Device^.Writeln(space(11)+S);
	end;
end;


{***************************************************************
 **                                                           **
 **                 REPEATER DIARY EVENT                      **
 **                                                           **
 ***************************************************************}
constructor TDiaryRepeater.Init;
begin
	inherited Init;
	StartDate.SetToToday;
	EndDate.Clear;
	Ptr2RptIdx := -1;
	JimmyID := -1;

	{now see if we can locate the jimmy}
	if Param<>nil then begin
		{parameter given - created from list/desktop}
		JimmyID := Param^.FocusedID;
		if (Param^.ListVIew<>nil) and (Param^.ListView^.lsType=lsDiary) then
			StartDate.SetToDate(PDiaryView(Param^.ListView)^.PageDate);

		{do here, rather than even if param=nil, as jimmy index stream creates
		 jimmys to modify pointers}
		if JimmyID = -1 then begin
			ProgramWarning('Cannot create Repeater'#13'Nothing to repeat',hcAANoJimmy);
			fail;
		end;
	end;

end;

{==== CREATE DISPLAY-LINE-FORMAT STRING ============}
function TDiaryRepeater.DisplayLine;
const
	RptRate : PChar = 'DWFMY';
begin
	DisplayLine := StartDate.Digit8+' '+RptRate[Frequency]+' '+GetJimmyIDName(JimmyID, naFull, 0)

	{$IFDEF fixit} +#13+'   TEK: '+N2Str(Recno)+' Idx'+N2Str(Ptr2RptIdx)+' Jim:'+N2Str(JimmyID) {$ENDIF}

	;
end;


{*****************************************
 ***        SCREEN INPUT BOX           ***
 *****************************************}

procedure TDiaryRepeater.MakeEditBox;
var	R: TRect;

begin
	R.Assign(0, 0, 43, 12);
	CentreOnView(R, Caller);
	EditBox := New(PJimmyEditBox, Init(R, 'Diary Repeater',Caller, @Self));

	inherited MakeEditBox(EditBox, Caller);

	with EditBox^ do begin
		InsTitledField(9,  1,10, 1, '~D~ate', New(PinputDate, Init(R)));
		InsTitledField(9,  2,10, 1, 'To', New(PinputDate, init(R)));

		{Radio button box for frequency}
		R.Assign(9, 4, 23, 9);
		Insert(New(PERadioButtons, init(R, NewSItem('~D~aily',
																			NewSItem('~W~eekly',
																			NewSItem('~F~ortnightly',
																			NewSItem('~M~onthly',
																			NewSItem('~Y~early',
		nil))))))));

		{hmmm... access to jimmy}
		InsTitledField(9, 10, 20, 1, 'Do', New(PInputJimmy, init(R, 20, 0)));
{		Current^.SetState(sfDisabled, True);{}

		{-- Buttons --}
		Insert(New(PJimmyOKButton, Init(31,Size.Y-5, @Self)));
		InsCancelButton(31,Size.Y-3);

		EndInit;
	end;
end;


{*****************************************
 ***     STREAMING DEFINITIONS         ***
 *****************************************}

const
	{--- Required for Stream ----}
	RDiaryRepeater : TStreamRec = (
		ObjType : srDiaryRepeater;
		VmtLink : Ofs(TypeOf(TDiaryRepeater)^);
		Load : @TDiaryRepeater.Load;
		Store : @TDiaryRepeater.Store
	);

function TDiaryRepeater.srType;
begin	srtype := srDiaryRepeater; end;

function TDiaryRepeater.RecSize;
begin RecSize := 40; end;

constructor TDiaryRepeater.Load(var S : TDataStream);
var	Ver : byte;

begin
	S.Read(Ver, 1);

	case Ver of
		1 : begin
			inherited Load(S);

			StartDate.Load(S);
			EndDate.Load(S);

			S.Read(Frequency, 2);
			S.Read(JimmyID, 4);
		end;
	else
		ProgramError('Version '+N2Str(Ver)+' not understood'#13'TDiaryRepeater.Load',hcInternalErrorMsg);
		fail;
	end;
end;

procedure TDiaryRepeater.StoreFields(var S : TDataStream);
var	Ver : byte;

begin
	Ver := 1; S.Write(Ver, 1);

	inherited StoreFields(S);

	StartDate.Store(S);
	EndDate.Store(S);

	S.Write(Frequency, 2);
	S.Write(JimmyID, 4);
end;



{============== POINTERS TO OTHER JIMMYS===================}
function TDiaryRepeater.NumIDs;
begin NumIDs := 1; end;

function TDiaryRepeater.GetJImmyID;
begin
	case jiType of
		1 : GetJimmyID := @JimmyID;
	else
		GetJimmyID := nil;
	end;
end;


{============ INDEXING ========================}
{--- Indexing ----}
function TDiaryRepeater.NumixTypes : byte;
begin NumixTypes := 1; end;

procedure TDiaryRepeater.GetIndex;
begin
	inherited getIndex(ixType, IdxRec, fiType);

	case ixType of
		1 : begin IdxRec := @Ptr2RptIdx; fitype := fiDiaryActionIdx; end;
	end;
end;

function TDiaryRepeater.GetIndexKey;
begin
	GetIndexKey := '';
	case ixType of
		1 : GetIndexKey := StartDate.AsKey;
	end;
end;

{***************************************************************************
 ***                                                                     ***
 ***                   THE DIARY LIST                                    ***
 ***                                                                     ***
 ***************************************************************************}
{Sub index string, if passed, is the Longint as Key of the person the diary
is for.  Note that subindexstring is also used for setting range for daily/
weekly views.}

constructor TDiaryView.Init;
var S : string;
begin
	if ForWho = -1 then S := '' else S := PakLint(ForWho);
	inherited Init(Bounds, lsDiary, NfiType, S);
	PageDate.SetToDate(NPageDate);
	DoneNew := True; {don't do auto-new in diary - may be lots of blank p
	ages to page through}
	FileAdmin(fiDiaryActionIdx)^.LogOn;
	CheckRepeaters;
end;

destructor TDiaryView.Done;
begin
	FIleAdmin(fiDiaryActionIdx)^.LogOff;
	inherited Done;
end;

procedure TDiaryView.SetRange;
var S : string;
begin
	S := SubIndexString; {store}
	SubIndexString := SubIndexString + PageDate.AsKey; {just today}
	inherited SetRange;
	SubIndexString := S;
end;

procedure TDiaryView.handleEvent;
begin
	if (Event.What = evBroadCast) and (Event.Command = cmDateChanged) {and
		(PDate(Event.InfoPtr)^.Days<>PageDate.Days){} then begin
			{date changed in peer views}
			PageDate.SetToDate(PDate(Event.InfoPtr)^);
			DateChanged;
			CheckRepeaters;
	 end;

	if Event.What = evCommand then
		case Event.Command of
			cmPrint 		: begin PrintDay; ClearEvent(Event); end;
			cmPrintList : begin PrintWeek; ClearEvent(Event); end;
		end;

	if (Event.What <> evKeyDown) or
		(pos(Event.CharCode, 'tTwWmMyY+-')=0) then {if any of these, leave for calendar to deal with}
		inherited HandleEvent(Event);


	{in order to keep keypresses consistent, we'll make sure that
	even if up/down have not been trapped, we discard them here so that
	we don't end up with up/down working if the list is empty and not
	working if it has something in it}
	if (Event.What = evKeyDown) then
		case Event.KeyCode of
			kbUp, kbDown : ClearEvent(Event);
		end;
end;


{**********************************************************
 ***                DATE MODIFICATION                   ***
 **********************************************************}
procedure TDiaryView.NotifyChangeOfDate; {call when current date is changed}
begin
	{tells other diary linked views to update to the new date}
	MEssage(Owner, evBroadcast, cmDateChanged, @PageDate);
end;

procedure TDiaryView.DateCHanged;
begin
	SetRange;
	FOcusItem(FirstItem);
	REdraw;
end;

procedure TDiaryView.PageUp;
begin
	PageDate.AddDay(False);
	DateChanged;
	NotifyChangeOfDate;
end;

procedure TDiaryView.PageDown;
begin
	PageDate.AddDay(True);
	CheckRepeaters;
	DateChanged;
	NotifyChangeOfDate;
end;

{checks repeater index to make sure all up to current date}
procedure TDiaryView.CheckRepeaters;
var RptIdxREc,UpToRec,HoleRec,ID : longint;
		IndexItem : PIndexItem;
		I : integer;
		B : byte;
		Date : TDate;
		Repeater : PDiaryRepeater;
		Jimmy : PJimmy;

begin
	if not AutoActionDate.Blank and (PageDate.Days<AutoActionDate.Days) then exit; {no need yet}

	Date.SetToDate(PageDate);
	Date.AddDay(True); {goes to the one at the beginning of next day, ie captures *all* for this day}
	I := IndexStream(fiDiaryActionIdx)^.FindFirst(Date.AsKey, UpToRec, HoleREc, ID);
	if (I>-1) or (UpToRec>-1) then begin

{		AutoActionDate.Clear;{}

		for RptIdxRec := 0 to UpToRec-1 do begin
			IndexItem := PIndexItem(INdexStream(fiDiaryActionIdx)^.GetAt(RptIdxRec));

			if (not IndexItem^.Hole) then begin
				{Ok, insert data item into real diary & update startdate}
				Repeater := PDiaryRepeater(GetJimmy(IndexItem^.Idx2Dat));
				if Repeater<>nil then begin
					Jimmy := GetJimmy(Repeater^.JimmyID);
					if Jimmy<>nil then begin

						while Repeater^.StartDate.Days<=PageDate.Days do begin
							{next date}
							Date.SetToDate(Repeater^.StartDate);
							case Repeater^.Frequency of
								0 : Date.AddDay(True); {daily}
								1 : Date.AddWeek(True); {weekly}
								2 : begin Date.AddWeek(True); DAte.AddWeek(True); end; {fortnightly}
								3 : Date.AddMonth(True); {monthly}
								4 : Date.AddYear(True); {annual}
							end;

							{update repeater}
							if (Date.Days>Repeater^.EndDate.Days) and not Repeater^.EndDate.Blank then
								Repeater^.Deleted := True {finished}
							else
								Repeater^.StartDate.SetToDate(Date);
							Repeater^.StoreSelf;

							{update jimmy}
							Jimmy^.DoRepeater(Date,0);
							Jimmy^.StoreSelf;{}
						end;
						dispose(Jimmy, done);
					end;
					dispose(repeater, done);
					{set autoaction date}
{					if AutoActionDate.Blank or (AutoActionDate.Days<Date.Days) then
						AutoActionDate.SetToDate(Date);{}
				end;

			end;
			dispose(IndexItem, done);
		end; {for}
	end; {if something found}

	{look for first non-hole in repeater file to get next auto-action date}
	RptIdxRec := 0; AutoActionDate.Clear;
	while (RptIdxRec<Stream(fiDiaryActionIdx)^.NoRecs) and AutoActionDate.Blank do begin
		IndexItem := PIndexItem(INdexStream(fiDiaryActionIdx)^.GetAt(RptIdxRec));
		if not IndexItem^.Hole then AutoActionDate.SetToKey(IndexItem^.KeyString);
		dispose(IndexItem, done);
		inc(RptIdxrec);
	end;
end;

procedure TDiaryView.PrintDay;
var RecNo, HoleRec, ID : longint;
		IndexItem : PIndexItem;
		Jimmy : PJimmy;

begin
	Printer^.FormCodes^.SetDate('DT', PageDate);
	Printer^.StartPrint('DIARYDAY','REPORT');

	{Run through from firstitem to lastitem}
	RecNo := FirstItem;
	while RecNo<=LastItem do begin
		IndexItem := PIndexItem(IndexStream(fitype)^.GetAt(RecNo));
		if not IndexItem^.Hole then begin
			Jimmy := GetJimmy(IndexItem^.Idx2Dat);
			Jimmy^.SetFormCodes(Printer^.FormCodes);
			Jimmy^.PrintLine(Printer);
			dispose(Jimmy, done);
		end;
		inc(RecNo);
		dispose(IndexItem, done);
	end;

{	Printer^.writeln('Todo:');

	FileAdmin(fiDiaryTodoIdx)^.LogOn;

	{Then do todo list}
{	RecNo := 0; {Start at beginning and go on until dates beyond today}
{  IndexItem := PIndexItem(Stream(fiDiaryTodoIdx)^.GetAt(RecNo));
	while (RecNo<=PIndexStream(Stream(fiDiaryTodoIdx))^.NoRecs-1) and (IndexItem<>nil)
							and (S2Num(Copy(IndexItem^.KeyString,1,5))<=Today.Days) do begin
		if not IndexItem^.Hole then begin
			DiaryRepeater := PDiaryEvent(JimmyStream^.getAt(IndexItem^.Idx2Dat));
			DiaryEvent^.Print(prDaily, @Printer^);
			dispose(DiaryEvent, done);
		end;
		inc(RecNo);
		IndexItem := PIndexItem(PIndexStream(Stream(fiDiaryTodoIdx))^.GetAt(RecNo));
	end;

	FileAdmin(fiDiaryTodoIdx)^.LogOff;{}

	Printer^.EndPrint;

end;

procedure TDiaryView.PrintWeek;
var RecNo, HoleRec, ID : longint;
		IndexItem : PIndexItem;
		Jimmy : PJimmy;

begin
	Printer^.FormCodes^.SetDate('DT', PageDate);
	Printer^.StartPrint('DIARYWK','REPORT');

	{Run through from firstitem to lastitem}
{	RecNo := FirstItem;
	while (RecNo<=IndexStream(fiType)^.NoRecs) and (Key<do begin
		IndexItem := PIndexItem(IndexStream(fitype)^.GetAt(RecNo));
		if not IndexItem^.Hole then begin
			Jimmy := GetJimmy(IndexItem^.Idx2Dat);
			Jimmy^.SetFormCodes(Printer^.FormCodes);
			Jimmy^.PrintLine(Printer);
			dispose(Jimmy, done);
		end;
		inc(RecNo);
		dispose(IndexItem, done);
	end;{}

end;

{***************************************************************************
 ***                                                                     ***
 ***                   THE TO-DO DIARY LIST                              ***
 ***                                                                     ***
 ***************************************************************************}
constructor TDiaryToDoView.Init;
begin
	inherited Init(Bounds, NfiType, NPageDate, ForWho);
	lsType := lsDiaryTodo;
end;


procedure TDiaryToDoView.SetRange;
var HoleRec, ID : longint;
begin
	if PageDate.Days<=Today.Days then begin
		{if today or before, list all to-do since dot to the date}
		if SubIndexString = '' then FirstItem := 0
		else IndexStream(fiType)^.FindFirst(SubIndexString, FirstItem, HoleRec, ID);
		IndexStream(fiType)^.FindFirst(SubIndexString+PageDate.AsKey+#255, LastItem, HoleRec, ID);
		GetPrevItemNo(LastItem);
		FindOKItemNo(FirstItem); {skip holes, etc}
		TListView.SetRange; {updates scroll bar}
	end else
		inherited SetRange;
end;


{***************************************************************************
 ***                   DATE INDICATOR                                    ***
 ***************************************************************************}
type
	PDateIndicator = ^TDateIndicator;
	TDateIndicator = object(TView)
		Date : TDate;
		constructor Init(Bounds : TRect);
		procedure Draw; virtual;
		procedure HandleEvent(var Event : TEvent); virtual;
	end;

constructor TDateIndicator.Init;
begin
	inherited Init(Bounds);
	Date.SetToToday;
	EventMask := EventMask or evBroadCast;
end;

procedure TDateIndicator.HandleEvent;
begin
	inherited HandleEvent(Event);

	if (Event.What = evBroadCast) and (Event.Command = cmDateChanged){ and
		(PDate(Event.InfoPtr)^.Days<>Date.Days){} then begin
			{date changed in peer views}
			Date.SetToDate(PDate(Event.InfoPtr)^);
			DrawView;
	end;
end;

procedure TDateIndicator.Draw;
var S : string;
begin
	with Date do
		S := 'D'+N2Str(DayOfYear)
					+'/W'+N2Str(WeekOfYear)
					+ ' '+Copy(DoWeekName[DayOfWeek],1,3) {first three chars of day}
					+ ' '+AddOrdinator(Day) {plus 15th, etc}
					+ ' '+Copy(MonthName[Month],1,3)+' '; {first three chars of month}

	WriteStr(0,0,SetLength(S,Size.X),1);
end;



{***************************************************************************
 ***                                                                     ***
 ***                   THE FULL DIARY WINDOW                             ***
 ***                                                                     ***
 ***************************************************************************}

constructor TDayDiary.Init;
var
		DateIndicator : PDateIndicator;
		Lab : PLabel;
		NfiType : word;
		X : integer;
		S : string;

begin
	NfiType := fiDiaryIdx;
	if ForWho<>-1 then begin
		NfiType := fiStaffDiaryIdx;
		S := ' - '+ucase(GetJimmyIDName(ForWho, naDIsplay, 0));
	end else
		S := '';

	inherited Init(Bounds, 'DIARY'+S, New(PDiaryView, init(Bounds, Nfitype, Today, ForWho)));

	{locate main diary to top of view, leaving space for calendar & todo}
	Bounds.Assign(1,2, Size.X-1, Size.Y - 10);
	List^.Locate(Bounds);

	{---------------- to do view -------------------}
	NfiType := fiDiaryTodoIdx; if ForWho<>-1 then NfiType := fiStaffDiaryTodoIdx;
	Bounds.Assign(1, Size.Y-9, Size.X-22, Size.Y-1);
	New(ToDoView, init(Bounds, Nfitype, Today,ForWho));
	ToDoView^.Options := ToDoView^.Options or ofFramed;

	{Y top/bottom fixed to owner's bottom, X left with owner's left,
	X right with owner's right}
	ToDoView^.GrowMode := gfGrowLoY+gfGrowHiX+gfGrowHiY;

	Insert(ToDoView);
	Insert(ToDoView^.VScrollBar); {insert todo's scrollbar}

	{to do label}
	X := (Size.X-22) div 2;;
	Bounds.Assign(X - 3, Size.Y-10, X +2, Size.Y-9);
	Lab := New(PLabel, init(Bounds, 'TO DO', ToDoView));
	{Y top/bottom fixed to owner's bottom, X left/right with owner's left}
	Lab^.GrowMode := gfGrowLoY + gfGrowHiY;
	Insert(Lab);

	{calendar}
	Bounds.Assign(SIze.X-21, Size.Y-9, Size.X-1, Size.Y-1);
	New(Calendar, init(Bounds));
	{not selectable - so useful views, ie todo/diary list stay focused,
	but allow postprocess and usual broadcast eventmask to pick up mouse
	and t/T/+/- etc keypresses}
	Calendar^.Options := (Calendar^.Options or ofFramed or ofPostProcess) and not ofSelectable;
	Calendar^.GrowMode := gfGrowAll; {moves with bottom right}


	Insert(Calendar);

	{date indicator}
	Bounds.Assign(Size.X-21, 1, Size.X-1, 2);
	New(DateIndicator, init(Bounds));
	DateIndicator^.GrowMode := gfGrowLoX + gfGrowHiX;{}
	Insert(DateIndicator);

	List^.Focus; {focus on main list}
end;


procedure TDayDiary.SizeLimits;
begin
	inherited SizeLimits(Min, Max);
	Min.X := 27;
	Min.Y := 13;
end;

{$IFDEF MSDOS}
procedure TDayDiary.Idle;
begin
	List^.Idle;
{  Calendar^.Idle;{}
	ToDoView^.Idle;
end;
{$ENDIF}

{***************************************************************************
 ***                                                                     ***
 ***                   WEEKLY DIARY VIEW                                 ***
 ***                                                                     ***
 ***************************************************************************}
type
	PWeekDiary = ^TWeekDiary;
	TWeekDiary = object(TListWindow)
		DayView : array[1..7] of PDiaryView; {list points to current one}
		ToDoView : PDiaryToDoView;
		Calendar : PCalendarView;
		constructor Init(Bounds : TRect; ForWho : longint);
		procedure SizeLimits(var Min,Max: TPoint); virtual;
		{$IFDEF MSDOS} procedure Idle; virtual;{$ENDIF}
	end;

constructor TWeekDiary.Init;
var	DateIndicator : PDateIndicator;
		Lab : PLabel;
		NfiType : word;
		Date : TDate;
		X : integer;
		S : string;

begin
	NfiType := fiDiaryIdx;
	if ForWho<>-1 then begin
		NfiType := fiStaffDiaryIdx;
		S := ' - '+ucase(GetJimmyIDName(ForWho, naDIsplay, 0));
	end else
		S := '';

	inherited Init(Bounds, 'DIARY'+S, nil);

	{--- Days ----------------------------}
	Date.SetToToday;
	Bounds.Assign(1,3, Size.X div 2, 5);

	for X := 1 to 7 do begin
		New(DayView[X], init(Bounds, NfiType, Date, ForWho));
		Insert(DayView[X]);
		{label each view with day name?}
		Bounds.Move(0,4);
		if X=4 then Bounds.Move(Size.X div 2 + 2, -16);
		Date.AddDay(True);
	end;


	{---------------- to do view -------------------}
	NfiType := fiDiaryTodoIdx; if ForWho<>-1 then NfiType := fiStaffDiaryTodoIdx;
	Bounds.Assign(1, Size.Y-9, Size.X-22, Size.Y-1);
	New(ToDoView, init(Bounds, Nfitype, Today,ForWho));
	ToDoView^.Options := ToDoView^.Options or ofFramed;

	{Y top/bottom fixed to owner's bottom, X left with owner's left,
	X right with owner's right}
	ToDoView^.GrowMode := gfGrowLoY+gfGrowHiX+gfGrowHiY;

	Insert(ToDoView);
	Insert(ToDoView^.VScrollBar); {insert todo's scrollbar}

	{to do label}
	X := (Size.X-22) div 2;;
	Bounds.Assign(X - 3, Size.Y-10, X +2, Size.Y-9);
	Lab := New(PLabel, init(Bounds, 'TO DO', ToDoView));
	{Y top/bottom fixed to owner's bottom, X left/right with owner's left}
	Lab^.GrowMode := gfGrowLoY + gfGrowHiY;
	Insert(Lab);

	{calendar}
	Bounds.Assign(SIze.X-21, Size.Y-9, Size.X-1, Size.Y-1);
	New(Calendar, init(Bounds));
	{not selectable - so useful views, ie todo/diary list stay focused,
	but allow postprocess and usual broadcast eventmask to pick up mouse
	and t/T/+/- etc keypresses}
	Calendar^.Options := (Calendar^.Options or ofFramed or ofPostProcess) and not ofSelectable;
	Calendar^.GrowMode := gfGrowAll; {moves with bottom right}


	Insert(Calendar);

	{date indicator}
	Bounds.Assign(Size.X-23, 1, Size.X-1, 2);
	New(DateIndicator, init(Bounds));
	DateIndicator^.GrowMode := gfGrowLoX + gfGrowHiX;{}
	Insert(DateIndicator);

	List^.Focus; {focus on main list}
end;


procedure TWeekDiary.SizeLimits;
begin
	inherited SizeLimits(Min, Max);
	Min.X := 27;
	Min.Y := 13;
end;

{$IFDEF MSDOS}
procedure TWeekDiary.Idle;
begin
	List^.Idle;
{  Calendar^.Idle;{}
	ToDoView^.Idle;
end;
{$ENDIF}




{************************************************************
 ***              DIARY WINDOW GROUP                      ***
 ************************************************************}
procedure StartDayDiary; far;
var Bounds : TRect;
		Diary : PDayDiary;

begin
	Desktop^.GetExtent(Bounds);{}
	Bounds.Assign(0, 0, 80, Bounds.B.Y);{}
	CentreOnView(Bounds, Desktop);
	CheckOnDesktop(Bounds);

	New(Diary, init(Bounds,-1));
	Desktop^.Insert(Diary);
end;

procedure StartweekDiary; far;
var Bounds : TRect;
		Diary : PWeekDiary;

begin
	Desktop^.GetExtent(Bounds);{}
	Bounds.Assign(0, 0, 80, Bounds.B.Y);{}
	CentreOnView(Bounds, Desktop);
	CheckOnDesktop(Bounds);

	New(Diary, init(Bounds,-1));
	Desktop^.Insert(Diary);
end;

{Starts staff diary for current user}
procedure StartUserDiary; far;
var Bounds : TRect;
		Diary : PDayDiary;

begin
	{$IFDEF Kusers}
	if CurrentUser<>nil then begin
		Desktop^.GetExtent(Bounds);{}
		Bounds.Assign(0, 0, 80, Bounds.B.Y);{}
		CentreOnView(Bounds, Desktop);
		CheckOnDesktop(Bounds);

		New(Diary, init(Bounds, CurrentUser^.RecNo));
		Desktop^.Insert(Diary);
	end;
	{$ENDIF}
end;

procedure StartStaffDiary; far;
var Bounds : TRect;
		Diary : PDayDiary;
		EditBox : PEditBox;
		R : TREct;
		ID : longint;
		Control : word;
		Directoryitem : Pdirectoryitem;
		InpLine : PInputJimmy;

begin
	R.ASsign(0,0,33,7);
	New(EditBox, init(R, 'Diary For Who',nil));
	with EditBox^ do begin
		Options := Options or ofCentered;

		InpLine := PInputJimmy(InsTitledField(5, 2, 23, 1, 'For',
				New(PInputDirectory, init(R, 26, fiCatDirIdx, lsDirectory, 'STA'))));
		InpLine^.MustInput := True;

		InsOKButton(9, 4, @ID);
		InsCancelButton(20, 4);
		EndInit;
	end;

	if Desktop^.ExecView(EditBox)<>cmCancel then begin

		Desktop^.GetExtent(Bounds);{}
		Bounds.Assign(0, 0, 80, Bounds.B.Y);{}
		CentreOnView(Bounds, Desktop);
		CheckOnDesktop(Bounds);

		New(Diary, init(Bounds,ID));
		Desktop^.Insert(Diary);
	end;

	dispose(EditBox, done);
end;



{**********************************
 ***  CREATORS/TASK             ***
 **********************************}

procedure StartDiaryRepeater; far;
var Bounds : TRect;
		List : PIndexedJimmyListView;
begin
	Bounds.Assign(Desktop^.Size.X div 2, 0, Desktop^.Size.X, 24);
	List := New(PIndexedJimmyListView, init(Bounds, lsDiaryRepeaters, fiDiaryActionIdx, ''));
	List^.ColHeader := '  Next  Rpt  From  ';
	Desktop^.Insert(New(PIndexedJimmyListWindow, init(Bounds, 'Auto-Action Diary', List)));
end;

{procedure NewDiaryToDoList; far;
var Bounds : TRect;
begin
	Desktop^.GetExtent(Bounds);
	Desktop^.Insert(New(PIndexedJimmyListWindow, init(Bounds, 'DIARY TO-DO',
										New(PDiaryView, init(Bounds, fiDiaryToDoIdx, Today)))));
end; {}

function NewDiaryIndex : PStream; far;
begin NewDiaryIndex := New(PIndexedJimmyStream, init('DIARY.IDX',TDiaryIndexSize)); end;

function NewDiaryToDoIndex : PStream; far;
begin NewDiaryToDoIndex := New(PIndexedJimmyStream, init('DYTODO.IDX',TDiaryIndexSize)); end;

function NewDiaryActionIndex : PStream; far;
begin NewDiaryActionIndex := New(PIndexedJimmyStream, init('DYRPT.IDX',TDiaryIndexSize)); end;

function NewStaffDiaryIndex : PStream; far;
begin NewStaffDiaryIndex := New(PIndexedJimmyStream, init('STAFFDY.IDX',TDiaryIndexSize)); end;

function NewStaffDiaryToDoIndex : PStream; far;
begin NewStaffDiaryToDoIndex := New(PIndexedJimmyStream, init('STAFF2DO.IDX',TDiaryIndexSize)); end;


function CreateDiaryEvent(P : pointer) : pointer; far;
begin CreateDiaryEvent := New(PDiaryEvent, Init(P)); end;

function CreateDiaryRepeater(P : pointer) : pointer; far;
begin CreateDiaryRepeater := New(PDiaryRepeater, Init(P)); end;


{**************************************
 ***       INITIALISER              ***
 **************************************}
begin
	RegisterScodeType(scEvents,   'EVENTS.SC',  'Event Types', CostedSCodeCreator);
	RegisterSCodeType(scOutcomes, 'Outcome.SC', 'Outcome Codes', StdSCodeCreator);

	RegisterType(RDiaryEvent);

	RegisterType(RDiaryRepeater);
	RegisterCreator(cmNewDiaryRepeater, CreateDiaryRepeater);
{	RegisterJimmy(RDiaryREpeater, CreateDiaryRepeater, lsDiaryRepeaters, 'Repeater');{}

{$IFDEF KDiary}
	RegisterTask(DesktopTasks, cmStartDiary, @StartDayDiary);
	RegisterTask(DesktopTasks, cmStartStaffDiary, @StartStaffDiary);
	RegisterTask(DesktopTasks, cmStartDiaryRepeater, @StartDiaryRepeater);
	RegisterTask(DesktopTasks, cmStartUserDiary, @StartUserDiary);

	RegisterTask(DesktopTasks, cmStartWeekDiary, @StartWeekDiary);

	{Streams}
	NewFileAdmin(fiDiaryIdx, 'Diary Index',NewDiaryIndex); {full diary}
	NewFileAdmin(fiDiaryTodoIdx, 'Diary Todo Index', NewDiaryToDoIndex);
	NewFileAdmin(fiDiaryActionIdx, 'Diary Auto Action Index', NewDiaryActionIndex);

	NewFileAdmin(fiStaffDiaryIdx, 'Staff Diary Index',NewStaffDiaryIndex);
	NewFileAdmin(fiStaffDiaryTodoIdx, 'Staff Diary Todo Index', NewStaffDiaryToDoIndex);

	{Diary Item}
	RegisterCreator(cmNewDiaryEvent, CreateDiaryEvent);
	RegisterNewWithList(lsDiary, '~A~ppointment', cmNewDiaryEvent);
{	AddItemEnd(DiaryNewMenu, NewItem('~A~ppointment', '', kbNone, cmNewDiaryEvent, hcNoContext,	nil));{}

	RegisterNewWithList(lsDiary, 'Repeat', cmNewDiaryRepeater);
	RegisterNewWithList(lsDesktop, 'Repeat', cmNewDiaryRepeater);
{	RegisterTask(DesktopTasks, cmNewDiaryRepeater, @CreateEditJimmy);{}

	RegisterWithList(lsDiary, '~P~rint',
		NewItem('~I~tem',   ksPrint, kbPrint, cmPrintBox,hcNoContext,
		newLine(
		NewItem('~D~ay',  ksPrintList,  kbPrintList,cmPrintList,hcNoContext,
	nil))),nil);{}

{$ENDIF}

	AutoActionDate.Clear;
	AutoActionTime.Clear;

	AlarmDate.Clear;
	AlarmTime.Clear;
end.

