MODULE InfoLinks;

	(*
	-- Create a link list about the contents of a dieretory.
	-- This module is a modified ObxLinks version.
	-- Other samples are
	-- DosListCmds, Epse21ObxModules, Epse21SysModules, S4System & TboxBook
	-- Helmut Zinn 
	--
	--  "InfoLinks.Directory('')"
	--  "InfoLinks.Directory('Archiv/')"
	--
	--  "StdCmds.OpenToolDialog('Dos/Rsrc/ListCmds', '#Dos:List File or Directory')"
	--  "StdCmds.OpenToolDialog('Info/Rsrc/CreateLinks', '#Info:Link Documents')"
	--  "StdCmds.OpenToolDialog('Info/Rsrc/LinkList', '#Info:List Files')" <-- neu nicht fertig
	--
	-- InfoLinks.OpenExternal replace the Dialog.OpenExternal for using BlackBox in Wine
	*)

	IMPORT
		Dialog, DosTextCmds, InfoDialog, InfoCmds,
		Files, Fonts, Ports, StdLinks, StdStamps, Strings,
		TextMappers, TextModels, TextViews, Views;

	CONST
		callXed = FALSE; (* use editor xed or blackbox - utf8 *)
		underline = FALSE;
		cmdLink = "InfoLinks.Directory('";
		cmdExternal = "InfoLinks.OpenExternal('";
		cmdOpen = "InfoCmds.OpenDoc('";
		cmdStart = "InfoCmds.Start('";
		end = "')";

	PROCEDURE WriteLink (VAR fm: TextMappers.Formatter; IN cmd, path, name: ARRAY OF CHAR);
		VAR
			vw: Views.View;
	BEGIN
		vw := StdLinks.dir.NewLink(cmd + path + end);
		fm.WriteView(vw); 	(* insert left link view in text *)
		fm.WriteString(name);
		vw := StdLinks.dir.NewLink("");
		fm.WriteView(vw); 	(* insert right link view in text *)
		fm.WriteLn;
	END WriteLink;

	PROCEDURE PathToLoc (IN path: ARRAY OF CHAR; OUT loc: Files.Locator);
		VAR i, j: INTEGER; ch: CHAR; name: ARRAY 256 OF CHAR;
	BEGIN
		loc := Files.dir.This("");
		IF path # "" THEN
			i := 0; j := 0;
			REPEAT
				ch := path[i]; INC(i);
				IF (ch = "/") OR (ch = 0X) THEN name[j] := 0X; j := 0; loc := loc.This(name)
				ELSE name[j] := ch; INC(j)
				END
			UNTIL (ch = 0X) OR (loc.res # 0)
		END
	END PathToLoc;

	PROCEDURE TruncateTitle (IN str: ARRAY OF CHAR; OUT title: Views.Title);
		VAR s1, s2: Views.Title; n: INTEGER;
	BEGIN
		n := LEN(str$);
		IF n > 63 THEN	
			Strings.Extract(str, 0, 29, s1);
			Strings.Extract(str, n - 29, 29, s2);
			title := s1$ + " ... " + s2$
		ELSE
			title := str$;
		END;
	END TruncateTitle;

	PROCEDURE LastIndexOf (IN this: ARRAY OF CHAR; c: CHAR): INTEGER;
		VAR k, n: INTEGER;
	BEGIN
		n := LEN(this$) - 1;
		FOR k := 0 TO n DO
			IF this[n - k] = c THEN RETURN n - k END
		END;
		RETURN - 1
	END LastIndexOf;

	PROCEDURE GetFilename (IN filename: ARRAY OF CHAR; OUT file: ARRAY OF CHAR);
		VAR pos: INTEGER;
	BEGIN
		pos := LastIndexOf(filename, '.');
		IF pos < 0 THEN
			file := filename$;
		ELSE
			Strings.Extract(filename, 0, pos, file); 	(* before & without . *)
		END;
	END GetFilename;

	PROCEDURE GetExtension (IN filename: ARRAY OF CHAR; OUT extension: ARRAY OF CHAR);
		VAR pos, pos2, pos3: INTEGER;
	BEGIN
		(* Split "filename" into "file" & "extension" *)
		pos := LastIndexOf(filename, '.');
		pos2 := LastIndexOf(filename, '/');
		pos3 := LastIndexOf(filename, '\');
		IF (pos < 0) OR (pos < pos2) OR (pos < pos3) THEN
			extension := "";
		ELSE
			Strings.Extract(filename, pos + 1, LEN(filename$) - pos, extension); 	(* behind  . *)
		END;
	END GetExtension;

	PROCEDURE Directory* (IN path: ARRAY OF CHAR);
		VAR
			tm: TextModels.Model; fm: TextMappers.Formatter; tv: TextViews.View;
			textAttr, headerAttr, linkAttr: TextModels.Attributes;
			loc: Files.Locator; li: Files.LocInfo; fi: Files.FileInfo; 
			fn, cmd: ARRAY 256 OF CHAR; title: Views.Title;
	BEGIN
		ASSERT((path="") OR (path[LEN(path$)-1] = "/"), 100);
		tm := TextModels.dir.New();
		fm.ConnectTo(tm);
		(* text attribute *)
		textAttr := fm.rider.attr;
		textAttr := TextModels.NewTypeface(textAttr, "Calibri");
		textAttr := TextModels.NewSize(textAttr, 12 * Fonts.point);
		(* header attribute *)
		headerAttr := textAttr;
		headerAttr := TextModels.NewWeight(headerAttr, Fonts.bold);
		headerAttr := TextModels.NewSize(headerAttr, 16 * Fonts.point);
		(* link attribute *)
		linkAttr := textAttr;
		linkAttr := TextModels.NewColor(linkAttr, Ports.blue);
		IF underline THEN 
			linkAttr := TextModels.NewStyle(linkAttr, linkAttr.font.style + {Fonts.underline});
		END;
		(* write head line *)
		fm.rider.SetAttr(headerAttr); 	(* change current attributes of formatter *)
		WriteLink(fm, cmdExternal, path, path);
		fm.rider.SetAttr(textAttr); 	(* reset current attributes of formatter *)
		(* list directories *)
		fm.WriteLn;
		fm.WriteString("Directories"); fm.WriteLn;
		(* generate list of all locations *)
		PathToLoc(path, loc);
		li := Files.dir.LocList(loc);
		WHILE li # NIL DO	(* no particular sorting order is guaranteed *)
			fm.rider.SetAttr(linkAttr); 	(* change current attributes of formatter *)
			WriteLink(fm, cmdLink, path + li.name + '/', li.name);
			fm.rider.SetAttr(textAttr); 	(* reset current attributes of formatter *)
			li := li.next
		END;
		(* list files *)
		fm.WriteLn;
		fm.WriteString("Files"); fm.WriteLn;
		(* generate a list of all files *)
		fi := Files.dir.FileList(loc);
		WHILE fi # NIL DO	(* no particular sorting order is guaranteed *)
			IF fi.type = "odc" THEN	(* there is a converter for this file type *)
				GetFilename(fi.name, fn);
				cmd := cmdOpen;
			ELSE
				fn := fi.name$;
				IF Dialog.IsWine() OR Dialog.IsLinux() THEN cmd := cmdExternal ELSE cmd := cmdStart END;
			END;
			fm.rider.SetAttr(linkAttr); 	(* change current attributes of formatter *)
			WriteLink(fm, cmd, path + fn, fn);
			fm.rider.SetAttr(textAttr); 	(* reset current attributes of formatter *)
			fi := fi.next
		END;
		fm.WriteLn;
		fm.WriteString("Ende. "); fm.WriteView(StdStamps.New()); fm.WriteLn;
		(* open the view in Browser mode to show the result *)
		tv := TextViews.dir.New(tm);
		TruncateTitle(path, title);
		Views.OpenAux(tv, title)
	END Directory;

	PROCEDURE CreateLinkList*;
	BEGIN
		InfoDialog.ProofParam;
		Directory(InfoDialog.param.source);
	END CreateLinkList;

	PROCEDURE OpenExternal* (IN filename: ARRAY OF CHAR);
		VAR file, extension: ARRAY 256 OF CHAR; call: INTEGER;
	BEGIN
		IF Dialog.IsWine() THEN
			GetExtension(filename, extension);
			file := filename$;
			Strings.ToLower(extension, extension);
			IF ('A' <= CAP(file[0])) & (CAP(file[0]) <= 'Z') & (file[1] = ':') THEN
				Strings.Extract(file, 2, LEN(file$) - 2, file); (* cut drive letter *)
				file := file;
			END;
			call := 0;
			IF (extension = "odc") THEN call := 1
			ELSIF (extension = "") THEN call := 2
			ELSIF (extension = "htm") OR (extension = "html") THEN call := 3
			ELSIF (extension = "jpg") OR (extension = "png") OR (extension = "bmp") THEN call := 4
			ELSIF (extension = "odt") OR (extension = "doc") OR (extension = "docx") THEN call := 5
			ELSIF (extension = "ods") OR (extension = "xls")  OR (extension = "xlsx") THEN call := 5
			ELSIF (extension = "odp") OR (extension = "ppt")  OR (extension = "pptx") THEN call := 5
			ELSIF (extension = "pdf") THEN call := 6
			ELSIF (extension = "java") THEN call := 9
			ELSIF (extension = "py") THEN call := 7
			ELSIF (extension = "txt") OR (extension = "log") OR (extension = "sh") THEN 
				IF callXed THEN call := 8 (* editor *) ELSE call := 9 (* blackbox - utf8 *) END;
			END;
			CASE call OF
			| 1: InfoCmds.OpenDoc(filename)	(* blackbox - odc *)
			| 2: Dialog.RunExternal('/usr/bin/nemo ' + '"' + file + '"')	(* dateimanager *)
			| 3: Dialog.RunExternal('/usr/bin/brave-browser ' + '"' + file + '"')	(* internet browser *)
			| 4: Dialog.RunExternal('/usr/bin/xviewer ' + '"' + file + '"')	(* picture *)
			| 5: Dialog.RunExternal('/usr/bin/libreoffice ' + '"' + file + '"')	(* libre office *)
			| 6: Dialog.RunExternal('/usr/bin/xreader ' + '"' + file + '"')	(* acrobat *)
			| 7: Dialog.RunExternal('/usr/bin/idle ' + '"' + file + '"')	(* phyton idle *)
			| 8: Dialog.RunExternal('/usr/bin/xed ' + '"' + file + '"')	(* editor xed *)
			| 9: DosTextCmds.OpenDocAs(filename, 'utf8')	(* blackbox - utf8 *)
			ELSE Dialog.OpenExternal(file)
			END;
		ELSE
			Dialog.OpenExternal(filename)
		END;
	END OpenExternal;

END InfoLinks.
