{****************************************************************************
 ***                                                                      ***
 *** New Fabbo Singing Dancing OOP                                        ***
 ***                          Job DETAILS                             ***
 ***                                                                      ***
 *** M Hill                                                      Nov 1992 ***
 ****************************************************************************}
{$I compdirs}  {Compiler directives}

unit KJOB;

INTERFACE

uses
		ordproc, jimmys, {parent}
		scodes, {outcome}
		files,
		devices, forms,
		global, objects, views, dattime, notes, tuiedit;

{====================== JOB SHEET =======================}
type
	PJob = ^TJob;
	TJob = object(TOrder)

		{Torder.date is call date}
		{now in torder CustRef		: string[20];{}
		VisitDate : TDate;{}
		VisitTime : string[15];

		SiteID : longint;

		Outcome   : TSCode;

		Invoiced  : boolean;

		DiaryIdx : longint; {pointer to diary}
		StaffDiaryIdx : longint; {pointer to bywho's diary}

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

		function DisplayLine(ListForWho : longint; lstype : byte; Maxlen : integer; View : word) : string; virtual;
		procedure MakeEditBox(var EditBox : PEditBox; Caller : PView);  virtual;

		procedure SetFormCodes(const FormCodes: PFormCodeCollection); virtual;
		procedure PrintSummary(const Device : PDeviceStream; const PrintAs : word); virtual;
		procedure PrintFull(const Device : PDeviceStream; const PrintAs : word); virtual;

		{DataBase}
		constructor Load(var S : TDataStream);
		procedure   StoreFields(var S : TDataSTream); virtual;

		function srType : word; virtual;
		function RecSize : word; virtual;
		function PtrOffset : byte; virtual;

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

		{-- Hooking to others -----}
		{override key}
		procedure GetHookTo(const htType : byte; var HookToID,SubHookToID : PLongint;
												var hkType : byte; var Key : longint; var InsertBias : boolean); virtual;
 end;


IMPLEMENTATION

uses minilib, inpdnt, lstrings,
			address,
			help,
			inpjimmy,
			kdirctry,
			app,
			tui, tuijimmy, tuimsgs, tuiboxes,
			idindex,
			jimhooks,
			tasks;


{**************************************************************
 ***                                                        ***
 ***               DEFINE JOB SHEET OBJECT                  ***
 ***                                                        ***
 **************************************************************}

constructor TJob.Init;
begin
	inherited Init(Param);

	Date.SetToToday;
	VisitDate.SetToToday; VisitDate.AddDay(True);
	Invoiced := False;
  SiteID := -1;
end;

{Required by get as well}
procedure TJob.CommonInit;
begin
	inherited CommonInit;
	SCodeCollection[scOutcomes]^.LogOn;
end;

destructor TJob.Done;
begin
	SCodeCollection[scOutcomes]^.LogOff;
	inherited Done;
end;

{==== CREATE DISPLAY-LINE-FORMAT STRING ============}
function TJob.DisplayLine;
var S,SS : string;
		FW : PDirectoryItem;
		Site : Paddress;

begin
	if VisitDate.Blank then begin
		S := Date.Digit8+' JOB (No Visit)';
	end else begin
		S := VisitDate.Digit8;
		if lsType = lsDiary then
			S := S + ' '+padspaceR(VisitTime,10);
		S := S + ' JOB ';
	end;

	S := S+ PadSpaceL(N2Str(Ref),6);
	if ForWhoRef<>nil then S := S + ' ' + padspaceR(ForWhoRef^,15);        {Customer ref}

	if lsType<>lsHistory then begin
		SS := '';
		if ForWho<>-1 then begin
			FW := PDirectoryItem(GetJimmy(ForWHo));
			SS := FW^.GetName(naRef,0);
			dispose(FW, done);
		end;
		if SiteID<>-1 then begin
			if SS<>'' then SS := SS + ', ';
			Site := PAddress(GetJimmy(SiteID));
			SS := SS+Site^.Town;
			dispose(Site, done);
		end;
{		if SS<>'' then S := S + PadSpaceR(SS,23);{}
	end;

	if ByWho<>-1 then S := S + RightSet+' '+GetJimmyIDName(ByWho, naRef, 0);

	DisplayLine := S;
end;

{*****************************************
 ***        SCREEN INPUT BOX           ***
 *****************************************}
procedure LinkSite(const Linker : PInputLinker; const CallingView : PView); far;
var	ForLine : PINputDirectory;
		SiteLine : PInputHookedJimmy;
		Site : PAddress;

begin
	ForLine := PInputDirectory(Linker^.SourceView[1]);
	SiteLine := PInputHookedJimmy(Linker^.TargetView[1]);

	{set address from whichever - person/coy}
	if PInputJimmy(ForLine)^.GetJimmy<>nil then begin
		Site := PDirectoryItem(PInputJimmy(ForLine)^.GetJimmy)^.GetAddressFor(Today, apDelivery);
		if Site<>nil then begin
			SiteLine^.SetData(Site^.recNo);
			SiteLine^.DrawView;
			dispose(Site, done);
		end else begin
			SiteLine^.SetData(PDirectoryItem(PInputJimmy(ForLine)^.GetJimmy)^.AddressID);
			SiteLine^.DrawView;
		end;
	end;

	if ForLine^.GetJimmy=nil then
		SiteLine^.SetParent(-1)
	else
		SiteLine^.SetParent(ForLine^.ID);
end;




procedure TJob.MakeEditBox;
var
	R: TRect;
	I : integer;
	InpFor, InpBy : PInputDirectory;
	ByView, NotesView, ItemView, VisitTimeView, VisitDateView, ForRefView, CallDateView, RefView : PView;
	SiteLinker : PInputLinker;

begin
	R.Assign(0, 0, 60, 20);
	CentreOnView(R, Caller);
	EditBox := New(PJimmyEditBox, init(R, 'JOB DETAILS',Caller,@Self));

	New(SiteLinker, init(@LinkSite, EditBox));

	with EditBox^ do begin

		HelpCtx := hcJobSheetEditBox;

		Insert(New(PSkipBytes, init( sizeof(TJimmy)
																+4 {skip ptr2items}
																+sizeof(TDate) {skip lastprint}
																+1+sizeof(TTotallerGroup)))); {skip state & price group}

		RefView := InsTitledField( 7, 1, 6, 1, '~R~ef',  New(PInputRefNum, Init(R, 10, srJobSheet)));
		Insert(New(PSkipBytes, init(4))); {skip old ref}

		CallDateView := InsTitledField(27, 1,10, 1, 'Call ~D~ate', New(PInputDate, Init(R)));

		InsTitledField( 7, 3,26, 1, '~F~or', 			New(PInputDirectory, Init(R,25, fiFullDirIdx, lsDirectory, '')));
		SiteLinker^.SetSourceView(Current, 1);
		InpFor := PInputDirectory(Current);
		InpFor^.MustInputToClose := True;{}

		ForRefView 	:= InsTitledField(45, 3,10, 1, 'Cust Ref', New(PInputPStr, init(R,20)));
		ByView 			:= InsTitledField( 7, 4,26, 1, '~B~y', 			New(PInputDirectory, Init(R,25, fiCatDirIdx, lsDirectory, 'STA')));

		VisitDateView := InsTitledField( 7, 6,10, 1, '~V~isit', New(PInputDate, Init(R)));
		VisitTimeView := InsTitledField(27, 6,10, 1, '~T~ime',      New(PInputELine, Init(R, 15)));

		InsTitledField(45, 6, 12, 1, '~S~ite', New(PInputHookedJimmy, init(R, 25, hkAddress, lsAddresses, 0, -1)));
		SiteLinker^.SetTargetView(Current, 1);


		{list}
		ItemView := InsTitledField(7, 8,50,7, 'T~a~sks',
								New(PDlgHookView,	Init(R, lsSalesItems, 0, hkOrderItems, @Self, PJimmyEditBox(EditBox))));
		Insert(PHookViewer(ItemView)^.VScrollBar);

		{notes}
		NotesView := InsTitledField(7,16,28, 3, '~N~otes', New(PInputFreeText, Init(R, 490, 27, nil)));   {Memo editor}

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

		EndInit;

		{Now, the above is laid out as we would wish to input it.  We now have to
		map the getdataorder to the layout of the jobsheet:

		TOrder, then
		VisitDate : TDate;
		VisitTime : string[15];
		Outcome   : TSCode;
		Invoiced  : boolean;{}

		SetDataOrder;
		MoveDataOrder(NotesView, ByView); {move the notes view to after the byview}

		InpFor^.Focus;
{		if ForWho<>-1 then begin
			FocusNext(False); {move on to customer reference line}
			{note that with above INpFor^ set to just mustclose, this line
			produces an error ('Must Input') *before* even inputting to the box.
			Because of course, it's empty at the moment...}
{		end;{}
	end;
end;



{*****************************************
 ***     STREAMING DEFINITIONS         ***
 *****************************************}
function TJob.srType;
begin srType := srJobSheet; end;

function TJob.RecSize;
begin Recsize := 120; end;

function TJob.PtrOffset;
begin PtrOffset := inherited PtrOffset +1; end;

constructor TJob.Load(var S : TDataStream);
var	Ver : byte;
		FW : PDirectoryItem;
begin
	S.Read(Ver, 1);

	case Ver of
		1 : begin
			{v4.1 type}
			inherited Load(S);

			ForWhoRef := NewStr(S.ReadStr);
			S.Read(ByWho, 4);

			VisitDate.Load(S);
			VisitTime := S.ReadStr;

			Notes^.Load(S);

			S.Read(Outcome, sizeof(Outcome));
			S.Read(Invoiced, 1);

			FW := PDirectoryItem(GetJimmy(ForWho));
			SiteID := FW^.AddressID;
			dispose(FW, done);
		end;
		2 : begin
			{4.3a bywho, notes and custref moved to TOrder}
			inherited Load(S);

			VisitDate.Load(S);
			VisitTime := S.ReadStr;

			S.Read(Outcome, sizeof(Outcome));
			S.Read(Invoiced, 1);

			FW := PDirectoryItem(GetJimmy(ForWho));
			SiteID := FW^.AddressID;
			dispose(FW, done);
		end;
		3 : begin
			{4.3d added siteid}
			inherited Load(S);

			VisitDate.Load(S);
			VisitTime := S.ReadStr;

			S.Read(Outcome, sizeof(Outcome));
			S.Read(Invoiced, 1);

			S.Read(SiteID, 4);
		end;
	else
		DBaseMessage(@S, 'Version '+N2Str(Ver)+' not understood'#13#10'TJob.Load',mfError,hcInternalErrorMsg);
		fail; {return nil pointer}
	end; {case}
end;

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

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

	inherited StoreFields(S);

	VisitDate.Store(S);
	S.WriteStr(@VisitTime);

	S.Write(Outcome, sizeof(Outcome));
	S.Write(Invoiced, 1);

	S.Write(SiteID, 4);
end;

{--- Indexing ----}
function TJob.NumixTypes : byte;
begin NumixTypes := 2; end;

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

	case ixType of
		1 : begin IdxRec := @DiaryIdx; 			fiType := fiDiaryIdx; 			end;
		2 : begin IdxRec := @StaffDiaryIdx; fiType := fiStaffDiaryIdx; 	end;
	end;
	if VisitDate.Blank and (ixType=1) then fiType := fiDiaryToDoIdx;
end;

function TJob.GetIndexKey;
begin
	GetIndexKey := '';
	if not VisitDate.Blank then begin
		case ixtype of
			1 : GetIndexKey := VisitDate.AsKey + space(4)+VisitTime;
			2 : if ByWho>-1 then GetIndexKey := PakLint(ByWho)+ GetIndexKey(1);{temporary comment out for NSS update!}
		end;
	end else begin
		if ixType = 1 then GetIndexKey := Date.AsKey + space(4);
	end;
end;

{-- Hooking to others -----}
{overrides key with visitdate}
procedure TJob.GetHookTo;
begin
	inherited GetHookTo(htType, HookToID,SubHookToID, hkType, Key, InsertBias);
	insertBias := biStart;
	if VisitDate.Blank then	Key := SortKeyStart {Make sure appears at beginning}
	else Key := -VisitDate.Days;  							{Reverse Sort on date}
end;

{*****************************************************
 ***               PRINT JOB SHEET                 ***
 *****************************************************}
procedure TJob.SetFormCodes;
begin
	inherited SetFormCodes(FormCodes);

	with FormCodes^ do begin
{		SetJimmyIDFormCodes(ToAdd, FormCodes); {put in address stuff direct}
		Insert(New(PJimmyFormCode, init('SITE', SiteID)));

		Insert(New(PFreeTextFormCode, init('NOTES',Notes^)));

		SetStr('CDT',Date.Digit10);
		SetStr('VDT',VisitDate.Digit10);
		SetStr('VTIME',VisitTime);
	end;
end;

procedure TJob.PrintSummary;
var I : byte;
begin
	with Device^ do begin
		{Check to see if *likely* to run over page, and do a new page if nec (so
		trying to keep in discrete lumps}
		CheckForNewPage(1 + LSnumLines(Notes^.Text)+2);{}

		{First line}
		WriteStr(VisitDate.Digit8+' JOB '+N2Str(Ref));
		if ForWhoRef<>nil then writeln(' '+ForWhoRef^) else writeln('');

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

procedure TJob.PrintFull;
var ForDir : PDirectoryItem;
		FormName : string;
begin
	with Device^ do begin
		SetFormCodes(FormCodes);

		{Print header}
		FormName := 'JOBSHEET';

{$IFDEF solitaire}
		{allow for "multi-company" job sheet headers}
		if ForWho<>-1 then begin
			ForDir := PDirectoryItem(JimmyStream^.GetAt(ForWho));
			if ForDir<>nil then begin
				if pos('NWC', ForDir^.GetCategories)>0 then	FormName := 'JOBSHNWC';
				dispose(ForDir, done);
			end;
		end;
{$ENDIF}

		StartPrint('',FormName);  {Page heading definition}

		{do print items}

		{$IFDEF Solitaire}
			if ForWhoRef<>nil then
				if ucase(delspace(ForWhoRef^))='PRIVATE' then writeln('       Job to be charged for');
		{$ENDIF}

		EndPrint;{}
	end; {with}
end;


{**********************************************************************
 ***																																***
 ***                 SELECT BY ID                                   ***
 ***																																***
 **********************************************************************}
{Returns rec no of ID of owning person}
procedure FindJobByID; far;
var	Ref,ID : longint;
		Control : word;
		Job : PJob;

begin
	Ref := 0;
	Control := InputLintBox('FIND JOB', 'Ref #', Ref);

	if Control<>cmCancel then begin
		ID := GetIDPtr(srJobSheet, Ref);
		if ID=-1 then
			ProgramWarning('Could not find Job Ref '+N2Str(Ref),hcNoContext)
		else begin
			Job := PJob(GetJimmy(ID));
			Job^.Edit(Desktop,nil);
		end;
	end;
end;


{*************************************************
 ***         REG/INIT                          ***
 *************************************************}
function CreateJob(P : pointer) : pointer; far;
begin CreateJob := New(PJob, Init(P)); end;

const
	{--- Required for Stream ----}
	RJob : TStreamRec = (
		ObjType : srJobSheet;
		VmtLink : Ofs(TypeOf(TJob)^);
		Load : @TJob.Load;
		Store : @TJob.Store
	);

begin
	RegisterJimmy(RJob, CreateJob, lsDesktop, '~J~ob Sheet');

	{Register with directory history}
	RegisterNewWithList(lsHistory, '~J~ob Sheet', cmNewJobSheet);
	{Register with diary}
	RegisterNewWithList(lsDiary, '~J~ob Sheet', cmNewJobSheet);

	RegisterTask(DesktopTasks, cmFindJobByID, @FindJobByID);
end.
