#!/usr/local/bin/lefty
# This is a graphical user interface for maria(1).
# It requires the lefty interpreter and the dotty*.lefty scripts of GraphViz.
#
# This script was written in 2001 by Marko Mäkelä <msmakela@tcs.hut.fi>,
# and it is in the public domain.  See maria-vis(1) for documentation.
# The "subnet" commands (support for modular state spaces) were added in 2003.

load ('dotty.lefty');
checkpath = function () {
  if (tablesize (dotty) > 0) {
    remove ('checkpath');
  }
  else {
    writeline (2, 'cannot locate the dotty scripts');
    exit ();
  }
};

checkpath ();

monitorfile = function (data) {
  local line;
  if (~data.fd) {
    if (~(line = readline (0))) exit ();
    run (line);
    return 1;
  }
  return dotty.monitorfile (data);
};

maria.init = function () {
  dotty.init ();
  maria.protovt = [
    'name' = 'Maria Browser';
    'type' = 'normal';
    'menus' = [
      'general' = [
	0 = "undo (u)";
	1 = "command (c)";
	2 = "horizontal layout (h)";
	3 = "vertical layout (v)";
	4 = "cancel layout (k)";
	5 = "redraw ( )";
	6 = "save graph as (s)";
	7 = "copy view";
	8 = "clone view";
	9 = "zoom in (Z)";
	10 = "zoom out (z)";
	11 = "quit (q)";
      ];
      'node' = [
	0 = "successors (n)";
	1 = "predecessors (p)";
	2 = "path (P)";
	3 = "delete (d)";
	4 = "Delete (D)";
	5 = "open view (o)";
      ];
      'edge' = [
	0 = "delete (d)";
	1 = "Delete (D)";
	2 = "open view (o)";
      ];
    ];
    'keys' = [
      'general' = [
	'u' = "undo (u)";
	'c' = "command (c)";
	'h' = "horizontal layout (h)";
	'v' = "vertical layout (v)";
	'k' = "cancel layout (k)";
	' ' = "redraw ( )";
	's' = "save graph as (s)";
	'Z' = "zoom in slowly";
	'z' = "zoom out slowly";
	'q' = "quit (q)";
      ];
      'node' = [
	'd' = "delete (d)";
	'D' = "Delete (D)";
	'o' = "open view (o)";
	'n' = "successors (n)";
	'p' = "predecessors (p)";
	'P' = "path (P)";
      ];
      'edge' = [
	'd' = "delete (d)";
	'D' = "Delete (D)";
	'o' = "open view (o)";
      ];
    ];
    'uifuncs' = [
      'closeview' = function (data) {
	maria.gt = null;
	dotty.protovt.normal.uifuncs.closeview (data);
      };
      'keyup' = function (data) {
	maria.gt = dotty.graphs[dotty.views[data.widget].gtid];
	dotty.protovt.normal.uifuncs.keyup (data);
      };
      'rightdown' = function (data) {
	maria.gt = dotty.graphs[dotty.views[data.widget].gtid];
	dotty.protovt.normal.uifuncs.rightdown (data);
      };
      'middledown' = function (data) {
	maria.gt = dotty.graphs[dotty.views[data.widget].gtid];
	if (data.obj.nid >= 0)
	  writeline (1, concat ("subnet ", maria.gt.graph.name, "; visual visual pred ", data.obj.name));
      };
      'leftdown' = function (data) {
	maria.gt = dotty.graphs[dotty.views[data.widget].gtid];
	if (data.obj.nid >= 0)
	  writeline (1, concat ("subnet ", maria.gt.graph.name, "; visual visual succ ", data.obj.name));
      };
      'redraw' = function (data) {
	maria.gt = dotty.graphs[dotty.views[data.widget].gtid];
	dotty.protovt.normal.uifuncs.redraw (data);
      };
    ];
  ];

  maria.protogt = [
    'actions' = [
      'general' = [
	"undo (u)" = function (gt, vt, data) {
	  gt.undo (gt, 1);
	  maria.gt = gt;
	};
	"command (c)" = function (gt, vt, data) {
	  writeline (1, ask ("command"));
	  maria.gt = gt;
	};
	"horizontal layout (h)" = function (gt, vt, data) {
	  gt.graph.graphattr.rankdir = 'LR';
	  gt.layoutgraph (gt);
	  maria.gt = gt;
	};
	"vertical layout (v)" = function (gt, vt, data) {
	  gt.graph.graphattr.rankdir = 'TB';
	  gt.layoutgraph (gt);
	  maria.gt = gt;
	};
	"cancel layout (k)" = function (gt, vt, data) {
	  gt.cancellayout (gt);
	  maria.gt = gt;
	};
	"redraw ( )" = function (gt, vt, data) {
	  gt.redrawgraph (gt, [vt.vtid = vt;]);
	  maria.gt = gt;
	};
	"save graph as (s)" = function (gt, vt, data) {
	  gt.savegraph (gt, null, 'file', 1);
	  maria.gt = gt;
	};
	"copy view" = function (gt, vt, data) {
	  gt = gt.copygraph (gt);
	  gt.createview (gt, vt);
	  maria.gt = gt;
	};
	"clone view" = function (gt, vt, data) {
	  gt.createview (gt, vt);
	  maria.gt = gt;
	};
	"zoom in (Z)" = function (gt, vt, data) {
	  gt.zoom (gt, vt, 0.5, data.pos);
	  maria.gt = gt;
	};
	"zoom out (z)" = function (gt, vt, data) {
	  gt.zoom (gt, vt, 2, data.pos);
	  maria.gt = gt;
	};
	"zoom in slowly" = function (gt, vt, data) {
	  gt.zoom (gt, vt, 0.9, data.pos);
	  maria.gt = gt;
	};
	"zoom out slowly" = function (gt, vt, data) {
	  gt.zoom (gt, vt, 1.1, data.pos);
	  maria.gt = gt;
	};
	"quit (q)" = function (gt, vt, data) {
	  exit ();
	};
      ];
      'node' = [
	"successors (n)" = function (gt, vt, obj, data) {
	  if (obj.nid >= 0)
	    writeline (1, concat ("subnet ", maria.gt.graph.name, "; visual visual succ ", obj.name));
	  maria.gt = gt;
	};
	"predecessors (p)" = function (gt, vt, obj, data) {
	  if (obj.nid >= 0)
	    writeline (1, concat ("subnet ", maria.gt.graph.name, "; visual visual pred ", obj.name));
	  maria.gt = gt;
	};
	"path (P)" = function (gt, vt, obj, data) {
	  if (obj.nid >= 0)
	    writeline (1, concat ("subnet ", maria.gt.graph.name, "; visual visual path ", obj.name));
	  maria.gt = gt;
	};
	"delete (d)" = function (gt, vt, obj, data) {
	  if (obj.eid >= 0)
	    gt.removeedge (gt, obj);
	  else
	    gt.removenode (gt, obj);
	  gt.redrawgraph (gt, gt.views);
	  maria.gt = gt;
	};
	"Delete (D)" = function (gt, vt, obj, data) {
	  gt.removesubtree (gt, obj);
	  gt.redrawgraph (gt, gt.views);
	  maria.gt = gt;
	};
	"open view (o)" = function (gt, vt, obj, data) {
	  local mode;
	  if (obj.nid >= 0)
	    mode = null;
	  else
	    mode = 'support';
	  gt.cut (gt, obj, 'one', mode, 'copy');
	  gt = dotty.protogt.creategraph (maria.protogt);
	  gt.createview (gt, maria.protovt);
	  gt.mergegraph (gt, dotty.clipgt.graph, 0);
	  gt.layoutgraph (gt);
	  maria.gt = gt;
	};
      ];
    ];
  ];

  maria.protogt.actions.edge = maria.protogt.actions.node;
  maria.gt = null;

  dotty.protogt.layoutmode = 'async';
  dotty.mlevel = 0;
  monitor ('on', 0);
};

new = function () {
  maria.gt = dotty.protogt.creategraph (maria.protogt);
  maria.gt.createview (maria.gt, maria.protovt);
  maria.gt.loadgraph (maria.gt, '-', 'file', copy (dotty.protogt.graph), 1);
};

add = function () {
  local gt, nameid, nid, node;
  gt = dotty.protogt.creategraph (maria.protogt);
  if (maria.gt == null) {
    maria.gt = gt;
    gt.createview (gt, maria.protovt);
    gt.loadgraph (gt, '-', 'file', copy (dotty.protogt.graph), 0);
  }
  else {
    gt.loadgraph (gt, '-', 'file', copy (dotty.protogt.graph), 0);
    for (nameid in gt.graph.nodedict) {
      nid = maria.gt.graph.nodedict[nameid];
      if (nid >= 0) {
	node = maria.gt.graph.nodes[nid];
	node.attr = copy (gt.graph.nodes[gt.graph.nodedict[nameid]].attr);
	maria.gt.unpacknodeattr (maria.gt, node);
	nid = -1;
      }
    }
    maria.gt.mergegraph (maria.gt, gt.graph, 0);
  }
  maria.gt.layoutgraph (maria.gt);
};

monitorfile = maria.monitorfile;
maria.init ();
txtview ('off');
