// graph3.C
// ----------------------------------------------------------------
// COMP 290-001: Algorithm Library Design, Lutz Kettner, 01/11/2000
// Graph example illustrating a flexible solution for mutual dependencies 
// between class templates. Implements adjacency lists.
// Note that const-correctness is a difficult issue here and not 
// addressed in this example.
// (only on g++, not on SGI CC)

#include <assert.h>
#include <list.h>

using namespace std;

template <class Refs>
class Node {
public:
    typedef typename Refs::Edge_iterator Edge_iterator;
    typedef list<Edge_iterator>          Edge_list;
    typedef typename Edge_list::iterator iterator;
private:
    Edge_list edges;
public:
    iterator       begin()       { return edges.begin(); }
    iterator       end()         { return edges.end(); }
    void           push_back( Edge_iterator edge) { edges.push_back( edge); }
    // and so on ....
};

template <class Refs>
class Edge {
public:
    typedef typename Refs::Node_iterator Node_iterator;
private:
    Node_iterator m_source;
    Node_iterator m_dest;
public:
    Edge( Node_iterator source, Node_iterator dest)
	: m_source( source), m_dest( dest) {}
    Node_iterator source() const { return m_source; }
    Node_iterator target() const { return m_dest; }
    // and so on ....
};

template < template <class Refs> class T_Node, 
           template <class Refs> class T_Edge>
class Graph {
public:
    typedef Graph< T_Node, T_Edge>       Self;
    typedef T_Node< Self>                Node;
    typedef T_Edge<Self>                 Edge;
    typedef list<Node>                   Node_list;
    typedef list<Edge>                   Edge_list;
    typedef typename Node_list::iterator Node_iterator;
    typedef typename Edge_list::iterator Edge_iterator;
private:
    Node_list nodes;
    Edge_list edges;
public:
    Node_iterator nodes_begin() { return nodes.begin(); }
    Node_iterator nodes_end()   { return nodes.end(); }
    Edge_iterator edges_begin() { return edges.begin(); }
    Edge_iterator edges_end()   { return edges.end(); }
    void          nodes_push_back( const Node& v) { nodes.push_back(v); }
    void          edges_push_back( const Edge& e) { edges.push_back(e); }
};

// to show the flexibility, here is a different Node class,
// adding a color field to the node class from above.
template <class Refs>
class Colored_node : public Node<Refs> {
public:
    int color;
};


// Using two graph types -- one with the Node and Edge from above, and 
// one with the Colored_node -- and create a small graph with two 
// nodes one edge.

int main() {
    {
	// Declaring a graph type with Node and Edge from above:
	typedef Graph< Node, Edge> G;
	typedef G::Node            Node;
	typedef G::Edge            Edge;
	typedef G::Node_iterator   Node_iterator;
	
	G graph;
	graph.nodes_push_back( Node());  // create first node
	graph.nodes_push_back( Node());  // create second node
	Node_iterator v1 = graph.nodes_begin();  // iterator to first node
	Node_iterator v2 = v1;                 
	++v2; // iterator to second node
	
	// create edge with correct node iterators
	graph.edges_push_back( Edge( v1, v2)); 
	
	 // insert edge into both node adjajency lists
	v1->push_back( graph.edges_begin());
	v2->push_back( graph.edges_begin());
    }
    {
        // Declaring a graph type using the modified colored node:
        typedef Graph< Colored_node, Edge> G;
	typedef G::Node            Node;
	typedef G::Edge              Edge;
	typedef G::Node_iterator   Node_iterator;
	
	G graph;
	graph.nodes_push_back( Node());  // create first node
	graph.nodes_push_back( Node());  // create second node
	Node_iterator v1 = graph.nodes_begin();  // iterator to first node
	Node_iterator v2 = v1;                 
	++v2; // iterator to second node
	
	// create edge with correct node iterators
	graph.edges_push_back( Edge( v1, v2)); 
	
	 // insert edge into both node adjajency lists
	v1->push_back( graph.edges_begin());
	v2->push_back( graph.edges_begin());

	// Now we should be able to access the additional color field
	// starting at the edge going to its source node.
	graph.edges_begin()->source()->color = 5;
	
	// The source node was the first node created, so check its color.
	assert( graph.nodes_begin()->color == 5);
    }    
}

// EOF //



