{*******************************************************************
 ***                 AUTO-DIALLER                                ***
 *******************************************************************}
{$I compflgs}
unit AutoDial;

interface

uses scodes;

{--- Telephone number manipulators ---------}

{Removes inappropriate characters}
function CleanTelNum(Tel : string) : string;

{Split multiple numbers (eg 237456/309)}
function SplitTelNums(TelList : string) : string; {returns as a number of lines}

{Convert to standard international format (ie +44 (0)1525 237456)}
function MakeStdTelNum(Tel : string; const TargetCountry : TSCode) : string;

{Check for locality and chop as required}
function MakeLocalTelNum(Tel : string) : string;

{Expand to full string ready to send to modem, eg incl dial	prefix, macros, etc{}
function MakeModemString(Tel : string) : string;

var
	TelErr : word;

const
	teOK 			= 0;
	teFormat 	= 1; {couldn't make it into standard telephone format}

implementation

uses
	setup,
	tuiedit,
	kamsetup,
	help,
	files,
	devices,
	tasks,
	global,
	country,
	objects,
	minilib;

const
	TelChars 		= '1234567890,WP*@T!^;+';
	RHTelChars 	= '1234567890;'; {numbers for checking RH trimming}

function TrimNonNumsL(S : string) : string;
var I : byte;
begin
	I := 1;
	while (I<length(S)) and (pos(S[I], TelChars)=0) do inc(I);
	TrimNonNumsL := Copy(S,I,length(S));
end;

function TrimNonNumsR(S : string) : string;
var I : byte;
begin
	I := length(S);
	while (I>0) and (pos(S[I], RHTelChars)=0) do dec(I);
	TrimNonNumsR := Copy(S,1,I);
end;

function TrimTelNum(S : string) : string;
begin
	TrimTelNum := TrimNonNumsR(TrimNonNumsL(S));
end;

{extracts telephone number suitable for modem (and makestdtelnum) from string,
	ie numbers, W, P, commas, etc}
{Also leaves spaces and slashes in for routines below}
function CleanTelNum;
var	S : string;
		I : byte;
begin
	Tel := TrimTelNum(Tel); {removes more stuff to right, so that "What" after the telephone doesn't leave W...}

	{remove extensions for the purposes of dialling}
	if (pos('x', Tel))>0 then Tel := delspaceR(copy(Tel, 1, pos('x',Tel)-1));

	S := '';
	for I := 1 to length(Tel) do
		if (pos(Tel[I], TelChars+' /')>0) then
			S := S + Tel[I];
	CleanTelNum := delspace(S);
end;



{********************************************************
 ***                  AUTODIAL SETUP                  ***
 ********************************************************}

type
	PDialSetup = ^TDialSetup;
	TDialSetup = object(TSetup)

		ExtLine : string[5];

		DefIntMacro : TSCode; {Dial macros, this is the standard one put
														between the ExtLine (eg 9) and the intl
														code (eg 0044)}
		DefTrunkMacro : TSCode;

		LocalAreaCode : string[10];

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

var
	DialSetup : TDialSetup;

procedure TDialSetup.Load;
begin
	ExtLine 		:= Get('EXTERNAL LINE','');
	DefIntMacro := Get('INT MACRO','');
	DefTrunkMacro := Get('TRUNK MACRO','');
	LocalAreaCode := Get('LOCAL AREA CODE','');
end;

procedure TDialSetup.Store;
begin
	Put('External Line',ExtLine);
	Put('Int Macro',DefIntMacro);
	Put('Trunk Macro',DefTrunkMacro);
	Put('Local Area Code',LocalAreaCode);

	ProgramSetup.Store;
end;

procedure EditDialSetup; far;
begin	DialSetup.Edit; end;


{============ EDIT ======================}
procedure TDialSetup.AddSetupLines;
var R : TRect;
begin
	with EditBox^ do begin
		HelpCtx := hcEditAutoDialSetup;
		GrowTo(45,9);

		InsTitledField(20,  1, 5, 1, 'Ext Line', 			New(PInputELine, init(R, 5)));
		InsTitledField(20,  2,20, 1, 'Internat. Macro', New(PInputSCode, init(R, scDialMacros)));
		InsTitledField(20,  3,20, 1, 'Trunk Macro', New(PInputSCode, init(R, scDialMacros)));
		InsTitledField(20,  4,10, 1, 'Local Area Code', New(PInputELIne, init(R, 10)));
	end;
end;

type
	PDialMacroScodeItem = ^TDialMacroScodeItem;
	TDialMacroScodeItem = object(TScodeItem)
		Macro : PString;
		constructor Init(const NCode, NDesc : string);
		constructor Load(var S : TDataStream);
		procedure Store(var S : TDataStream); virtual;
		function Print(Device : PDeviceStream; prType : word) : word; virtual;
		procedure AddEditFields(P : PObjectEditBox);           virtual;
	end;

{*******************************************************
 ***              SPLIT TEL NUMS                     ***
 *******************************************************}
{Takes a raw telephone number, splits into several as need be.
Assumes the / means that only that number of digits are to be
replaced at the end, eg 237456/309 --> 237456 and 237309}
function SplitTelNums(TelList : string) : string;
var MainTel,SubTel : string;
		Line, Result : string;
		L : byte;
		Comment : string;
begin
	Result := '';
	for L := 1 to NumLines(TelList) do begin
		Line := GetLine(TelList,L);

		{need to remove non numbers from beginning & end}
		Line := TrimNonNumsL(Line);
		Comment := Line; Line := TrimNonNUmsR(Line);
		Comment := delspace(copy(Comment, length(Line)+1,length(Line)));

		if Line<>'' then begin
			MainTel := SplitBy(Line, '/');
			Result := Result + MainTel +' '+Comment+CRLF;

			while Line<>'' do begin
				SubTel := SplitBy(Line, '/');
				Result := Result + Copy(MainTel,1,length(MainTel)-length(SubTel))+SubTel+' '+Comment+CRLF;
			end;
		end;
	end;
	SplitTelNums := TrimCRLF(Result);
end;

{*******************************************************
 ***              MAKE STD TEL NO                    ***
 *******************************************************}
{need to consider following "user" formats:

	2373456 			- local dial code - leave as is
	01525 237456 	- trunk route
	+44 1525 237456 - actual int code
	+44 (0)1525 237456 - already OK int code}


function MakeStdTelNum;
var Result : string;
		CountrySCode : PCountrySCode;
begin
	TelErr := teOK;
	Tel := CleanTelNum(Tel); {removes brackets, extra words, etc}
	MakeStdTelNum := Tel; {in case of errors exiting}
	if Tel='' then exit; {nothing to do}

	if Tel[1] = '+' then begin
		{check to make sure no spaces between + and intl code}
		while (length(Tel)>2) and (Tel[2]=' ') do Delete(Tel, 2,1); {remove spaces}
		if (length(Tel)<5) then begin
			TelErr := teFormat;
			exit;
		end;

		{check to make sure space between intl code and first bracket, if any}
		if pos('(', Tel)>0 then
			if (pos(' ',Tel)=0) or (pos(' ',Tel)>pos('(',Tel)) then
				Insert(' ', Tel, pos('(', Tel));

		{remove international bit}
		Result := SplitByWord(Tel);
	end else begin
		if Copy(Tel,1,3)='(0)' then Tel := '0'+Copy(Tel,4,length(Tel));

		if Tel[1]='0' then begin
			{area code given - add intl code}
			CountrySCode := PCOuntrySCode(GetSCode(scCountries, TargetCountry));
			{use setup country as default}
			if CountrySCode = nil then CountryScode := PCountrySCode(GetSCode(scCountries, ProgramSetup.Get(siCountry,'UK')));
			if CountrySCode<>nil then
				Result := '+'+CountryScode^.TelCode+' '
			else
				Result := '';
		end else
			{no area code given - just local code}
			Result := '';
	end;

	{At this stage, result contains the international code, if available,
	and tel contains the area code (if given) and the local code}

	{-- Check the initial zero - should be removed for intl codes---}
	if (Result<>'') then begin
		if Tel[1]='0' then
			Tel := Copy(Tel,2,length(Tel))
		else
			if Copy(Tel,1,3)='(0)' then
				Tel := Copy(Tel,4,length(Tel));
	end;

	Result := Result + Tel;

	MakeStdTelNum := Result;
end;

{*******************************************************
 ***              MAKE LOCAL TEL NO                  ***
 *******************************************************}
{takes a std phone number and converts to local if poss, might get:

	2373456 			- local dial code - leave as is
	01525 237456 	- trunk route
	+44 1525 237456 - actual int code{}

function MakeLocalTelNum;
var CountrySCode : PCountryScode;
begin
	if Tel[1]='+' then begin
		{International code}
		CountryScode := PCountrySCode(GetScode(scCountries, ProgramSetup.get(siCountry, 'UK')));
		if CountrySCode<>nil then
			if Copy(Tel,2,length(COuntrySCode^.TelCode))=CountryScode^.TelCode then
				Tel := '0'+delspace(Copy(Tel,length(CountryScode^.TelCode)+2,length(Tel))); {add zero back on}
	end;

	if Tel[1]='0' then begin
		{area code}
		if Copy(Tel,1,length(DialSetup.LocalAreaCode))=DialSetup.LocalAreaCode then
			Tel := delspace(Copy(Tel,length(DialSetup.LocalAreaCode)+1,length(Tel)));
	end;

	MakeLocalTelNum := Tel;
end;

{*******************************************************
 ***              MAKE MODEM TEL NO                  ***
 *******************************************************}
{Takes a std telephone number and adds modem codes to make a modem
dial string - not incl predial & postdial of modem, that's already
done}
function MakeModemString;
var DialMacroSCode : PDialMacroScodeItem;
		CountrySCode : PCountrySCode;
begin
	if Tel[1] = '+' then begin
		{-- international call --}
		Tel := Copy(Tel,2,length(Tel));  {chop out plus}

		{add dial-out international access line}
		CountryScode := PCountrySCode(GetScode(scCountries, ProgramSetup.get(siCountry, 'UK')));
		if CountrySCode<>nil then
			Tel := CountryScode^.IntLine+' '+Tel;

		{add international dial macro}
		DialMacroSCode := PDialMacroSCodeItem(GetSCode(scDialMacros, DialSetup.DefIntMacro));
		if DialMacroSCode<>nil then
			Tel := DialMacroSCode^.Macro^+' '+Tel;
	end else
		if Tel[1] = '0' then begin
			{--- Trunk call ---}

			{add trunk dial macro}
			DialMacroSCode := PDialMacroSCodeItem(GetSCode(scDialMacros, DialSetup.DefTrunkMacro));
			if DialMacroSCode<>nil then
				Tel := DialMacroSCode^.Macro^+' '+Tel;

		end;

	{add external line, if reqd}
	MakeModemString := DialSetup.ExtLine+Tel;
end;


{*******************************************
 **         DIAL MACRO CODES              **
 *******************************************}
const
 RDialMacroSCodeItem : TStreamRec = (
	 ObjType : srDialMacroScodeItem;
	 VmtLink : Ofs(TypeOf(TDialMacroScodeItem)^);
	 Load : @TDialMacroScodeItem.Load;
	 Store : @TDialMacroScodeItem.Store
 );


constructor TDialMacroScodeItem.Init;
begin
	inherited Init(NCode, NDesc);
	Macro := NewStr(' ');
end;

constructor TDialMacroScodeItem.Load;
begin
	inherited Load(S);
	Macro := NewStr(S.ReadStr);
end;

procedure TDialMacroScodeItem.Store;
begin
	inherited Store(S);
	S.WriteStr(Macro);
end;

procedure TDialMacroScodeItem.AddEditFields(P : PObjectEditBox);
var R : TRect;
begin
	inherited AddEditFields(P);
	P^.GrowTo(P^.Size.X, P^.Size.Y+1); {make room for below}
	P^.InsTitledField(9,4, 21, 1, 'Macro', New(PInputPStr, init(R,50)));
end;

function TDialMacroScodeItem.Print;
begin
	Device^.writeln('    '+padspaceR(Code,3)
														+'  '+setlength(Description^,30)
														+'  '+setlength(Macro^, 30));
end;

function DialMacroScodeCreator(const NCode, NDesc : string) : PScodeItem; far;
begin
	DialMacroScodeCreator := New(PDialMacroScodeItem, init(NCode, NDesc));
end;




begin
	DialSetup.Init('AutoDial');
	RegisterTask(DesktopTasks, cmEditDialSetup, @EditDialSetup);

	RegisterSCodeType(scDialMacros, 'DialMacr.SC', 'Dial Macros', DialMacroScodeCreator);
	RegisterType(RDialMacroSCodeItem);
end.
