(* Copyright (C) 1994, Digital Equipment Corporation         *)
(* All rights reserved.                                      *)
(* See the file COPYRIGHT for a full description.            *)
(*                                                           *)
(* Last modified on Tue May 24 09:09:59 PDT 1994 by najork   *)
(*      modified on Sat Jul 25 02:03:20 1992 by karsenty     *)

INTERFACE MFGraph;

(***************************************************************************)
(*   Author:  Solange Karsenty						   *)
(***************************************************************************)
(* A graph is an object represented as two lists of vertices and edges.
  Vertices and edges are both objects. They both carry some data (a
  REFANY) that can be used by other modules.

  From a vertex, one can access all the edges connected to it and also
  apply a procedure to all vertex neighbors.
  From an edge, one can access the vertices it connects (from, to). Edges
  are not oriented despite the identifiers.

  Apply methods allow browsing thought the vertices, the edges, or the neighbors
  of a given vertex.
  If the procedure that is passed to apply methods does deletions, it will do
  what you think, IF you delete only through the provided methods.

  Deletions methods are provided at the two levels: graph objects
  and vertices/edges objects. They are exactly the same.

  See test.m3 for as an example.
*)

(* $Revision: 1.1.1.1 $ *)
    
EXCEPTION
  ExitApply;
  MissingVertex;
  NoSuchVertexInGraph;
  NoSuchEdgeInGraph;

TYPE

  T <: TPublic;
  TPublic = OBJECT
    vertices: VertexList;
    edges: EdgeList
  METHODS
    init (): T;
	(* creates a vertex in the graph with data = u *)
    createVertex  (u: REFANY): Vertex ;
	(* delete first all edges connected to that vertex, then deletes
	   the vertex itself *)
    deleteVertex  (n: Vertex) RAISES {NoSuchVertexInGraph} ;
	(* create an edge connecting from and to, with data = u *)
    createEdge (from, to: Vertex; u: REFANY): Edge RAISES {MissingVertex};
	(* delete the edge from the graph. The edge is therefore deleted
	from the vertices' list of edges it belongs to *)
    deleteEdge  (edge: Edge)  RAISES {NoSuchEdgeInGraph};
	(* apply procedure p(arg) to each edge of the graph.
	The procedure can raise an exception ExitApply in order to
	exit from the loop. It returns the last edge that was visited, and
	NIL if all of them were visited *)
    edgeApply (p: Proc; arg: REFANY): Edge ;
	(* same for vertices *)
    vertexApply (p: Proc; arg: REFANY): Vertex ;
  END;

  Proc = PROCEDURE (obj: REFANY; arg: REFANY := NIL);

  Vertex <: TVertexPublic;
  TVertexPublic = OBJECT
    data: REFANY;
    edges: EdgeList;
    myGraph: T;
  METHODS
    init (graph: T): Vertex;
    delete () ;
    applyToNeighbors (p: Proc; arg: REFANY): Vertex;
  END;

  Edge <: TEdgePublic;
  TEdgePublic = OBJECT
    data: REFANY;
    from, to: Vertex;
    myGraph: T;
  METHODS
    init (graph: T): Edge;
	(* given one edge and one of the two edges it connects, returns
	the other vertex *)
    otherVertex (n: Vertex): Vertex ;
    delete () ;
  END;

  VertexList = REF VertexEl;
  VertexEl =  RECORD
    vertex: Vertex;
    next, prev: VertexList
  END;

  EdgeList = REF EdgeEl;
  EdgeEl = RECORD
    edge: Edge;
    next, prev: EdgeList 
  END;


PROCEDURE EdgeDelete(self: Edge) RAISES {};
(* same as DeleteEdge, but applied to an Edge *)

PROCEDURE VertexDelete(self: Vertex) RAISES {};
(* same as DeleteVertex, but applied to a vertex *)

PROCEDURE ApplyToNeighbors(self: Vertex; p: Proc; arg: REFANY): Vertex RAISES {};
(* apply p to all the vertex neighbors of self. p can raise ExitApply to exit 
   returns the last vertex that was visited, NIL if all of them were visited *)

END MFGraph.
