// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): Patricia K. Fasel (Los Alamos Nat. Lab.), Jonathan Berry,
//	      Chris Burrows (Trenton State College)
//	      Jon Berry (Elon 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: 28-Jun-1999
// 
#include <iostream.h>
#include <LINK/graph/Graph.h>
#include <LINK/graph/UBinGraph.h>
#include <LINK/graph/Vertex.h>
#include <LINK/graph/Attribute.h>
#include <LINK/basic/Sequence.h>
#include <LINK/algorithm/Algorithms.h>
const static int white_mark = 0;
const static int gray_mark  = 1;
const static int black_mark = 2;

#include <fstream.h>

int clockwise_cmp(Vertex* const& u, Vertex*  const& w)
{
	double ux, uy, wx, wy, pvx, pvy, px, py;
	Vertex *p, *gp;
	int retval=0;
	getAttribute((GraphObject*)u, "pred", p);
	getAttribute((GraphObject*)p, "pred", gp);
	getAttribute((GraphObject*)p, "x", px);
	getAttribute((GraphObject*)p, "y", py);
	getAttribute((GraphObject*)u, "x", ux);
	getAttribute((GraphObject*)u, "y", uy);
	getAttribute((GraphObject*)w, "x", wx);
	getAttribute((GraphObject*)w, "y", wy);
	ux = ux - px;  uy = uy - py;
	wx = wx - px;  wy = wy - py;
	if (gp) {
		getAttribute((GraphObject*)p, "par_vec_x", pvx);
		getAttribute((GraphObject*)p, "par_vec_y", pvy);
		int u_ccw_from_p = ((ux*pvy-uy*pvx) < 0);
		int w_ccw_from_p = ((wx*pvy-wy*pvx) < 0);
		if (u_ccw_from_p && !w_ccw_from_p) 
			retval = -1;
		if (!u_ccw_from_p && w_ccw_from_p) 
			retval = 1;
	}
	if (!retval) {
		int u_cw_from_w = ((ux*wy-uy*wx) > 0);
		if (u_cw_from_w)
			retval = -1;
		else 	retval = 1;
	}
	return retval;
}
		
//
// visit all the neighbors of the vertex 
//
static void
HalinDFSvisit(Graph* graph, Vertex* v, Sequence<Vertex*>& result) 
{
    setAttribute((GraphObject*) v, "mark", gray_mark);
    Set<Vertex*> out_neighs = v->outNeighbors();
    List<Vertex*> out_neighs_list;
    Iterator<Vertex*> get_vert1(&out_neighs);
    Vertex* out_neigh;
    double vx, vy, onx, ony;
    while (get_vert1(out_neigh)) {
	int vmark;
	getAttribute((GraphObject*) out_neigh, "mark", vmark);
	if (vmark == white_mark) {
		out_neighs_list.insert(out_neigh);
		setAttribute((GraphObject*)out_neigh, "pred", v);
		getAttribute((GraphObject*) v, "x", vx);
		getAttribute((GraphObject*) v, "y", vy);
		getAttribute((GraphObject*) out_neigh, "x", onx);
		getAttribute((GraphObject*) out_neigh, "y", ony);
		setAttribute((GraphObject*)out_neigh, "par_vec_x", vx-onx);
		setAttribute((GraphObject*)out_neigh, "par_vec_y", vy-ony);
	}
    }
    out_neighs_list.sort(clockwise_cmp);
    Iterator<Vertex*> get_neigh(&out_neighs_list);
    Vertex *adjVertex;
    while (get_neigh(adjVertex)) {
   	HalinDFSvisit(graph, adjVertex, result);
    }
    setAttribute((GraphObject*) v, "mark", black_mark);
    if (graph->degree(v) == 1)
    	result.append(v);
}

static
Sequence<Vertex*>
HalinDepthFirstSearch(Graph* graph)
{
    Sequence<Vertex*> result;
    if (!graph) return result;

    Attribute<double> par_vec_x(graph, "par_vec_x", 0.0);
    Attribute<double> par_vec_y(graph, "par_vec_y", 0.0);
    Iterator<Vertex*> verts(&graph->vertices());
    Vertex* v;
    
    ResetAttributes(graph);
    MSet<Vertex*> vertices = graph->vertices();
    Iterator<Vertex*> get_vertex(&vertices);
    
    while(get_vertex(v)) {
	setAttribute((GraphObject*) v, "mark", white_mark);
	setAttribute((GraphObject*) v, "pred", (Vertex*) 0);
    }
    get_vertex.reset();
    List<Vertex*> vertex_list;
    while(get_vertex(v))
    	vertex_list.append(v);
	
    while(vertex_list.size()) {
    	v = vertex_list.get();
    	int color;
    	getAttribute((GraphObject*) v, "mark", color);
    	if (color == white_mark) {
		HalinDFSvisit(graph, v, result);
    	}
    }
    return result;
}

MUBinGraph *GenHalinGraph(Graph *tree)
{
	MUBinGraph *g = new MUBinGraph(*tree);
	Sequence<Vertex*> leaf_order = HalinDepthFirstSearch(g);
	Iterator<Vertex*> get_leaf(&leaf_order);
	Vertex *first_leaf, *cur_leaf, *next_leaf;
	get_leaf(cur_leaf);
	first_leaf = cur_leaf;
	Set<Vertex*> s;
	Edge *e;
	while (get_leaf(next_leaf)) {
		s.insert(cur_leaf);
		s.insert(next_leaf);
		e = g->addEdge(s);
		setAttribute((GraphObject*)e, "color", "red");
		cur_leaf = next_leaf;
		s.clear();
	}
	s.clear();
	s.insert(first_leaf);
	s.insert(cur_leaf);
	e = g->addEdge(s);
	setAttribute((GraphObject*)e, "color", "red");
	return g;
}
