/*
 * Copyright (c) 1999 Johnny C. Lam.
 * All rights reserved.
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.  The author makes no representations
 * about the suitability of this software for any purpose.  It is
 * provided "as is" without express or implied warranty.
 */

#include <iostream>
#include <fstream>
#include <list>
#include <graph>
#include <graphalg>

using namespace std;

class AllVisible {
public:
    bool operator()(const node &n) const {
	return true;
    }
};

class Visible {
public:
    void add(const node &n) { visible.insert(n); }
    bool operator()(const node &n) const {
	return visible.count(n) == 1;
    }
private:
    set<node> visible;
};

int
main ()
{
    typedef stl_graph<int, double> Graph;
    typedef graph_traits<Graph> traits;
    typedef typename traits::node_type node_type;
    typedef typename traits::edge_type edge_type;

    Graph *g;
    
    cout << "Reading graph:" << endl;
    g = new Graph();
    ifstream istr("dijkstra.test");
    istr >> *g;
    istr.close();
    cout << "End reading graph." << endl;
    
    cout << "=======================" << endl;
    cout << *g << endl;
    cout << "=======================" << endl;

    Visible visible;
    int vis[] = { 1, 2, 4,
		5, 7, 8, 9,
		10, 14,
		15, 19,
		22 };
    int vis_size = 12;
    for (int *i = &vis[0]; i != &vis[vis_size]; ++i) {
	visible.add(g->find_node(*i));
    }

    list<edge_type> tree1, tree2, tree3, tree4, tree5;
    node_map<double> dist1, dist2, dist3;
    Dijkstra(*g, g->find_node(1), &dist1, back_inserter(tree1));
    DijkstraSubset(*g, g->find_node(1), AllVisible(), &dist2,
		   back_inserter(tree2));
    DijkstraSubset(*g, g->find_node(1), visible, &dist3,
		   back_inserter(tree3));
    DijkstraSubset(*g, g->find_node(1), visible, back_inserter(tree4));
    Dijkstra(*g, g->find_node(1), back_inserter(tree5));

    cout << "Distances:" << endl;
    for (Graph::node_iterator n = g->n_begin(); n != g->n_end(); ++n) {
	cout << "\t" << g->value(*n)
	     << " :\t" << dist1[*n]
	     << "\t"   << dist2[*n]
	     << "\t"   << dist3[*n]
	     << endl;
    }
    
    list<edge_type>::iterator l;

    cout << "Tree1:" << endl;
    cout << "\t" << "tree1.size() = " << tree1.size() << endl;
    for (l = tree1.begin(); l != tree1.end(); ++l) {
	cout << "\t" << g->value(l->source()); cout.flush();
	cout << " <---(" << g->weight(*l) << ")--- "; cout.flush();
	cout << g->value(l->target()) << endl; cout.flush();
    }

    cout << "Tree2:" << endl;
    cout << "\t" << "tree2.size() = " << tree2.size() << endl;
    for (l = tree2.begin(); l != tree2.end(); ++l) {
	cout << "\t" << g->value(l->source()); cout.flush();
	cout << " <---(" << g->weight(*l) << ")--- "; cout.flush();
	cout << g->value(l->target()) << endl; cout.flush();
    }

    cout << "Tree3:" << endl;
    cout << "\t" << "tree3.size() = " << tree3.size() << endl;
    for (l = tree3.begin(); l != tree3.end(); ++l) {
	cout << "\t" << g->value(l->source()); cout.flush();
	cout << " <---(" << g->weight(*l) << ")--- "; cout.flush();
	cout << g->value(l->target()) << endl; cout.flush();
    }

    delete g;
    
    return 0;
}
