/* This software is distributed under the Lesser General Public License */
//
// Attributes.cpp
//
// This file implements the classes
//   GT_List_of_Attributes
//
//------------------------------------------ CVS
//
// CVS Headers -- The following headers are generated by the CVS
// version control system. Note that especially the attribute
// Author is not necessarily the author of the code.
//
// $Source: /home/br/CVS/graphlet/src/gt_base/List_of_Attributes.cpp,v $
// $Author: himsolt $
// $Revision: 1.2 $
// $Date: 1999/03/05 20:44:18 $
// $Locker:  $
// $State: Exp $
//
//------------------------------------------ CVS
//
// (C) University of Passau 1995-1999, graphlet Project
//

#include "Graphlet.h"
#include "GML.h"

#include "List_of_Attributes.h"
#include "Attribute_string.h"  // included for optimization

#include <algorithm>

//////////////////////////////////////////
//
// list<GT_Attribute_Base*> Attributes
//
//////////////////////////////////////////


GT_List_of_Attributes::GT_List_of_Attributes ()
{
}



GT_List_of_Attributes::~GT_List_of_Attributes ()
{
    for(const_iterator it = begin(); it != end(); ++it)
	delete *it;

    clear();
}


//////////////////////////////////////////
//
// Printing
//
//////////////////////////////////////////


void GT_print (ostream& out, const GT_List_of_Attributes* attrs)
{
    out << graphlet->gml->begin_list_delimeter << '\n';
    attrs->print (out);
    out << graphlet->gml->end_list_delimeter << '\n';
}


void GT_List_of_Attributes::print_list_head (ostream& out,
    const GT_Key key)
{
    GT_Attribute_Base::print (out, key);
    out << graphlet->gml->begin_list_delimeter << '\n';	
}


void GT_List_of_Attributes::print (ostream& out) const
{
    for(const_iterator it = begin(); it != end(); ++it)
	out << *it;
}


void GT_List_of_Attributes::print_list_tail (ostream& out)
{
    out << graphlet->gml->end_list_delimeter << '\n';	
}


//
// A bit of optimization: if do_print returns false, the
// attribute should not be printed.
//

bool GT_List_of_Attributes::do_print () const
{
    return !empty();
}



//////////////////////////////////////////
//
// Cloning
//
//////////////////////////////////////////


void GT_List_of_Attributes::copy (const GT_List_of_Attributes* from,
    GT_Copy copy_type)
{
    if (copy_type.is_deep()) {
	
	if (!copy_type.is_update_from_parent()) {
	    for(const_iterator it = from->begin();
		it != from->end(); ++it)
	    {
		push_back ((*it)->clone (copy_type));
	    }
	} else {
	    for(const_iterator it = begin();
		it != end(); ++it)
	    {
		GT_List_of_Attributes* l;
		if ((*it)->value_list(l)) {
		    l->update_from_parent (copy_type);		    
		}
	    }	    
	}
	
    } else {
	this->list<GT_Attribute_Base*>::operator= (*from);
    }
}


GT_List_of_Attributes* GT_List_of_Attributes::clone (GT_Copy type) const
{
    GT_List_of_Attributes* new_list = new GT_List_of_Attributes;
    new_list->copy (this, type);
    return new_list;
}


void GT_List_of_Attributes::update_from_parent (GT_Copy copy_type)
{
    //
}



//////////////////////////////////////////
//
// Search & Find
//
//////////////////////////////////////////


//
// find_type
//

GT_List_of_Attributes::const_iterator
GT_List_of_Attributes::find (const GT_Key key) const
{
    for(const_iterator it = begin(); it != end(); ++it)
	if ((*it)->key() == key) 
	    return it;

    return end();
}	

GT_List_of_Attributes::iterator
GT_List_of_Attributes::find (const GT_Key key)
{
    for(iterator it = begin(); it != end(); ++it)
	if ((*it)->key() == key) 
	    return it;

    return end();
}	

GT_List_of_Attributes::const_iterator
GT_List_of_Attributes::find (const GT_Key key, int& value) const
{
    const_iterator it = find(key);
	
    if (it != end() && (*it)->value_int (value)) {
	return it;
    }

    return end();
}

GT_List_of_Attributes::const_iterator
GT_List_of_Attributes::find (const GT_Key key, bool& value) const
{
    const_iterator it = find(key);
    
    int int_value;
    if (it != end() && (*it)->value_int (int_value)) {
	value = (int_value != 0);
	return it;
    }

    return end();
}


GT_List_of_Attributes::const_iterator
GT_List_of_Attributes::find (const GT_Key key, double& value) const
{
    const_iterator it = find(key);
	
    if (it != end () && (*it)->value_double (value)) {
	return it;
    }

    return end();
}


GT_List_of_Attributes::const_iterator
GT_List_of_Attributes::find (const GT_Key key, string& value) const
{
    const_iterator it = find(key);
	
    if (it != end() && (*it)->value_string (value)) {
	return it;
    }

    return end();
}


GT_List_of_Attributes::const_iterator
GT_List_of_Attributes::find (const GT_Key key, GT_Key& value) const
{
    const_iterator it = find(key);
    
    if (it != end() && (*it)->is_string ()) {
	// This avoids an extra copy
	GT_Attribute_string* attr_string =
	    (GT_Attribute_string*)(*it);
	value = graphlet->keymapper.add (attr_string->value());
	return it;
    }

    return end();
}


GT_List_of_Attributes::const_iterator
GT_List_of_Attributes::find (const GT_Key key,
    GT_List_of_Attributes*& value) const
{
    const_iterator it = find(key);
	
    if (it != end() && (*it)->value_list (value)) {
	return it;
    }

    return end();
}


//
// extract_type
//


bool GT_List_of_Attributes::extract (const GT_Key key, int& value)
{
    iterator it = find(key);
	
    if (it != end() && (*it)->value_int (value)) {
	erase(it);
	return true;
    }

    return false;
}


bool GT_List_of_Attributes::extract (const GT_Key key, bool& value)
{
    iterator it = find(key);
	
    int int_value;
    if (it != end() && (*it)->value_int (int_value)) {
	value = (int_value != 0);
	erase(it);
	return true;
    }

    return false;
}


bool GT_List_of_Attributes::extract (const GT_Key key, double& value)
{
    iterator it = find(key);
	
    if (it != end() && (*it)->value_double (value)) {
	erase(it);
	return true;
    }

    return false;
}


bool GT_List_of_Attributes::extract (const GT_Key key, string& value)
{
    iterator it = find(key);
	
    if (it != end() && (*it)->value_string (value)) {
	erase(it);
	return true;
    }

    return false;
}


bool GT_List_of_Attributes::extract (const GT_Key key, GT_Key& value)
{
    iterator it = find(key);

    if (it != end() && (*it)->is_string ()) {
	// This avoids an extra copy
	value = graphlet->keymapper.add (
	    ((GT_Attribute_string*)(*it))->value());
	erase(it);
	return true;
    }

    return false;
}


bool GT_List_of_Attributes::extract (const GT_Key key,
    GT_List_of_Attributes*& value)
{
    iterator it = find(key);
	
    if (it != end() && (*it)->value_list (value)) {
	erase(it);
	return true;
    }

    return false;
}


//////////////////////////////////////////
//
// Value extraction (generic)
//
// extract is used by derived classes to extract their cached
// data from the list.
//
//////////////////////////////////////////


int GT_List_of_Attributes::extract (GT_List_of_Attributes* /* current_list */,
    string& /* message */)
{
    return GT_OK;
}

