{**************************************************************
 ***                                                        ***
 ***                     MAINTENANCE                        ***
 ***                                                        ***
 **************************************************************}
{$I CompDirs}
unit KMAINT;

INTERFACE

uses files, setup,
			devices, inpfname,
			{$IFDEF Windows}
				winedit;
			{$ELSE}
				tuiedit;
			{$ENDIF}

{==== DATABASE MANAGEMENT =======}
procedure DataBackup;  {backs up data directory}
{procedure SetupBackup; {backs up forms, .cfg, wp directory, etc}
procedure DataRestore;
{procedure SetupRestore;{}

procedure MakeHolesinAll;

procedure EditForm;

procedure EditProgramSetup;

type
	PBackupSetup = ^TBackupSetup;
	TBackupSetup = object(TSetup)

		BackupDrive : string[1];

		BackupProgram   : string[80];
		RestoreProgram   : string[80];

		ConcatPaths : boolean;
		AppendFlag : string[10];

		procedure Load; virtual;
		procedure Store; virtual;
		procedure AddSetupLines(EditBox : PEditBox); virtual;
		procedure SetButtonDefaults; virtual;
	end;

var
	BackupSetup : TBackupSetup;

IMPLEMENTATION

uses
{$IFDEF WINDOWS}
	win,
{$ELSE}
	tui, {text}
	tuiboxes,
	menus, {for scode list}
	tuimsgs,
	tuiapp,
	views,
	dialogs,
{$ENDIF}

	stddlg, {for file dialog box}
	muser,{}
	help,
	kamsetup,{backup setup/etc}
	objects, {TRect}
	status, 	{for checking for other terminals}
	dosUtils, {for executing programs, eg backup}
	editfile, {for edit forms}
	tasks,
	scodes, {for editing}
	forms, {for tcodecollection, used to decode command lines}

	dattime, inpdnt, windos,{setting date & time}

	global,
{$IFDEF kdirctry}	kdirctry, {for updating main menu}{$ENDIF}
{$IFDEF Kusers}		kusers, {$ENDIF} {For setting terminal no}
	kimport,
	multcurr,
	{$IFDEF kwplink} kwplink, {$ENDIF}
	indexes, indxUtil, {for making holes}
	minilib,
	address, jimprint, {for setup edit}
	app;


{*****************************************
 **             BACKUP                 ***
 *****************************************}

procedure DataBackup;
var
	Control : word;
	Paths : TStringCollection;
	P : string;
	I : integer;
	Result : word;

	{=== BACKS UP A PARTICULAR PATH =========}
	function RunPathBackup(const Msg,Path : string; const First : boolean) : word;
	var
		CodeSet : TFormCodeCollection;
		Backup : string;

	begin
		{Decode parameter line}
		with CodeSet do begin
			Init;
			SetStr('FROM', Path);
			SetStr('TO',   BackupSetup.BackupDrive+':');
			if First then SetStr('FLAGS','') else SetStr('FLAGS',BackupSetup.AppendFlag);
			Backup := QDecodeStr(BackupSetup.BackupProgram);
			Done;
		end;

		{backup - eg dos backup}
		if delspaceR(Backup)<>'' then
			RunPathBackup :=
				Run( Copy(Backup,1,pos(' ',Backup)-1), 			{prog}
						 Copy(Backup, pos(' ',Backup)+1, 255),  {params}
						 rnCheck, Msg+#13#10+'   '+Backup);
	end;


begin
	{First check that there are no other views open}
	if not DesktopEmpty then begin  {only one - the background - allowed}
		ClearDesktopMessage;
		exit;
	end;
	if OtherTerminalsRUnning then begin
		Control := CloseOtherTerminalsMessage;
		if Control = cmRetry then DataBackup;
		if Control = cmCancel then exit;
	end;

	{set paths array}
	Paths.Init(5,1);
	Paths.Insert(NewStr(DataPath));
	Paths.Insert(NewStr(FormsPath));
	Paths.Insert(NewStr(PrintersPath));
	{$IFDEF kwplink} Paths.Insert(NewStr(WPSetup.FormsPath)); {$ENDIF}

	ProgramStatus.DOne; {close status file so it can be backed up}

	if not BackupSetup.ConcatPaths then begin
		{multiple steps}
		Result := 0;
		for I := 0 to Paths.Count-1 do begin
			if Result = 0 then
				Result := RunPathBackup('Backing up path '+PString(Paths.At(I))^,
																	PString(Paths.At(I))^+'*.*',I=0);
		end;
	end else begin
		{single step}
		P := '';
		for I := 0 to Paths.Count-1 do
			P := P + PString(Paths.At(I))^+'*.* ';

		RunPathBackup('Complete Backup',P, False);
	end;

	Paths.Done;
	ProgramStatus.Init; {reopen}

	Today.SetToToday;
	ProgramStatus.SetLastBackupDate(Today);
end;

{***************************************
 ***        RESTORE                  ***
 ***************************************}

procedure DataRestore;
var
	Control : word;
	Params, Prog : string;
	CodeSet : TFormCodeCollection;

begin
	{First check that there are no other views open}
	if not DesktopEmpty then        {only one - the background - allowed}
			ClearDesktopMessage
	else begin
		{And that no other terminals are running}
		if OtherTerminalsRUnning then begin
			Control := CloseOtherTerminalsMessage;
			if Control = cmRetry then DataRestore;
			if Control = cmCancel then exit;
		end;

		Params := copy(BackupSetup.RestoreProgram,pos(' ', BackupSetup.RestoreProgram)+1,255);
		Prog := copy(BackupSetup.RestoreProgram,1, pos(' ', BackupSetup.RestoreProgram)-1);


		{Decode parameter line}
		CodeSet.Init;
		CodeSet.SetStr('TO', DataPath);
		CodeSet.SetStr('FROM',   BackupSetup.BackupDrive+':');
		Params := CodeSet.QDecodeStr(Params);
		CodeSet.Done;

		ProgramStatus.DOne; {close status file so it can be backed up}
		Run(Prog,Params, rnCheck,'Restoring Data...');
		ProgramStatus.Init;
	end;

end;

{**********************************************
 ***           BACKUP/RESTORE SETUP         ***
 **********************************************}
procedure TBackupSetup.Load;
var S : string;
begin
	BackupDrive := Get('DRIVE','');

	BackupProgram   :=  Get('BACKUP PROGRAM',		'');
	RestoreProgram   := Get('RESTORE PROGRAM',	'');
	ConcatPaths := GetBoolean('CONCAT PATHS', False);
	AppendFlag := Get('APPEND FLAG', '');

	if BackupProgram = '' then SetButtonDefaults; {first time set}
end;

procedure TBackupSetup.Store;
begin
	Put('DRIVE', BackupDrive);
	Put('BACKUP PROGRAM',    BackupProgram);
	Put('RESTORE PROGRAM',   RestoreProgram);
	PutBoolean('CONCAT PATHS', 		ConcatPaths);
	Put('APPEND FLAG', 			AppendFlag);

	ProgramSetup.Store;
end;

procedure TBackupSetup.SetButtonDefaults;
begin
	BackupDrive 		:= 'A:';
	BackupProgram   := 'BACKUP.EXE <FROM> <TO> <FLAGS> /L' ;
	RestoreProgram  := 'RESTORE.EXE <FROM> <TO>';
	ConcatPaths 		:= False;
	AppendFlag 			:= '/A';
end;

{============ EDIT ======================}
procedure TBackupSetup.AddSetupLines;
var R : TRect;
begin
	with EditBox^ do begin
		GrowTo(50,12);

		InsTitledField(20,  1, 1, 1, '~D~rive', New(PInputELine, init(R, 1)));
		PInputELine(Current)^.UpperCase := True;

		InsTitledField(20,  3,26, 1, 'BACKUP Program', New(PInputELine, init(R, 80)));
		InsTitledField(20,  4,26, 1, 'RESTORE Program', New(PInputELine, init(R, 80)));

		InsTitledField(20,  6, 1, 1, 'Concatinate Paths', New(PInputBoolean, init(R)));
		InsTitledField(20,  7,10, 1, 'Append Flag', New(PInputELine, init(R, 10)));

		HelpCtx := hcBackupSetup;
	end;
end;


{***************************************************************************
 ***                                                                     ***
 ***               CREATE HOLES IN INDEX                                 ***
 ***                                                                     ***
 ***************************************************************************}
procedure MakeHolesinAll;
var EditBox : PEditBox;
		R : TRect;
		Control : word;
		fiType : word;
		Line : word;

begin
	{First check that there are no other views open}
	if not DesktopEmpty then begin       {only one - the background - allowed}
			ClearDesktopMessage;
			exit;
	end;
	if OtherTerminalsRUnning then begin
			Control := CloseOtherTerminalsMessage;
			if Control = cmRetry then begin MakeHolesinAll; exit; end;
			if Control = cmCancel then exit;
	end;

	Control := cmOK;
	for fiType := 1 to fiMaxfi do begin
		if FIleAdmin(fiType)<>nil then begin
			FileAdmin(fiType)^.LogOn;
			if Right(Stream(fiType)^.FileName, 4)='.IDX' then
				Control := MakeHoles(PIndexStream(Stream(fiType)), 5);
			FileAdmin(fiType)^.LogOff;
			if Control = cmCancel then begin
				MessageBox('HOLE MAKER','Abandoned',mfInformation+mfWarningBleep+mfOkButton, hcHoleCreator);
				exit;
			end;
		end;
	end;

	MessageBox('HOLE MAKER','Finished!',mfInformation+mfWakeUpBleep+mfOKButton, hcHoleCreator);
end;


{**********************************************
 ***              EDIT STANDARD FORMS       ***
 **********************************************}
var LastFormFileName : FNameStr;

procedure EditForm;
const
	FormExts = 'HDR FTR HD1 FTL FRM STL';

var EditBox : PEditBox;
		R : TRect;
		Control : word;
		FileName : string[20];
		FullFileName : FNameStr;

begin
	repeat
		{get file name to edit}
		Control := FileSelectBox('EDIT FORM','Form', LastFormFileName,
							FormExts, FormsPath, fdPickOnly+fdOpenButton+fdNewButton,
							hcNoContext);

		if Control <> cmCancel then begin

			if Control = cmNew then
				FullFileName := FormsPath
			else
				FullFileName := FormsPath + LastFormFileName;

			{Edit file}
			FileEditor(FullFileName, 0, '',FormExts, StdBufferSize, hcEditForm);

		end;
	until Control=cmCancel;

end;

{******************************************
 ***          EDIT PROGRAM SETUP        ***
 ******************************************}
{A more user friendly approach than the tekky one below}

procedure EditProgramSetup;
var EditBox : PEditBox;
		R : TRect;
		Control : word;
		Line : integer;
		InputRecord : record

			UserCoyID : longint;

			Terminal : byte;

			Country : TSCode;     {not just default country - assumed for labels & dialling to be the one we're in}
			DefCurrency : TScode;
			DefVAT : TSCode;

			DeadDataMode : Boolean;

			NewsFlashInt : word; {check for news flash interval}

			AutoNew : boolean;

			DefEditor	: word;
			StartupView : word;
		end;

begin
	{-- Get data from cfg file ----}
	with InputRecord do with ProgramSetup do begin
		UserCoyID			:= S2Num(Get('USER COY ID','-1'));
		Terminal			:= S2Num(Get(siTerminalNo, '0'));
		Country 			:= Get(siCountry,'UK');
		DefCurrency 	:= Get(siDefaultCurrency,'STE');
		DefVAT				:= Get(siDefaultVAT, 'STD');
		DeadDataMode 	:= GetBoolean(siDeadDataMode,False);
		NewsFlashInt	:= S2Num(Get(siNewsFlashInt, '0'));
		AutoNew				:= GetBoolean(siAutoNew, True);
		DefEditor			:= S2Num(Get(siDefedType, N2Str(edInternal)));
		StartUpView		:= S2Num(Get(siStartStdView, ''));
	end;

	{-- set up box ---}
	R.Assign(0,0,50,12);
	New(EditBox, init(R, 'Program Setup', Desktop));

	with EditBox^ do begin
		Options := Options or ofCentered;
		HelpCtx := hcGeneralSetup;
		Line := 1;

		{--- Create fields ----}
		{$IFDEF kdirctry}
		InsTitledField(16,Line,20,1, 'Your Coy', New(PInputDirectory, init(R,20, fiFullDirIdx, lsDirectory,'')));
		inc(Line,2);
		{$ELSE}
		Insert(New(PSkipBytes, init(4)));
		{$ENDIF}

		{$IFNDEF SingleUser}
		InsTitledField(16,Line,2,1, 'Terminal', New(PInputByte, init(R,2)));
		inc(Line,2);
		{$ELSE}
		Insert(New(PSkipBytes, init(1)));
		{$ENDIF}

		if SCodeCollection[scCOuntries]<>nil then begin
			InsTitledField(16,Line,20,1, 'Country', 			New(PInputSCode, init(R, scCountries)));
			PInputELine(CUrrent)^.MustInput := True;
			inc(Line);
		end else
			Insert(New(PSkipBytes, init(sizeof(TSCode))));

		if SCodeCollection[scCurrency]<>nil then begin
			InsTitledField(16,Line,20,1, 'Def Currency', New(PInputSCode, init(R, scCurrency)));
			PInputELine(CUrrent)^.MustInput := True;
			inc(Line);
		end else
			Insert(New(PSkipBytes, init(sizeof(TSCode))));

		if SCodeCollection[scVATRates]<>nil then begin
			InsTitledField(16,Line,20,1, 'Def VAT', New(PInputSCode, init(R, scVATRates)));
			PInputELine(CUrrent)^.MustInput := True;
			inc(Line);
		end else
			Insert(New(PSkipBytes, init(sizeof(TSCode))));

		inc(Line);

		{$IFDEF klivestk}
		InsTitledField(16,Line, 1,1, 'Dead Data Mode', New(PInputBoolean, init(R)));
		inc(Line,2);
		{$ELSE}
		Insert(New(PSKipBytes, init(1)));
		{$ENDIF}

		{$IFDEF Knewsfl}
		InsTitledField(16,Line,4,1, 'News Flash Int', New(PInputWord, init(R,4)));
		inc(Line,2);
		{$ELSE}
		Insert(New(PSKipBytes, init(2)));
		{$ENDIF}

		InsTitledField(16,Line, 1,1, 'Auto New', New(PInputBoolean, init(R)));
		inc(Line,2);

		{--- Def Editor ----}
		R.XYLD(16, Line,17,2);	Insert(NewEditorLine(R)); AddLabel('Def Editor', Current);
		inc(Line,3);

		{--- Def Editor ----}
		R.XYLD(16, Line,20,3);	Insert(New(PERadioButtons, init(R,
																			NewSItem('None',
																			NewSItem('Directory/Diary',
																			NewSItem('Full Directory',
																		nil))))));
		{$IFNDEF kdiary} 		with PCluster(Current)^ do EnableMask := EnableMask and not Exp2(01); {$ENDIF}
		{$IFNDEF kdirctry} 	with PCluster(Current)^ do EnableMask := EnableMask and not Exp2(01 or 02); {$ENDIF}

		AddLabel('Start ~V~iew', Current);
		inc(Line,4);

		GrowTo(Size.X,Line);

		{-- Buttons ---}
		InsOKButton(38, Size.Y-5, @InputRecord);
		InsCancelButton(38, Size.Y-3);

		EndInit;

		SetData(InputRecord);
	end;

	Control := Desktop^.ExecView(EditBox);

	{--- set data back into cfg file ----}
	if Control = cmOK then begin
		with InputRecord do with ProgramSetup do begin
			Put(siUserCoyID, N2Str(UserCoyID));

			Put(siCountry, Country);
			Put(siDefaultCurrency, DefCurrency);
			Put(siDefaultVAT, DefVAT);

			PutBoolean(siDeadDataMode, DeadDataMode);

			Put(siNewsFlashInt, N2Str(NewsFlashInt));

			if TerminalNo<>Terminal then begin
				ProgramStatus.SetWhoAtTerminal(TerminalNo,-1);
				{$IFDEF Kusers}
				ProgramStatus.SetWhoAtTerminal(Terminal,CurrentUser^.RecNo);
				{$ELSE}
				ProgramStatus.SetWhoAtTerminal(Terminal,-2);
				{$ENDIF}
				TerminalNo := Terminal;
			end;
			Put(siTerminalNo, N2Str(Terminal));

			PutBoolean(siAutoNew, AutoNew);

			Put(siDefedType, N2Str(DefEditor));

			Put(siStartStdView, N2Str(StartupView));

			ProgramSetup.Store;
		end;

		{update global vars}
		LoadGlobalSetup;
	end;

	dispose(editBox, done);
end;




procedure TekkyEditProgramSetup; far;
var F : FNameStr;
begin
	F := ConfigFileName;

	FileEditor(F, 0, '','', StdBufferSize, hcTekkySetup);

	ProgramSetup.Clear;
	ProgramSetup.Load;

{	if ProgramSetup.Get('TEKKY MODE')='X' then TekkyMode := True else TekkyMode := False;{}
end;








{***************************************************
 ***             EDIT SHORT CODES                ***
 ***************************************************}

procedure EditSCodes; far;
var Menu : PMenu;
		B : byte;
		scType : word;

begin
	{build menu to decide which to select}
	Menu := nil;
	for B := 1 to MaxNumSCodeTypes do
		if SCodeCollection[B]<>nil then
			AddItemEnd(Menu, NewItem(
				'~'+SCodeCollection[B]^.Name^[1]+'~'+Copy(SCodeCollection[B]^.Name^,2,99), '', kbNone, B+1000, hcShortCodes,
			nil));

	{Execute}
	scType := DoPopUpMenu(Menu, Desktop);

	if scType<>0 then
		SCodeCollection[scType-1000]^.ExecuteList(nil);

end;



procedure EditBackupSetup; far;
begin	BackupSetup.Edit; end;


procedure SetDateTime; far;
var EditBox : PEditBox;
		INputRecord : record
			Date : TDate;
			Time : TTime;
		end;
		R : TRect;
		Control : word;

begin
	R.Assign(0,0,25,9);
	New(EditBox, init(R, 'Set System Date & Time', Desktop));

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

		InsTitledField(8,2,10,1, '~D~ate', New(PInputDate, init(R)));
		InsTitledField(8,4, 8,1, '~T~ime', New(PInputTime, init(R,itHMS or itTime)));

		InsOKButton(3,6, @InputRecord);
		InsCancelButton(14,6);

		EndInit;
	end;

	InputRecord.Date.SetToToday;
	InputRecord.Time.SetToNow;

	EditBox^.SetData(InputRecord);

	Control := Desktop^.ExecView(EditbOx);

	if Control<>cmCancel then begin

		with InputRecord do begin
			SetTime(Time.Hour, Time.Min, Time.Sec, Time.S100);
			SetDate(Date.Year, Date.Month, Date.Day);
		end;
	end;

	dispose(EditBox, done);
end;


procedure DoKickOut; far;
begin
	ProgramWarning('Setting Kickout to '+N2Str(TerminalNo), hcNoContext);
	ProgramStatus.SetKickOut(TerminalNo);
end;

procedure UndoKickOut; far;
begin
	PauseMessage('KICKOUT','Clearing Kickout', hcNoContext);
	ProgramStatus.SetKickOut(0);
end;

{************************************************************
 ***          INITIALISATION                              ***
 ************************************************************}

begin
	BackupSetup.Init('Backup/Restore');
	{Setup editing}
	RegisterTask(DesktopTasks, cmEditBackupSetup, @EditBackupSetup);
	RegisterTask(DesktopTasks, cmTekkyEditProgramSetup, @TekkyEditProgramSetup);
	RegisterTask(DesktopTasks, cmEditProgramSetup, @EditProgramSetup);


{{$IFNDEF MSDOS}
	{Wont run in real mode due to lack of memory}
	RegisterTask(DesktopTasks, cmBackup,  @DataBackup);
	RegisterTask(DesktopTasks, cmRestore, @DataRestore);
{{$ENDIF}
	RegisterTask(DesktopTasks, cmSetDateTime, @SetDateTime);
	RegisterTask(DesktopTasks, cmMakeHoles, 	@MakeHolesinAll);
	RegisterTask(DesktopTasks, cmKamDosShell, @DosShell); {remove this to use default application dosshell}
	RegisterTask(DesktopTasks, cmEditScodes, 	@EditScodes);{}
	RegisterTask(DesktopTasks, cmEditForm, 		@EditForm);

	RegisterTask(DesktopTasks, cmKickOut, 		@DoKickOut);
	RegisterTask(DesktopTasks, cmUndoKickOut, @UndoKickOut);

	LastFormFileName := 'LETTER.HDR'; {default!}
end.

