// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
//               and Elon College, North Carolina 27244
// Author(s): Jonathan Berry
// This software is copyrighted by the DIMACS Center at Rutgers, The State
// University of New Jersey and Elon College, North Carolina.  
// IT IS PROVIDED AS IS, AND THE AUTHORS, DIMACS, AND
// RUTGERS, THE STATE UNIVERSITY OF NEW JERSEY  AND ELON COLLEGE 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/graph/Graph.h>
#include <LINK/graph/Attribute.h>
#include <LINK/algorithm/Algorithms.h>
int EvenDegrees(Graph *g)
{
	Vertex *v;
	Vertex **vs = g->vertexStart();
	int i;
	for (i=0; i<g->order(); i++)
		if (g->degree(vs[i]) % 2 != 0)
			return 0;
	return 1;
}
void HideTrailInG(Graph *g, Graph* gt, Edge* g_edge, Edge* gt_edge, char *gv)
{
	if (!g || !gt || !g_edge || !gt_edge)
		return;
	Collection<Vertex*>* gt_everts = gt_edge->vertices();
	if (gv) {
		Iterator<Vertex*> get_gt_evert(gt_everts);
		Vertex* next_gt_evert;
		while (get_gt_evert(next_gt_evert)) {
			if (gt->degree(next_gt_evert) == 1) {
				Vertex *evert = 
				   g->findVertexByName(next_gt_evert->name());
				animateVertex(evert, gv, "color", "color",
					      INIT_STEP, WHITE);
			}
		}
		animateEdge(g_edge, gv, "color", "color", ALG_STEP, RED);
	}
	gt->deleteEdge(gt_edge);
}
int CheckTrailEdge(Edge *gt_edge, Set<Edge*> bridges, Graph* g_minus_t, 
	      Vertex *gt_place, Edge* g_edge, char *gv)
{
	if (gv && gt_edge) {
		animateEdge(g_edge, gv, "color", "color", ALG_STEP, GREEN,
			    JIGGLE);
		if (bridges.memberQ(gt_edge)) {
			if (g_minus_t->degree(gt_place) == 1)
				animateEdge(g_edge, gv, "width", "width", 
					INIT_STEP, 2, FLASH);
			else {
				animateEdge(g_edge, gv, "width", "width", 
					INIT_STEP, 8, FLASH, 0, 0);
				animateEdge(g_edge, gv, "color", "color", 
					INIT_STEP, BLACK, FLASH, 0, 0);
			}
		}
	}
	if (gt_edge && (!bridges.memberQ(gt_edge) ||
                             g_minus_t->degree(gt_place) == 1)) {
		return 1;
	}
	return 0;
}
Sequence<Edge*> Fleury(Graph *g, char *graph_view)
{
	Sequence<Edge*> result;
	if (!g || g->size() == 0 || !EvenDegrees(g)) 
		return result;
	ResetAttributes(g);
	Graph *g_minus_t = g->copyGraph(CLONE);
	Edge *ge = g->edge(0);
	Edge *gmte = g_minus_t->isEdge(ge);
	HideTrailInG(g, g_minus_t, ge, gmte, graph_view);
	result.insert(ge);
	setAttribute((GraphObject*)ge, "mark",1);
	Vertex *place = ge->sourceVertex();
	Vertex *gt_place = g_minus_t->findVertexByName(place->name());
	while (g_minus_t->size() > 0) {
		Set<Edge*> bridges = Bridges(g_minus_t);
		Edge *ge = result.first();
		Edge *gmte = g_minus_t->isEdge(ge);
		if (place == ge->sourceVertex())
			place = ge->sinkVertex();
		else
			place = ge->sourceVertex();
		gt_place = g_minus_t->findVertexByName(place->name());
		MSet<Edge*> place_edges = place->incidentEdges();
		Iterator<Edge*> get_edge(&place_edges);
		Edge *next_edge;
		while (get_edge(next_edge)) {
			int mark;
			getAttribute((GraphObject*)next_edge, "mark", mark);
			if ((next_edge == ge) || (mark == 1)) {
				continue;
			}
			Edge *gt_next_edge = g_minus_t->isEdge(next_edge);
			if (CheckTrailEdge(gt_next_edge, bridges, g_minus_t, 
				      gt_place, next_edge, graph_view)) {
				result.insert(next_edge);
				setAttribute((GraphObject*)next_edge, "mark",1);
				HideTrailInG(g,g_minus_t, next_edge, 
					     gt_next_edge, graph_view);
				break;
			}
		}
	}
	return result;
}
