// 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: 31-Jul-1996
// 

#include <string.h>
#include <stdio.h>
#include <iostream.h>
#include <LINK/graph/GraphObject.h>
#include <LINK/graph/Graph.h>
#include <LINK/graph/Vertex.h>
#include <LINK/graph/Edge.h>
#include <LINK/graph/Attribute.h>

Graph* GraphObject::_graphBeingConstructed = (Graph*) 0;

//
// constructor and destructor for GraphObject
//
GraphObject::GraphObject(Graph* passed_owner) : _owner(passed_owner)
{
	_attributes.clear();
}

GraphObject::GraphObject(const GraphObject &G, Flag clone) : 
				_owner(_graphBeingConstructed)
{
    Iterator<AttributeBase*> get_attribute(&G._attributes);
    AttributeBase* attribute;
    while (get_attribute(attribute))
    {
    	if (clone || (strcmp(attribute->name(),"name")==0)) {
		addAttr(attribute->copy());
	}
    }
}

GraphObject::~GraphObject()
{
    // delete all graphics and attributes associated with graph object
    Iterator<AttributeBase*> get_attribute(&_attributes);
    AttributeBase* attribute;
    while (get_attribute(attribute)) {
    	delete attribute;
    }
    _attributes.clear();
}


//
// add an attribute to this graph object
//
void
GraphObject::addAttr(AttributeBase* passed_attribute)
{
    _attributes.append(passed_attribute);
}


//
// remove an attribute from this object
//
void
GraphObject::removeAttr(AttributeBase* passed_attribute)
{
    if (passed_attribute) {
        _attributes.remove(passed_attribute);
    }
}


//
// delete a copied attribute of the given name from a regular GraphObject
//
void
GraphObject::deleteAttr(String passed_name)
{
    AttributeBase* attribute = getAttr(passed_name);
    if (attribute) {
        _attributes.remove(attribute);
        delete attribute;
    }
}


//
// return the named attribute in this GraphObject
//
AttributeBase*
GraphObject::getAttr(String passed_name) const
{
    Iterator<AttributeBase*> get_attribute(&_attributes);
    AttributeBase* attribute;
    while (get_attribute(attribute))
        if (strcmp((char*) attribute->name(), (char*) passed_name) == 0)
            return attribute;
    return 0;
}


//
// return the named attribute in this GraphObject or its parent
//
AttributeBase*
GraphObject::findAttr(String passed_name)
{
    AttributeBase* attribute = getAttr(passed_name);
    if (!attribute)  	// look in parent
	attribute = _owner->getAttr(passed_name);
    if (attribute)
        return attribute;
    else
        return 0;
}


//
// print the list of attributes
//
void
GraphObject::printAttr()
{
    Iterator<AttributeBase*> get_attribute(&_attributes);
    AttributeBase* attribute;
    while (get_attribute(attribute))
	cout << attribute->name() << " " << *attribute << endl;
}


void
GraphObject::printAttr(String passed_name)
{
    Iterator<AttributeBase*> get_attribute(&_attributes);
    AttributeBase* attribute;
    while (get_attribute(attribute)) {
	if (strcmp(attribute->name(), passed_name) == 0)
	    cout << passed_name << attribute << endl;
    }
}


//
// get the name from the attribute list
//
String
GraphObject::name() const
{
    Attribute<String>* attr = (Attribute<String>*) getAttr("name");
    String name;
    if (attr)
        name = attr->value();
    else
	name = "";
    return name;
}


//
// save a graph object to an ascii file
//
void
GraphObject::saveToFile(ofstream *fout, int indent)
{
    char buf[BUFSIZE];
    sprintf(buf, "%*c", indent, ' ');

    Iterator<AttributeBase*> get_attr(&_attributes);
    AttributeBase* attribute;
    *fout << " (";
    while (get_attr(attribute))
	if (strcmp(attribute->name(), "x_subgraph") == 0) {
	    Graph* subgraph;
	    getAttribute(this, "x_subgraph", subgraph);
	    *fout << " " << attribute->name() << "(" << endl;
	    subgraph->saveToFile(fout, indent+4);
	    *fout << buf << "    " << ")";
	} else if (strncmp(attribute->name(), "x_", 2) != 0)
	    *fout << " " << attribute->name() << "(" << *attribute << ")";
    *fout << " )" << endl;
}

//
// these to support SortedList<Vertex*>  SortedList<Edge*>
// use  obj->type() to find out if Edge, compare differently if so
// (this to be done)
//
Bool                 
GraphObject::operator<(const GraphObject& obj)
{
	if (strcmp(this->name(), obj.name()) < 0)
		return TRUE;
	return FALSE;
}

Bool                 
GraphObject::operator>(const GraphObject& obj)
{
	if (strcmp(this->name(), obj.name()) > 0)
		return TRUE;
	return FALSE;
}


Bool                 
GraphObject::operator==(const GraphObject& obj)
{
	if (strcmp(this->name(), obj.name()) == 0)
		return TRUE;
	return FALSE;
}

Bool                 
GraphObject::operator!=(const GraphObject& obj)
{
	return !operator==(obj);
}

ostream& operator<<(ostream& os, const GraphObject& g)
{
	return g.display(os);
}
