MODULE ObxDb;
(**
	project	= "BlackBox"
	organization	= "www.oberon.ch"
	contributors	= "Oberon microsystems"
	version	= "System/Rsrc/About"
	copyright	= "System/Rsrc/About"
	license	= "Docu/BB-License"
	changes	= "
	- YYYYMMDD, nn, ...
	"
	issues	= "
	- ...
	"

**)

	IMPORT Views, TextModels, TextMappers, TextViews, TextControllers;

	CONST
		int = TextMappers.int; string = TextMappers.string; real = TextMappers.real; invalid = TextMappers.invalid;

	TYPE
		Node = POINTER TO RECORD
			next: Node;
			id: INTEGER;
			name: TextMappers.String;
			value: REAL
		END;

	VAR list: Node;

	PROCEDURE Enter (id: INTEGER; name: TextMappers.String; value: REAL);
		VAR n, h, p: Node;
	BEGIN	(* insert a new tuple into the list at its correct position *)
		NEW(n); n.id := id; n.name := name; n.value := value;
		h := list; p := NIL; WHILE (h # NIL) & (h.id <= id) DO p := h; h := h.next END;
		IF p # NIL THEN	(* insert between p and h *)
			p.next := n
		ELSE	(* insert at beginning *)
			list := n
		END;
		n.next := h
	END Enter;

	PROCEDURE EnterData*;
		VAR c: TextControllers.Controller; beg, end: INTEGER;
			s: TextMappers.Scanner; id: INTEGER;
			name: TextMappers.String; value: REAL;
	BEGIN	(* read a text selection and split it into an integer, string, and real field *)
		c := TextControllers.Focus();
		IF (c # NIL) & c.HasSelection() THEN
			c.GetSelection(beg, end);
			s.ConnectTo(c.text); s.SetPos(beg);
			s.Scan;
			WHILE (s.type = TextMappers.int) & (s.Pos() <= end) DO
				IF s.type = int THEN id := s.int; s.Scan ELSE s.type := TextMappers.invalid END;
				IF s.type = string THEN name := s.string; s.Scan ELSE s.type := invalid END;
				IF s.type = real THEN value := SHORT(s.real); s.Scan ELSE s.type := invalid END;
				Enter(id, name, value)	(* enter the new tuple into a global list *)
			END;
			c.SelectAll(FALSE)
		END
	END EnterData;

	PROCEDURE ListData*;
		VAR t: TextModels.Model; n: Node; f: TextMappers.Formatter;
	BEGIN	(* write all entered tuples into a new text *)
		t := TextModels.dir.New();
		f.ConnectTo(t); f.SetPos(0);
		n := list;
		WHILE n # NIL DO
			f.WriteInt(n.id); f.WriteTab; f.WriteString(n.name); f.WriteTab;
			(* WriteRealForm allows to format real numbers in a flexible way, here rounding to two digits after the comma *)
			f.WriteRealForm(n.value, 7, 0, -2, TextModels.digitspace);	(* "-2" indicates 2 digits after comma *)
			f.WriteLn;
			n := n.next
		END;
		Views.OpenView(TextViews.dir.New(t))
	END ListData;

	PROCEDURE Reset*;
	BEGIN	(* release data structure so that garbage collector can reclaim memory *)
		list := NIL
	END Reset;

END ObxDb.
