// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): Chris Burrows (Trenton State College)
// 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: 25-Jun-1997
// 
///////////////////////////////////////////////////////////////////////////
// LINK: Generic Graph Tool and Class Library
//
//      Function name: BreadthSearch(Graph*, char*, Vertex*)
//		       Breadth First Search on a graph
//
//      Synopsis:
//	    Do a breadth first search on a hypergraph or binary graph
//
//      Description:
//	    1. Initialize an ordered search list by choosing an unmarked vertex.
//	    2. If there are no unmarked vertices, we are finished.
//	       Initialize a queue by marking and placing all the
//	       neighbors of the present vertex on the queue.
//	    3. If the queue is empty, choose a new unmarked vertex,
//	       add it to the search list, and return to step 2.
//	       Otherwise, remove a vertex from the queue, add it to
//	       the search list, and mark and place on the queue all
//	       of its unmarked neighbors.
//	    4. Repeat 3.
//
//      Creation: 1993 March 25, Patricia K. Fasel, pkf@lanl.gov
//
//      Routines used: Queue.cpp
//
//      Related files:
//
//      Test suite: none
//
//      User documentation: none
//
//      Development History:
//			08-01-95 berryj@dimacs.rutgers.edu  changed dequeue
//			08-24-95 berryj@dimacs.rutgers.edu  changed dequeue
//					again - this time to conform with
//					the new Deque class
//                      06-24-96 burrows@trenton.edu
//                                      severely altered behavior to conform
//                                      with CLR, 470. now accepts source
//                                      vertex, and spans only reachable
//                                      vertices. animated.
//
//      Testing History:
//
//      Code Review:
//
//      Bugs and Deficiencies:
//
///////////////////////////////////////////////////////////////////////////
#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/Queue.h>
#include <LINK/basic/Sequence.h>
#include <LINK/basic/SortedArray.h>
#include <LINK/algorithm/Algorithms.h>
static char white [] = "white"; 
static char gray [] = "gray"; 
static char black [] = "black"; 
static char edgeType[] = "tree";
static char edgeColor[] = "red";
static char inf_str[] = "-";
//
// mark all neigbors of the passed vertex and add to the passed stack
//
// void
// markNeighbors(Queue<Vertex*>& passed_queue, Vertex* passed_vertex)
// {
//     Set<Vertex*> neighbors = passed_vertex->outNeighbors();
//     Iterator<Vertex*> get_neighbor(&neighbors);
//     Vertex* vertex;
//     while (get_neighbor(vertex)) {
// 	int mark;
// 	getAttribute((GraphObject*) vertex, "mark", mark);
// 	if (mark == 0) {
// 	    setAttribute((GraphObject*) vertex, "mark", 1);
//             passed_queue.enqueue(vertex);
// 	}
//     }
// }
//
// breadth first search returns an ordered sequence of vertices
//
Sequence<Vertex*> 
BreadthFirstSearch(Graph* graph, Vertex *s, char *graph_view)
{
    	Sequence<Vertex*> result;
    	if (!graph)
		return result;

	//stores old graphics values
    	char **vcolor  = new char*[graph->order()];
    	char **vlabel  = new char*[graph->order()];
    	char **ecolor  = new char*[graph->size()];
    	char **elabel  = new char*[graph->size()];
    	int *mark_value = new int[graph->order()];
    	int low;
    	Iterator<Vertex*> verts(&graph->vertices());
    	Iterator<Edge*> edgs(&graph->edges());
    	Vertex* v;
    	Edge* e;
    	int i=0;
    	while (verts(v)) {
		getAttribute((GraphObject*)v, "color", vcolor[i]); 
		getAttribute((GraphObject*)v, "label", vlabel[i]); 
//		animateVertex(v, graph_view, "color", "color", INIT_STEP,
//					(char*)white);
		i++;
    	}

	i = 0;
	verts.reset();
	while(verts(v)) {
		getAttribute((GraphObject*)v, "mark", mark_value[i]);
		i++;
	}
	
    	Iterator<Vertex*> get_vert(&graph->vertices());
    	Vertex *vv;
    	while (get_vert(vv))		
		setAttribute((GraphObject*)vv, "distance", 0);

	i = 0;
    	while (edgs(e)) {
		getAttribute((GraphObject*)e, "color", ecolor[i]); 
		getAttribute((GraphObject*)e, "label", elabel[i]); 
		i++;
    	}

    	// initialize attributes on all vertices
    	ResetAttributes(graph);
    
	i = 0;
	verts.reset();
	while(verts(v)) {
		setAttribute((GraphObject*)v, "mark", mark_value[i]);
		i++;
	}

    	if(graph->order() == 0)
		return result;

    	Vertex** V = graph->vertexStart();
    	if (graph_view) {
    		for (int i=0; i < graph->order(); i++) {
			animateVertex(V[i], graph_view, 
		      	"label", "vertex-label", INIT_STEP, (char*)inf_str);
			animateVertex(V[i], graph_view, 
		      	"color", "color", INIT_STEP, (char*)white);
    		}
    	}
    // ###################################################################
    // ## for edges, the distance attribute is used to record the     ####
    // ## lengths of fundamental cycles.  The vertex "pred" attribute ####
    // ## can be used to retrieve the cycle itself.                   ####
    // ###################################################################
    	Edge *edge;
    	Iterator<Edge*> get_edge(&graph->edges()); 
    	while (get_edge(edge))
		setAttribute((GraphObject*)edge, "distance", 0);

    // get source
    	if (!s)
	 	s = graph->vertex(0);
    // initialize source
    	setAttribute((GraphObject*) s, "distance", 0);
    	setAttribute((GraphObject*) s, "mark", 1);
    	setAttribute((GraphObject*) s, "pred", 0);
    	char *temp;

	if (graph_view) {	 // added by JM on 6/24/99
    		animateVertex(s, graph_view, "color", "color", 
				INIT_STEP, (char*)gray);
    		animateVertex(s, graph_view, "label", "vertex-label", 
				ALG_STEP,(char*)"0");
  	}
 
    	Queue<Vertex*> Q;
    	Q.enqueue(s);
    	while(!Q.emptyQ()) {
		Vertex *u = Q.front();
		int distance;
		getAttribute((GraphObject*) u, "distance", distance);
		distance++;
	//	Set<Vertex*> neighbors = u->outNeighbors();
	//	Iterator<Vertex*> u_neighbor(&neighbors);
	//	Vertex* v;
		Set<Edge*> outEdges = graph->outIncidentEdges(u);
		Iterator<Edge*> getEdge(&outEdges);
		Edge* e;
		while (getEdge(e)) {
	    		Sequence<Vertex*> neighbors = e->otherVertices(u);
	    		Iterator<Vertex*> u_neighbor(&neighbors);
	    		Vertex* v;
	    	// only animate the edge if it gets us somewhere!
	    		int treeEdge = 0;
	    		while(u_neighbor(v)) {
				int mark;
				getAttribute((GraphObject*) v, "mark", mark);
				if(mark == 0) {
					treeEdge = 1;
					setAttribute((GraphObject*) v, 
						"pred", u);
				} else {    // #### record cycle length ####
					int s_v_dist, s_u_dist;
					getAttribute((GraphObject*) u,
						"distance", s_u_dist);
					getAttribute((GraphObject*) v, 
						"distance", s_v_dist);
			// ### cycle length: 1+s_u_dist+s_v_dist #####
					setAttribute((GraphObject*) e,
					   "distance", 1+s_u_dist+s_v_dist);
				}
	    		}
	    		if(treeEdge) {
				if (graph_view) {
					animateEdge(e, graph_view, "color", 
			    		"color", INIT_STEP, (char*)edgeColor);
					animateEdge(e, graph_view, "label", 
			           "edge-label", ALG_STEP, (char*)edgeType);
				}
	    		}
	    		u_neighbor.reset();
	    		while(u_neighbor(v)) {
				int mark;
				getAttribute((GraphObject*) v, "mark", mark);
		
				if (mark == 0) {
		    			setAttribute((GraphObject*) v,
						"mark", 1);
		    			setAttribute((GraphObject*) v, 
						"distance", distance);

					if (graph_view) {
						//added by JM on 6/24/99
		    				animateVertex(v, 
			graph_view, "color", "color", INIT_STEP, (char*) gray);
					}

		    			ostrstream string;
					string << distance << ends; 
		    			temp = string.str();

					if (graph_view) {
						//added by JM on 6/24/99
		    				animateVertex(v, graph_view,
			"label", "vertex-label", ALG_STEP, (char*)temp);
					}

		    		delete[] temp;
		    
		    		Q.enqueue(v);
				}
		
	    		}
		}
		result.append(Q.dequeue());

		if (graph_view) {	//added by JM on 6/24/99
			animateVertex(u, graph_view, "color", "color",
				 ALG_STEP, (char*)black);
		}
    	}

    	verts.reset();
    	edgs.reset();
    	i=0;
    	while (verts(v)) {
		setAttribute((GraphObject*)v, "color", vcolor[i]); 
		setAttribute((GraphObject*)v, "label", vlabel[i]); 
		i++;
    	}

    	i=0;
    	while (edgs(e)) {
		setAttribute((GraphObject*)e, "color", ecolor[i]); 
		setAttribute((GraphObject*)e, "label", elabel[i]); 
		i++;
    	}
	
    	delete [] vcolor;
    	delete [] vlabel;
    	delete [] ecolor;		//added [] 6/28/99
    	delete [] elabel;
	
    	return result;
}
