MODULE InfoMissingLinks;
(* Helmut Zinn  *)
	
	IMPORT
		Strings, Ports, Fonts, StdLinks, TextModels, TextMappers, TextViews, Views;

	CONST
		maxLength = 256;
		linkcommand = 'InfoCmds.Start'; (* Alternativ: linkcommand = 'LibMisc.ShellExecute'; *)
		underline = FALSE;

	TYPE
		DynString = POINTER TO ARRAY OF CHAR;
		FileList = POINTER TO RECORD
			name: DynString;
			count: INTEGER;
			org, ref: BOOLEAN;
			next: FileList
		END;
		DirList* = POINTER TO RECORD
			path: DynString;
			file: FileList;
			next: DirList;
		END;
		DocList* = DirList;

	PROCEDURE MakeDynString (IN s: ARRAY OF CHAR): DynString;
	VAR d: DynString;
	BEGIN
		NEW(d, LEN(s)+1); d^ := s$; 
		RETURN d;
	END MakeDynString;

	PROCEDURE New* (OUT docList: DocList);
	BEGIN
		docList := NIL; 
	END New;

	PROCEDURE Insert* (VAR docList: DocList; IN  path, name: ARRAY OF CHAR; quelle: BOOLEAN);
	VAR 
		dirList: DirList;
		fileList: FileList;
		upath, uname: ARRAY 256 OF CHAR;
	BEGIN
		Strings.ToLower(path$, upath); Strings.ToLower(name$, uname); 
		dirList := docList;
		WHILE (dirList # NIL) & (dirList.path$ # upath$) DO dirList := dirList.next END;
		IF dirList = NIL THEN
			NEW(dirList); 
			dirList.path := MakeDynString(upath$); 
			dirList.file := NIL;
			dirList.next := docList;
			docList := dirList;
		END;
		fileList := dirList.file;
		WHILE (fileList # NIL) & (fileList.name$ # uname$) DO fileList := fileList.next END;
		IF fileList = NIL THEN
			NEW(fileList); 
			fileList.name := MakeDynString(uname$); 
			fileList.count := 0; 
			fileList.org := FALSE;
			fileList.ref := FALSE;
			fileList.next := dirList.file;
			dirList.file := fileList;
		ELSE
			INC(fileList.count)
		END;
		IF quelle THEN fileList.org := TRUE ELSE fileList.ref := TRUE END;
	END Insert;

	PROCEDURE Display* (VAR f: TextMappers.Formatter; (* IN *) docList: DocList);
		VAR
			default, link: TextModels.Attributes;
			cmd, msg: ARRAY 256 OF CHAR;
			dirList: DirList;
			fileList: FileList;
			label: INTEGER; hit: BOOLEAN;
	BEGIN
		f.WriteString('Link missing:'); f.WriteLn; f.WriteLn;
		default := TextModels.dir.attr;
		link := TextModels.NewColor(default, Ports.blue); link := TextModels.NewStyle(link, {Fonts.underline});
		dirList := docList;		
		WHILE  dirList # NIL DO
			label := f.Pos(); hit := FALSE;
			f.WriteTab; f.WriteString(dirList.path$); f.WriteLn;
			fileList := dirList.file;
			WHILE  fileList # NIL DO
(*
				f.WriteString(dirList.path$); f.WriteString(fileList.name$); f.WriteTab; f.WriteInt(fileList.count); f.WriteLn;
*)
				IF (fileList.count = 0) & fileList.org THEN
					cmd := "InfoCmds.OpenDoc('" + dirList.path$ + fileList.name$ + "')";
					msg := fileList.name$;
					f.WriteTab; f.WriteTab; 
					f.WriteView(StdLinks.dir.NewLink(cmd));
					f.rider.SetAttr(link);
					f.WriteString(msg);
					f.rider.SetAttr(default);
					f.WriteView(StdLinks.dir.NewLink(""));
					f.WriteLn;
					hit := TRUE;
				END;
				fileList := fileList.next;
			END;
			IF ~hit THEN f.SetPos(label) END;
			dirList := dirList.next;
		END;
		f.WriteLn; f.WriteString('Link outside:'); f.WriteLn; f.WriteLn;
		default := TextModels.dir.attr;
		link := TextModels.NewColor(default, Ports.blue); link := TextModels.NewStyle(link, {Fonts.underline});
		dirList := docList;		
		WHILE  dirList # NIL DO
			label := f.Pos(); hit := FALSE;
			f.WriteTab; f.WriteString(dirList.path$); f.WriteLn;
			fileList := dirList.file;
			WHILE  fileList # NIL DO
(*
				f.WriteString(dirList.path$); f.WriteString(fileList.name$); f.WriteTab; f.WriteInt(fileList.count); f.WriteLn;
*)
				IF fileList.ref & ~fileList.org THEN
					cmd := "InfoCmds.OpenDoc('" + dirList.path$ + fileList.name$ + "')";
					msg := fileList.name$;
					f.WriteTab; f.WriteTab; 
					f.WriteView(StdLinks.dir.NewLink(cmd));
					f.rider.SetAttr(link);
					f.WriteString(msg);
					f.rider.SetAttr(default);
					f.WriteView(StdLinks.dir.NewLink(""));
					f.WriteLn;
					hit := TRUE;
				END;
				fileList := fileList.next;
			END;
			IF ~hit THEN f.SetPos(label) END;
			dirList := dirList.next;
		END;
	END Display;

	PROCEDURE Test*;
	VAR 
		docList: DocList;
		path, name: ARRAY 256 OF CHAR;
		t: TextModels.Model;
		f: TextMappers.Formatter;
		v: TextViews.View;
	BEGIN
		New(docList);
		path := "Uhl/Epost/"; name := "ep1.odc"; Insert(docList, path, name, TRUE);
		path := "Uhl/Epost/"; name := "ep3.odc"; Insert(docList, path, name, TRUE);
		path := "Uhl/Epost/"; name := "ep2.odc"; Insert(docList, path, name, TRUE);
		path := "Uhl/Epost/"; name := "ep3.odc"; Insert(docList, path, name, FALSE);
		path := "Uhl/Outside/"; name := "ep4.odc"; Insert(docList, path, name, FALSE);
		t := TextModels.dir.New();	(* create a new, empty text *)
		f.ConnectTo(t);	(* connect a formatter to the text *)
		(* Open View in BrowserMode *)
		v := TextViews.dir.New(t);	(* create a new text view for t *)
		Views.OpenAux(v, "Missing Links");
		Display (f, docList);
		t.Delete(f.Pos(), t.Length()); 
	END Test;

END  InfoMissingLinks.Test