MODULE InfoCatalog;
	(* Helmut Zinn  *)
	(* Build the TableofContents *)

	(*  InfoCatalog.CreateTableOfContents *)
	(*  "StdCmds.OpenToolDialog('Info/Rsrc/CreateCatalog', 'Build Reference')" *)

	IMPORT
		DosKeyboard, (* DosSort, *) Files, Fonts, InfoDialog, Ports,
		StdFolds, StdLinks, StdStamps, TextMappers, TextModels, TextRulers, TextViews, Views;

	VAR
		fm: TextMappers.Formatter;
		count: INTEGER;

	PROCEDUREWriteRuler;
		CONST mm = Ports.mm; 	(* universal units *)
		VAR ruler: TextRulers.Ruler;
	BEGIN
		ruler := TextRulers.dir.New(NIL);
		TextRulers.AddTab(ruler, 4 * mm);
		TextRulers.AddTab(ruler, 130 * mm);
		TextRulers.MakeRightTab(ruler);
		TextRulers.AddTab(ruler, 150 * mm);
		TextRulers.MakeRightTab(ruler);
		TextRulers.AddTab(ruler, 165 * mm);
		TextRulers.MakeRightTab(ruler);
		fm.WriteView(ruler)
	END WriteRuler;

	PROCEDURE WriteLink (VAR fm: TextMappers.Formatter; IN path, comment: ARRAY OF CHAR; file: Files.FileInfo);
		VAR cmd: ARRAY 512 OF CHAR;
	BEGIN
		IF file = NIL THEN
			cmd := "InfoCmds.Start('" + path$ + "')";
		ELSE
			IF file.type = "odc" THEN cmd := "InfoCmds.OpenDoc('" ELSE cmd := "InfoCmds.Start('" END;
			cmd := cmd + path$ + '/' + file.name$ + "')";
			fm.WriteTab;
		END;
		fm.WriteView(StdLinks.dir.NewLink(cmd));
		fm.rider.SetAttr(TextModels.NewColor(fm.rider.attr, Ports.blue));
		IF comment$ # '' THEN
			fm.WriteString(comment$)
		ELSIF file = NIL THEN
			fm.WriteString(path$)
		ELSE
			fm.WriteString(file.name$)
		END;
		fm.rider.SetAttr(TextModels.NewColor(fm.rider.attr, Ports.black));
		fm.WriteView(StdLinks.dir.NewLink(""));
		IF file # NIL THEN
			IF InfoDialog.param.listDate THEN
				fm.WriteTab;
				(*
				fm.WriteInt(file.length);
				*)
				fm.WriteTab;
				IF file.modified.day < 10 THEN fm.WriteChar(' ') END;
				fm.WriteInt(file.modified.day);
				fm.WriteString(".");
				IF file.modified.month < 10 THEN fm.WriteChar('0') END;
				fm.WriteInt(file.modified.month);
				fm.WriteString(".");
				fm.WriteInt(file.modified.year);
				fm.WriteTab;
				IF file.modified.hour < 10 THEN fm.WriteChar(' ') END;
				fm.WriteInt(file.modified.hour);
				fm.WriteString(":");
				IF file.modified.minute < 10 THEN fm.WriteChar('0') END;
				fm.WriteInt(file.modified.minute);
				fm.WriteString(":");
				IF file.modified.second < 10 THEN fm.WriteChar('0') END;
				fm.WriteInt(file.modified.second);
			END;
			fm.WriteLn;
		END;
	END WriteLink;

	PROCEDURE WriteHeader (IN note, path, name: ARRAY OF CHAR);
	BEGIN
		fm.rider.SetAttr(TextModels.NewWeight(fm.rider.attr, Fonts.bold));
		WriteLink(fm, path$, name$, NIL);
		fm.rider.SetAttr(TextModels.NewWeight(fm.rider.attr, Fonts.normal));
		fm.WriteString(note);
		fm.WriteLn;
	END WriteHeader;

	PROCEDURE WriteOpenFold (IN path, comment: ARRAY OF CHAR);
		VAR
			mdFold: TextModels.Model;
			fmFold: TextMappers.Formatter;
			fold: StdFolds.Fold;
	BEGIN
		mdFold := TextModels.dir.New();
		fmFold.ConnectTo(mdFold);
		fmFold.WriteString(' [');
		WriteLink(fmFold, path$, comment$, NIL);
		fmFold.WriteString('] ');
		fold := StdFolds.dir.New(StdFolds.expanded, "", mdFold);
		fm.WriteView(fold);
	END WriteOpenFold;

	PROCEDUREWriteCloseFold;
		VAR fold: StdFolds.Fold; len: INTEGER;
	BEGIN
		fold := StdFolds.dir.New(StdFolds.expanded, "", NIL);
		fm.WriteView(fold);
		fold.Flip; 	(* swap long-form text, now between the two fold views, with hidden short-form text *)
		len := fm.rider.Base().Length(); 	(* determine the text carrier's new length *)
		fm.SetPos(len)	(* position the formatter to the end of the text *)
	END WriteCloseFold;

	PROCEDURE ListAllFiles (IN path: ARRAY OF CHAR);
		VAR
			root: Files.Locator; locs: Files.LocInfo; files: Files.FileInfo;
			begFold, endFold: INTEGER;
	BEGIN
		INC(count); InfoDialog.ShowStatus(count, path);
		WriteHeader("", path, "");
		fm.WriteLn;
		(* generate a list of all files *)
		root := Files.dir.This(path);
		files := Files.dir.FileList(root);
		(* DosSort.FileList(files); *)
		WHILE ~DosKeyboard.Break() & (files # NIL) DO
			IF (InfoDialog.param.filter$ = '') OR (InfoDialog.param.filter$ = files.type$) THEN
				WriteLink(fm, path, "", files);
			END;
			files := files.next
		END;
		(* generate list of all locations *)
		root := Files.dir.This(path);
		locs := Files.dir.LocList(root);
		(* DosSort.LocList(locs); *)
		WHILE ~DosKeyboard.Break() & (locs # NIL) DO
			fm.WriteTab;
			IF InfoDialog.param.include THEN
				begFold := fm.Pos();
				fm.WriteLn;
				ListAllFiles(path + locs.name$ + '/');
				fm.WriteLn;
				WriteHeader(" Continue", path, "");
				endFold := fm.Pos();
				(* write the folded part *)
				fm.SetPos(begFold); WriteOpenFold(path$ + locs.name$ + '/', locs.name$);
				fm.SetPos(endFold + 1); fm.WriteTab; WriteCloseFold;
			ELSE
				fm.WriteChar('[');
				WriteLink(fm, path$ + '/' + locs.name$, locs.name$, NIL);
				fm.WriteChar(']');
			END;
			fm.WriteLn;
			locs := locs.next
		END;
	END ListAllFiles;

	PROCEDURE CreateTableOfContents*;
		VAR
			md: TextModels.Model; vw: Views.View;
	BEGIN
		InfoDialog.ProofParam;
		md := TextModels.dir.New();
		fm.ConnectTo(md); fm.SetPos(0);
		count := 0;
		WriteRuler;
		ListAllFiles(InfoDialog.param.source);
		fm.WriteLn; fm.WriteString('Ende. '); fm.WriteView(StdStamps.New()); fm.WriteLn;
		vw := TextViews.dir.New(md);
		Views.OpenView(vw);
		IF DosKeyboard.Break() THEN
			DosKeyboard.ResetBreak;
		ELSE
			(* Aufgabe ausgefhrt *)
		END;
	END CreateTableOfContents;

END InfoCatalog.
