//=======================================================================
// Copyright 2002 Indiana University.
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
//
// This file is part of the Boost Graph Library
//
// You should have received a copy of the License Agreement for the
// Boost Graph Library along with the software; see the file LICENSE.
//
// Permission to modify the code and to distribute modified code is
// granted, provided the text of this NOTICE is retained, a notice that
// the code was modified is included with the above COPYRIGHT NOTICE and
// with the COPYRIGHT NOTICE in the LICENSE file, and that the LICENSE
// file is distributed with the modified code.
//
// LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
// By way of example, but not limitation, Licensor MAKES NO
// REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
// PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS
// OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS
// OR OTHER RIGHTS.
//=======================================================================

#ifndef BOOST_LIST_BASE_HPP
#define BOOST_LIST_BASE_HPP

#include <boost/iterator_adaptors.hpp>

// Perhaps this should go through formal review, and move to <boost/>.

/*
  An alternate interface idea:
    Extend the std::list functionality by creating remove/insert
    functions that do not require the container object!
 */

namespace boost {
  namespace detail {

    //=========================================================================
    // Linked-List Generic Implementation Functions

    template <class Node, class Next>
    inline Node
    slist_insert_after(Node pos, Node x, 
                       Next next)
    {
      next(x) = next(pos);
      next(pos) = x;
      return x;
    }

    // return next(pos) or next(next(pos)) ?
    template <class Node, class Next>
    inline Node
    slist_remove_after(Node pos, 
                       Next next)
    {
      Node n = next(pos);
      next(pos) = next(n);
      return n;
    }

    template <class Node, class Next>
    inline Node
    slist_remove_range(Node before_first, Node last, 
                       Next next)
    {
      next(before_first) = last;
      return last;
    }

    template <class Node, class Next>
    inline Node
    slist_previous(Node head, Node x, Node nil, 
                   Next next)
    {
      while (head != nil && next(head) != x)
        head = next(head);
      return head;
    }

    template<class Node, class Next>
    inline void
    slist_splice_after(Node pos, Node before_first, Node before_last, 
                       Next next)
    {
      if (pos != before_first && pos != before_last) {
        Node first = next(before_first);
        Node after = next(pos);
        next(before_first) = next(before_last);
        next(pos) = first;
        next(before_last) = after;
      }
    }

    template <class Node, class Next>
    inline Node
    slist_reverse(Node node, Node nil, 
                  Next next)
    {
      Node result = node;
      node = next(node);
      next(result) = nil;
      while(node) {
        Node next = next(node);
        next(node) = result;
        result = node;
        node = next;
      }
      return result;
    }

    template <class Node, class Next>
    inline std::size_t
    slist_size(Node head, Node nil, 
               Next next)
    {
      std::size_t s = 0;
      for ( ; head != nil; head = next(head))
        ++s;
      return s;
    }

    template <class Next, class Data>
    class slist_iterator_policies
    {
    public:
      explicit slist_iterator_policies(const Next& n, const Data& d)
        : m_next(n), m_data(d) { }

      template <class Reference, class Node>
      Reference dereference(type<Reference>, const Node& x) const
        { return m_data(x); }

      template <class Node>
      void increment(Node& x) const
        { x = m_next(x); }

      template <class Node>
      bool equal(Node& x, Node& y) const
        { return x == y; }

    protected:
      Next m_next;
      Data m_data;
    };

  //===========================================================================
  // Doubly-Linked List Generic Implementation Functions

    template <class Node, class Next, class Prev>
    inline void
    dlist_insert_before(Node pos, Node x, 
                        Next next, Prev prev)
    {
      next(x) = pos;
      prev(x) = prev(pos);
      next(prev(pos)) = x;
      prev(pos) = x;
    }

    template <class Node, class Next, class Prev>
    void
    dlist_remove(Node pos, 
                 Next next, Prev prev)
    {
      Node next_node = next(pos);
      Node prev_node = prev(pos);
      next(prev_node) = next_node;
      prev(next_node) = prev_node;
    }

    // This deletes every node in the list except the
    // sentinel node.
    template <class Node, class Delete>
    inline void
    dlist_clear(Node sentinel, Delete del)
    {
      Node i, tmp;
      i = next(sentinel);
      while (i != sentinel) {
        tmp = i;
        i = next(i);
        del(tmp);
      }
    }
    
    template <class Node>
    inline bool
    dlist_empty(Node dummy)
    {
      return next(dummy) == dummy;
    }

    template <class Node, class Next, class Prev>  
    void
    dlist_transfer(Node pos, Node first, Node last, 
                   Next next, Prev prev)
    {
      if (pos != last) {
        // Remove [first,last) from its old position
        next(prev(last)) = pos;
        next(prev(first)) = last;
        next(prev(pos)) = first;

        // Splice [first,last) into its new position
        Node tmp = prev(pos);
        prev(pos) = prev(last);
        prev(last) = prev(first);
        prev(first) = tmp;
      }
    }  

    template <class Next, class Prev, class Data>
    class dlist_iterator_policies
      : public slist_iterator_policies<Next, Data>
    {
      typedef slist_iterator_policies<Next, Data> Base;
    public:
      template <class Node>
      void decrement(Node& x) const
        { x = m_prev(x); }

      dlist_iterator_policies(Next n, Prev p, Data d) 
        : Base(n,d), m_prev(p) { }
    protected:
      Prev m_prev;
    };

  } // namespace detail
} // namespace boost

#endif // BOOST_LIST_BASE_HPP
