// 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-Jul-1997
// 
#ifndef SortedList_CC
#define SortedList_CC

template <class Item>
SortedList<Item>::SortedList(const Container<Item>& l) 
{
    Iterator<Item> getnext(&l);
    Item item;
    while (getnext(item))
	insert(item);
}
template <class Item>
SortedList<Item>::SortedList(const SortedList<Item>& l) 
{
    Iterator<Item> getnext(&l);
    Item item;
    ContainerNode* cn;;
    if (!l.emptyQ()) {
	getnext(item);
	cn = insert(item);
    }
    while (getnext(item)) 
	cn = List<Item>::insertAfter(item, cn);
}
template <class Item>
SortedList<Item>&
SortedList<Item>::operator=(const SortedList<Item>& copy_list)
{
    ContainerNode *cn = ListNode2cn(_first);
    if (this != &copy_list) {
        clear();
        Iterator<Item> get_list(&copy_list);
        Item item;
    	if (!copy_list.emptyQ()) {
		get_list(item);
		cn = insert(item);
    	}
    	while (get_list(item)) 
		cn = List<Item>::insertAfter(item, cn);
    }
    return(*this);
}

template <class Item>
ContainerNode*
SortedList<Item>::prepend(const Item i)
{
    if (!listEnd(_first) && (ElementOps<Item>::compareItems(_first->getItem(),
								 i)<0)) 
    {
	warning("Larger than the first element can't prepend");
	return NULL;
    }
    ListNode<Item>* node = new ListNode<Item>(i);
    if (listEnd(_first))
	_last = node;
    node->setNext(_first);
    _first = node;
    return ListNode2cn(node);
}
//
// append() - insert at end if sorted order is maintained, else call insert()
//
template <class Item>
ContainerNode*
SortedList<Item>::append(const Item passed_item)
{
    if (listEnd(_first)) {
        ListNode<Item>* node = new ListNode<Item>(passed_item);
	node->setNext(_first);
	_first = _last = node;
        return ListNode2cn(node);
    }
    if (ElementOps<Item>::compareItems(_last->getItem(), passed_item) > 0) 
    {
	return insert(passed_item);
    }
    ListNode<Item>* node = new ListNode<Item>(passed_item);
    node->setNext(_last->next());
    _last->setNext(node);
    _last = node;
    return ListNode2cn(node);
}
extern double ListInsertTime;
//
//
//
template <class Item>
ContainerNode*
SortedList<Item>::insert(const Item passed_item)
{
    ListNode<Item>* node = new ListNode<Item>(passed_item);
    ListNode<Item>*prev, *n;
    int f;
    if (listEnd(_first))
    {
	node->setNext(_first);
	_first = _last = node;
    } else if (((f=ElementOps<Item>::compareItems(passed_item, 
					_first->getItem()))==0) || (f<0)){
	node->setNext(_first);
	_first = node;
    } else {
       for (prev=_first,n=prev->next(); !listEnd(prev); 
					prev=prev->next(),n=n->next()) {
    	   if (!listEnd(n)) {
	      if (ElementOps<Item>::compareItems(n->getItem(),passed_item)>0) {
	       		node->setNext(n);
	       		prev->setNext(node);
	       		break;
	      }
	   } else {
	       node->setNext(n);
	       prev->setNext(node);
	       _last = node;
	       break;
	   }
       }
    }
    return ListNode2cn(node);
}
    
//***************************************************************************
// This is here so that SortedList can be used as a Collection implementation
// (need an insertBefore(), but can't allow List::insertBefore() to be called)
//***************************************************************************
template <class Item>
ContainerNode*
SortedList<Item>::insertBefore(const Item passed_item, ContainerNode * in_node)
{
    ListNode<Item>* passed_node = cn2ListNode(in_node);
    if (listEnd(passed_node)) 
    {
	warning("SortedList::insertBefore(): can't insert before null pointer");
        return ListNode2cn(passed_node);
    }
    ListNode<Item>* before_node = (ListNode<Item>*) passed_node;
    ListNode<Item>* node = new ListNode<Item>(passed_item);
   
    if ((_first == before_node) || (listEnd(_first)))  {
      if (listEnd(_first)) {   
		warning("SortedList<Item>::insertBefore() "
			"called on empty list");
		_last = node;
      }
      if (listEnd(before_node)) {
		warning("SortedList<Item>::insertBefore(it,NULL), returning ");
    		return ListNode2cn(before_node);
      }
      if (ElementOps<Item>::compareItems(passed_item, 
					 *(Item*) before_node->info()) > 0) {
		warning("SortedList<Item>::insertBefore(), request for out"
			" of order insertion - returning");
    		return ListNode2cn(before_node);
      }
      node->setNext(_first);
      _first = node; 
      return ListNode2cn(node);
    }
    ListNode<Item>* n;
    for (n = _first; !listEnd(n->next()); n = n->next()) 
	if (n->next() == before_node)
	    break;
    if (ElementOps<Item>::compareItems(passed_item, 
				       *(Item*) before_node->info()) > 0) {
	warning("SortedList<Item>::insertBefore(), request for out"
		" of order insertion - returning");
    	return ListNode2cn(before_node);
    }
    node->setNext(n->next());
    n->setNext(node);
    return ListNode2cn(node);
}
    
template <class Item>
ContainerNode*
SortedList<Item>::insertAfter(const Item passed_item, ContainerNode * in_node)
{
    ListNode<Item>* passed_node = cn2ListNode(in_node);
    if (listEnd(passed_node)) 
    {
	warning("can't insert after a null pointer");
    	return ListNode2cn(passed_node);
    }
    ListNode<Item>* after_node = (ListNode<Item>*) passed_node;
    ListNode<Item>* node = new ListNode<Item>(passed_item);
    if (listEnd(after_node)) {
		warning("SortedList<Item>::insertAfter(it,NULL), returning ");
    		return ListNode2cn(after_node);
    }
    if (ElementOps<Item>::compareItems(passed_item, 
				       *(Item*) after_node->info()) < 0) {
	warning("SortedList<Item>::insertAfter(), request for out"
		" of order insertion - returning");
    	return ListNode2cn(after_node);
    }
    node->setNext(after_node->next());
    after_node->setNext(node);
    if (after_node == _last)
	_last = node;
    return ListNode2cn(node);
}
template <class Item>
Bool
SortedList<Item>::memberQ(const Item& passed_item) const
{
    for (ListNode<Item>* node = _first; !listEnd(node); node = node->next())
    {
        if (ElementOps<Item>::compareItems(passed_item, node->getItem())==0)
            return TRUE;
        if (ElementOps<Item>::compareItems(passed_item, node->getItem())<0)
	    return FALSE; 
    }
    return FALSE;
}
template <class Item>
ContainerNode*
SortedList<Item>::search(const Item& item) const
{
    for (ListNode<Item>* node = _first; !listEnd(node); node = node->next())
    {
        if (ElementOps<Item>::compareItems(item, node->getItem())==0) {
    	    return ListNode2cn(node);
	}
    //*************************************************************
    //** unsure about this part w.r.t. STk.  not sure if SortedList
    //** will be wrapped
    //*************************************************************
        if (ElementOps<Item>::compareItems(item, node->getItem())<0)
	    return NULL;
    }
    return NULL;
    //*************************************************************
}
// scramble is not implemented either.

#endif
