// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
//                    Elon College
// Author(s): Damon Desonier (Elon College), Jonathan Berry
 
// This software is copyrighted by the DIMACS Center at Rutgers, The State
// University of New Jersey.  IT IS PROVIDED AS IS, AND THE AUTHORS, DIMACS, AND
// RUTGERS, THE STATE UNIVERSITY OF NEW JERSEY  DISCLAIM
// ALL LIABILITY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
// DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
 
// THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
// IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
// NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
// MODIFICATIONS.
 
// The authors hereby grant permission to use, copy, modify, distribute,
// and license this software and its documentation for any purpose, provided
// that existing copyright notices are retained in all copies and that this
// notice is included verbatim in any distributions. No written agreement,
// license, or royalty fee is required for any of the authorized uses.
// Modifications to this software may be copyrighted by their authors
// and need not follow the licensing terms described here, provided that
// the new terms are clearly indicated on the first page of each file where
// they apply.
 
// Last File Update: 21-Feb-1998
//
#include <LINK/generator/Generators.h>
#include <stdio.h>
#include <strstream.h>
#include <LINK/graph/Graph.h>
#include <LINK/graph/Vertex.h>
#include <LINK/graph/Edge.h>
#include <LINK/graph/Attribute.h>
#include <LINK/basic/Set.h>
#include <LINK/basic/DJSet.h>
#include <LINK/basic/BinaryHeap.h>
#include <LINK/algorithm/Algorithms.h>
Set<Edge*>
Prim(Graph* graph, char* graph_view, Vertex* s )
{
	if (!s)
		s = graph->vertex(0);
	ResetAttributes(graph);
  
	ContainerNode* heapPtr;
	Set<Edge*> result;
	if(graph->order() == 0)
		return result;
	int order = graph->order();
	BinaryHeap<double,Vertex*> heap(order);
	Set<Vertex*> vertices = graph->vertices();
	vertices.remove(s);
	
	heapPtr = heap.insert(-1, s);
	setAttribute((GraphObject*) s ,"heap_info", heapPtr);
	setAttribute((GraphObject*) s, "pred", s); 
	Iterator<Vertex*> get_vertex(&vertices);
	Vertex* vertex;
	char inf_str[] = "-";
	//   intialize graph V-{s} with key MAX_INT
	while(get_vertex(vertex))
	{
		heapPtr = heap.insert(MAX_INT, vertex);
		setAttribute((GraphObject*) vertex, "heap_info", heapPtr);	
		setAttribute((GraphObject*) vertex, "pred", (Vertex*)0);	
		if (graph_view) {
			animateVertex(vertex, graph_view, "color","color",
					      INIT_STEP, (char *)"white");
			animateVertex(vertex, graph_view, "label",
				"vertex-label", INIT_STEP, (char*)inf_str);
		}
	}
    	const MSet<Edge*>& edges = graph->edges();
    	Iterator<Edge*> get_edge(&edges);
	Edge *edge;
    	while (get_edge(edge)) {
        	double weight;
        	getAttribute((GraphObject*) edge, "weight", weight);
		setAttribute((GraphObject*) edge, "mark", 0);
		if (graph_view) {
			ostrstream oss;
			char *wgt;
			oss << weight << ends;
			wgt = oss.str();
    			animateEdge(edge, graph_view, "label", 
					      "edge-label", INIT_STEP, wgt,
					      FLASH, 0, 0);
		// LEAK! must incorporate LINK_DYNAMIC
		}
    	}
	Set<Edge*> light_edges;
	while(!heap.emptyQ())
	{
		Vertex *v, *pred;
		BinaryHeapNode<double, Vertex*>* heap_node = heap.extractMin();
		v = heap_node->item;
		if (graph_view) { 
			animateVertex(v, graph_view, "color","color",
					      INIT_STEP, (char *)"black",
					      JIGGLE, 10, 10);
		}
		getAttribute((GraphObject*)v, "pred", pred);
		if (pred && pred != v) {
			Edge *e = graph->isEdge(pred, v);
			if (e) {
				setAttribute((GraphObject*)e, "mark", 1);
				result.insert(e);
				if (graph_view)
					animateEdge(e, graph_view, 
						"color",
						"color", INIT_STEP, RED, FLASH,
						5, 5);
			}
		}
		Set<Vertex*> neighbors = v->neighbors();
		Iterator<Vertex*> get_vertex_edge(&neighbors);
		double edge_weight;
		Edge* edge;
		Vertex* vertex1;
		char *temp;
		double light_edge;
		int width;
		while(get_vertex_edge(vertex1))
		{
			edge = graph->isEdge(v,vertex1);
			getAttribute((GraphObject*) edge, "weight",
				 edge_weight);
			getAttribute((GraphObject*) vertex1, "heap_info",
				 heapPtr);
			if (graph_view) {
				BinaryHeapNode<double, Vertex*>* n = 
						heap.minimum();
				light_edge  = n->key;
			}
			if (heap.memberQ(vertex1) && 
			     edge_weight < 
				((BinaryHeapNode<double,Vertex*>*)heapPtr)->key)
			{
				heap.decreaseKey(heapPtr, edge_weight);
				setAttribute((GraphObject*) vertex1, "pred", v);
				if (graph_view) {
					getAttribute((GraphObject*) edge, 
						"width", width);
					animateEdge(edge, graph_view, "width",
						"width", INIT_STEP, width,
						JIGGLE, 5, 10);
					ostrstream oss; oss<<edge_weight<<ends;
					temp = oss.str();
					animateVertex(vertex1, graph_view, 
						"label",
						"vertex-label",INIT_STEP, temp,
						JIGGLE, 0, 0);
					if (edge_weight <= light_edge) {
						light_edge = edge_weight;
					}
				}
			}
		}
		if (graph_view) {
			Iterator<Vertex*> get_vert(&heap);
			Vertex *v, *pred;
			double weight;
			Iterator<Edge*> get_light_edge(&light_edges);
			Edge *e;
			int mark;
			while (get_light_edge(e)) {
				getAttribute((GraphObject*)e, "mark", mark);
				if (!mark)
				   animateEdge(e, graph_view, "color",
					"color",INIT_STEP, BLACK,
					JIGGLE, 0, 0);
			}
			light_edges.clear();
			while (get_vert(v)) {
				getAttribute((GraphObject*)v, "pred", pred);
				if (pred) {
				    if ((e=graph->isEdge(pred, v))){
					getAttribute((GraphObject*)e,
						"weight", weight);
				 	if (weight <= light_edge) 
						light_edges.insert(e);
				    }
				}
			}
			get_light_edge.reset();
			while (get_light_edge(e)) {
				animateEdge(e, graph_view, 
					"color",
					"color",INIT_STEP, GREEN,
					JIGGLE, 0, 0);
			}
		}
		animateVertex(v, graph_view, "color","color",
				      ALG_STEP, (char *)"black",
				      JIGGLE, 0, 0);
	}
	return result; 
}
