// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): 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: 7-Aug-1997
// 
#ifndef Set_CC
#define Set_CC
template <class Item, class Impl>
Set<Item,Impl>::Set(const Set<Item, Impl>& s)
{
    delete store;  // it just got created in MSet()
    store = s.store;
    ((Container<Item>*)store)->incrRefCount();
}
template <class Item, class Impl>
Set<Item,Impl>::Set(const Collection<Item> &col)
{
    Iterator<Item> get_next(&col);
    Item item; 
    while (get_next(item))
	insert(item);
}
template <class Item, class Impl>
Set<Item,Impl>::Set(const Container<Item> &con)
{
    Iterator<Item> get_next(&con);
    Item item; 
    while (get_next(item))
	insert(item);
}
//
// copy one Set Class instance to another
//
template <class Item, class Impl>
Set<Item, Impl>&
Set<Item,Impl>::operator=(const Set<Item,Impl>& s)
{
    if (&s == this)
        return *this;
    ((Container<Item>*)store)->decrRefCount(); 
    if (((Container<Item>*)store)->getRefCount() == 0)
	delete store;
    store = s.store;
    ((Container<Item>*)store)->incrRefCount();
    return *this;
}
template <class Item, class Impl>
Set<Item, Impl>&
Set<Item,Impl>::operator=(const Collection<Item>& c)
{
    if (&c == this)
        return *this;
    newStore();
    Iterator<Item> get_next(&c);
    Item item;
    while (get_next(item))
        insert(item);
    return *this;
}
//
// insert an item to a set if it is not in it yet
//
template <class Item, class Impl>
void
Set<Item, Impl>::insert(const Item e)
{
    if (this->memberQ(e))
    {
	//warning("Item is in the set, can't insert");
	return;
    }
    else
    {
 	newSet(this);
	store->insert(e);
    }
}
//
// insert an item at the end of a set if it is not a member and the 
// order permits this (if not the container's append() method decides
// what is done - typically the element is simply inserted to
// maintain sorted order
//
template <class Item, class Impl>
void
Set<Item, Impl>::append(const Item e)
{
    if (this->memberQ(e))
    {
	//warning("Item is in the set, can't insert");
	return;
    }
    else
    {
 	newSet(this);
	store->append(e);
    }
}
//
// create a new set
//
template <class Item, class Impl>
void
Set<Item,Impl>::newSet(Set<Item,Impl>* s)
{
    Item item; 
    Impl* x = s->store;
    Iterator<Item> get_next(x);
    //if (store->ref_count > 1)  {
    if (((Container<Item>*)store)->getRefCount() > 1)  {
    	newStore();
    	while (get_next(item))
            MSet<Item,Impl>::append(item); //avoid membership tests
	    //insert(item);
    }
}

template <class Item, class Impl>
int
Set<Item, Impl>::occurrences(const Item item) const
{
    if (this->memberQ(item))
	return(1);
    else return(0);
}
template <class Item, class Impl>
Bool
Set<Item, Impl>::permutationQ() const
{
	return 1;
}
//
// display a human-readable representation of the set
//
template <class Item, class Impl>
ostream&
Set<Item,Impl>::display(ostream& os) const
{
    os << "{";    
    Iterator<Item> get_next(this);
    Item i;
    Bool start = FALSE;
    while (get_next(i))
         if (!start) {
                ElementOps<Item>::displayItem(os, i);
                start = TRUE;
         } else {
                os << " ";
                ElementOps<Item>::displayItem(os, i);
	}
    os << "}";    
    return os;
}
#endif
