// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): Patricia K. Fasel (Los Alamos Nat. Lab.), 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 <iostream.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <LINK/graph/Vertex.h>
#include <LINK/graph/Edge.h>
#include <LINK/graph/Attribute.h>
#include <LINK/basic/Set.h>
#include <LINK/graph/Graph.h>
//
// constructor and destructor for vertex
//
Vertex::Vertex(Graph* owner) : GraphObject(owner)
{}
Vertex::Vertex(const Vertex &V, Flag clone) : GraphObject(V, clone)
{
  // Since this is a new isolated vertex for the current graph we don't
  // have to add any edges.
  // [ the Vertex isn't added to graph yet -- it's the callers responsibility ]
  if ( ! GraphObject::_graphBeingConstructed ) GraphObject::_owner = V._owner; 
}
Vertex::~Vertex()
{
    _edges.clear();
}
#if 0
Vertex*
Vertex::copy()
{
    return this;
}
#endif
//
// add an incident edge to the vertex
//
void
Vertex::addEdge(Edge* passed_edge)
{
    if (passed_edge->owner() != owner()) {
        error("Vertex::addEdge(Edge*): illegal vertex");
        return;
    }
    _edges.append(passed_edge);
}
//
// remove the incident edge
//
void
Vertex::removeEdge(Edge *passed_edge)
{
    Iterator<Edge*> get_edge(&_edges);
    Edge* edge;
    while (get_edge(edge))
	if (edge == passed_edge) {
	    _edges.remove(edge);
	    break;
	}
}

Set<Vertex*>
Vertex::neighbors() const
{
    return outNeighbors();	// correct for undirected and directed
}
//
// return the set of vertices for which this vertex is the sink
//
Set<Vertex*>
Vertex::inNeighbors() const
{
    Set<Vertex*> return_vertices;
    Iterator<Edge*> get_edge(&_edges);
    Edge* edge;
    while (get_edge(edge)) {
	Set<Vertex*> neighbors = inNeighbors(edge);
        Iterator<Vertex*> get_in_neighbor(&neighbors);
        Vertex* vertex;
        while (get_in_neighbor(vertex))
            if(!return_vertices.memberQ(vertex))
	        return_vertices.insert(vertex);
    }
    return return_vertices;
}
Set<Vertex*>
Vertex::inNeighbors(Edge* passed_edge) const
{
    Set<Vertex*> in_vertices;
    Collection<Vertex*>* vertices = passed_edge->vertices();
    Iterator<Vertex*> get_in_neighbor(vertices);
    //DataType edge_dir = passed_edge->type();
    int undirected = vertices->sortedQ();
    Vertex* vertex;
    if (undirected) {
        while (get_in_neighbor(vertex))
            if ((vertex != this) && (!in_vertices.memberQ(vertex)))
		in_vertices.insert(vertex);
    } else {
        while (get_in_neighbor(vertex) && vertex != this)
            if (!in_vertices.memberQ(vertex))
	        in_vertices.insert(vertex);
        if (vertices->occurrences((class Vertex* const) this) > 1)
	        in_vertices.insert((class Vertex* const) this);
    }
    return in_vertices;
}
//
// return the set of vertices for which this vertex is the source
// Self loops imply that v can be a neighbor of itself. fixed 2/98 JWB
//
Set<Vertex*>
Vertex::outNeighbors() const
{
    Set<Vertex*> return_vertices;
    Iterator<Edge*> get_edge(&_edges);
    Edge* edge;
    while (get_edge(edge)) {
	Set<Vertex*> neighbors = outNeighbors(edge);
        Iterator<Vertex*> get_out_neighbor(&neighbors);
        Vertex* vertex;
        while (get_out_neighbor(vertex))
            if (!return_vertices.memberQ(vertex))
	        return_vertices.insert(vertex);
    }
    return return_vertices;
}
Set<Vertex*>
Vertex::outNeighbors(Edge* passed_edge) const
{
    Set<Vertex*> out_vertices;
    Collection<Vertex*>* vertices = passed_edge->vertices();
    Iterator<Vertex*> get_out_neighbor(vertices);
    //DataType edge_dir = passed_edge->type();
    int undirected = vertices->sortedQ();
    Vertex* vertex;
    if (undirected) {
        while (get_out_neighbor(vertex))
            if ((vertex != this) && (!out_vertices.memberQ(vertex)))
	        out_vertices.insert(vertex);
    } else {
        while (get_out_neighbor(vertex) && vertex != this);
        while (get_out_neighbor(vertex))
            if (!out_vertices.memberQ(vertex))
                out_vertices.insert(vertex);
    }
    return out_vertices;
}

MSet<Edge*>
Vertex::inIncidentEdges() const
{
	return _owner->inIncidentEdges(this);
}

MSet<Edge*>
Vertex::outIncidentEdges() const
{
	return _owner->inIncidentEdges(this);
}

int Vertex::degree() const
{
	return _owner->degree(this);
}

int Vertex::inDegree() const
{
	return _owner->inDegree(this);
}

int Vertex::outDegree() const
{
	return _owner->outDegree(this);
}

Edge*
Vertex::isIncidentEdge(const Collection<Vertex*>& vset) const
{
	Graph *g = owner();
	if (vset.emptyQ())
		return 0;
	MSet<Vertex*> sorted_verts;
	const Collection<Vertex*> *cp;
	if (!g->directedQ()) {
		sorted_verts = vset;
		cp = &sorted_verts;
	} else
		cp = &vset;
		
	Vertex* v1 = cp->first();
	//*********************************************************
	// v1 could conceivably belong to *another graph*
	// if so, find a vertex in *this graph* with the same name
	// for an example use, see animation in Kruskal.cpp
	//*********************************************************
	char *v1_graph_name, *this_graph_name;
	getAttribute((GraphObject*) v1, "graph_name", v1_graph_name);
	getAttribute((GraphObject*) g, "graph_name", this_graph_name);
	if (strcmp(this_graph_name, v1_graph_name) != 0)
		v1 = g->findVertexByName(v1->name());
        MSet<Edge*> v1_edges = v1->incidentEdges();
        Iterator<Edge*> get_edge(&v1_edges);
        Edge *e;
        while (get_edge(e)) {
		Collection<Vertex*>* everts = e->vertices();
		if (*everts == *cp)
                        return e;
	}
        return 0;
}
Edge*
Vertex::isIncidentEdge(Vertex* v1, Vertex* v2) const
{
	Sequence<Vertex*> sq;
	sq.append(v1);
	sq.append(v2);
	return isIncidentEdge(sq);
}
String Vertex::name() const
{
  String nm = GraphObject::name();
  return nm;
//////**********************************************************************
////// the following was a bad hack
////// see compareItems in graphTemplate.cpp and see the operators of Vertex
////// to see how things work now  (if no name specified, don't try to 
////// assign one - leave it null).
//////**********************************************************************
//  if ( nm[0] != 0 ) return nm;
// // else look up index and used it as its name 
// // this hack (for ostream) assumes that the graph has few vertices (say < 55)
//  nm = "[ ]";
//#ifndef __GNUC__
//  nm[1] = 'A' + _owner->vertices().search(this);
//#else
//  // gcc choking on 'this'.
//  Vertex *thisv = this;
//  nm[1] = 'A' + _owner->vertices().search(thisv);
//#endif
//
//return nm;
}
// ??? - JWB
//ostream&
//Vertex::display(ostream& stream) const
//{
//    if (CAST(*this,Vertex).name() == 0)
//    	stream << "<unnamed_vertex>";
//    else
//    	stream << CAST(*this,Vertex).name();
//    return stream;
//}
ostream&
Vertex::display(ostream& stream) const
{
    if (name() == 0)
    	stream << "<unnamed_vertex>";
    else
    	stream << name();
    return stream;
}
//
// save a vertex to an ascii file
//
void
Vertex::saveToFile(ofstream *fout, int indent)
{
    //cout << "*****Saving vertex " << *this << endl;
    char buf[BUFSIZE];
    sprintf(buf, "%*c", indent, ' ');
    *fout << buf << "  " << name();
    GraphObject::saveToFile(fout, indent);
}
//
// Vertex names are strings.  However, the strings usually contain
// only decimal digits.  It is not nice if  "2" > "10," so we test
// to see if the names are indeed integers before doing a strcmp.
//
int compareVertexNames(char *str1, char *str2)
{
	char *res1, *res2;
	int i1 = strtol(str1, &res1, 10);
	int i2 = strtol(str2, &res2, 10);
	if ((strlen(res1)>0) || (strlen(res2)>0))
		return strcmp(str1, str2); // give up; not ints
	return i1 - i2;
}
Bool
Vertex::operator<(const Vertex& obj) const
{       
	if (compareVertexNames(name(), obj.name()) < 0)
              return TRUE;
        else
              return FALSE;
}
Bool
Vertex::operator<=(const Vertex& obj) const
{       
	if (compareVertexNames(name(), obj.name()) <= 0)
                return TRUE;
        else
                return FALSE;
}
Bool
Vertex::operator>(const Vertex& obj) const
{       
	if (compareVertexNames(name(), obj.name()) > 0)
                return TRUE;
        else
                return FALSE;
}
Bool
Vertex::operator>=(const Vertex& obj) const
{       
	if (compareVertexNames(name(), obj.name()) >= 0)
                return TRUE;
        else
                return FALSE;
}
Bool
Vertex::operator==(const Vertex& obj) const
{       
	if (compareVertexNames(name(), obj.name()) == 0)
                return TRUE;
        else
                return FALSE;
}
Bool
Vertex::operator!=(const Vertex& obj) const
{       
	if (compareVertexNames(name(), obj.name()) != 0)
                return TRUE;
        else
                return FALSE;
}
Vertex* Vertex::randomNeighbor() const
{
	Set<Vertex*> out_neighbors = outNeighbors();
	int size = out_neighbors.size();
        if (size == 0)
                return 0;
        int rand_rank = Link_randomLong() % size;
        Vertex *rand_neighbor = out_neighbors.ref(rand_rank);
	return rand_neighbor;
}
