//  list : headerfile for the free standard C++ library
//  
//  Copyright (C) 1999 by the free standard C++ Library Team
//                        see AUTHORS for more details
//
//  Homepage : http://www.inf.fu-berlin.de/~mkrueger/fscl/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either	
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Library General Public License for more details.
//  You should have received a copy of the GNU Library General Public
//  License along with this library; if not, write to the Free
//  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//  version : 0.1 last modified : 17.09.99


#ifndef __CPP_LIST
#define __CPP_LIST

#include <cpp_extensions>
#include <cstddef>
#include <new>

#include <memory>
#include <iterator>
#include <functional>
#include <algorithm>

namespace std {
		

	template <class T, class Allocator = allocator<T> > 
	class list: public virtual generic_container<T, Allocator>
	{
		private:
			Allocator alloc;
			typedef struct node {
				node *next, *prev;				
				T value;
	
				node(T value)
				{
					this->value = value;
				}
				
				~node()
				{
				}
			};
			node *first;
			node *last;

			class list_iterator
			{
				private:
					friend list;
					node *n;
				public:
					typedef T                                   value_type;
					typedef typename Allocator::difference_type difference_type;
					typedef typename Allocator::pointer         pointer;
					typedef typename Allocator::reference       reference;
					typedef bidirectional_iterator_tag          iterator_category;

					list_iterator(node* a) : n(a)
					{
					}

					reference operator*()
					{
						return n->value;
					}

					list_iterator& operator=(T value)
					{
						n->value = value;
						return *this;
					}
	
					list_iterator& operator++()
					{
						n = n->next;
						return *this; 
					}
					
					list_iterator& operator++(int)
					{
						list_iterator *tmp = new list_iterator(n);
						n = n->next;
						return *tmp; 
					}					
					
					list_iterator &operator--()
					{
						n = n->prev;
						return *this; 
					}

					bool operator!=(list_iterator x)
					{
						return n != x.n;
					}
					
					bool operator==(list_iterator x)
					{
						return n == x.n;
					}					
			};
			
		public:
			typedef typename Allocator::reference             reference;
			typedef typename Allocator::const_reference       const_reference;
			typedef typename Allocator::size_type             size_type;
			typedef typename Allocator::difference_type       difference_type;
			typedef T                                         value_type;
			typedef Allocator                                 allocator_type;
			typedef typename Allocator::pointer               pointer;
			typedef typename Allocator::const_pointer         const_pointer;
			typedef list_iterator							  iterator;
			typedef const list_iterator                 	  const_iterator;
			typedef std::reverse_iterator<iterator>           reverse_iterator;
			typedef std::reverse_iterator<const_iterator>     const_reverse_iterator;

			// 23.2.2.1 construct/copy/destroy:
			explicit list(const Allocator& a = Allocator())
			:alloc(a)
			{
				last = first = 0;
			}

			explicit list(size_type n, const T& value = T(), const Allocator& a= Allocator())
			:alloc(a)		
			{
				last = first = 0;
				while (n--)
					push_back(value);
			}

			template <class InputIterator>
			list(InputIterator first, InputIterator last, const Allocator& a= Allocator())
			:alloc(a)			
			{
				last = first = 0;
				while (first!=last) 
					push_back(*first++);
			}

			list(const list<T,Allocator> &x)
			{
				last = first = 0;
				copy(x.begin(), x.end(), back_inserter(*this));
			}

			~list()
			{
				clear();
			}

			list<T,Allocator> &operator=(const list<T,Allocator> &x)
			{ 
				clear();
				copy(x.begin(), x.end(), back_inserter(*this));
				return *this;
			}

			template <class InputIterator>
			void assign(InputIterator first, InputIterator last)
			{
				clear();
				while (first != last)
					push_back(*first++);
			}

			void assign(size_type n, const T& t = T())
			{
				clear();
				first = new node(t);
				first->prev = 0;

				last = first;
				while (n--) {
					last->next = new node(t);
					last->next->prev = last;
					last = last->next;
				}
				last->next = 0;
			}

			allocator_type get_allocator() const
			{
				return alloc;
			}

			// iterators :
			virtual iterator               begin()
			{
				return list_iterator(first);
			}
			virtual const_iterator         begin() const
			{
				return list_iterator(first);
			}
			virtual iterator               end()
			{
				return list_iterator(last);
			}
			virtual const_iterator         end() const
			{
				return list_iterator(last);
			}
			virtual reverse_iterator       rbegin()
			{
				return reverse_iterator(end());
			}
			virtual const_reverse_iterator rbegin() const
			{
				return const_reverse_iterator(end());
			}
			virtual reverse_iterator       rend()
			{
				return reverse_iterator(begin());
			}
			virtual const_reverse_iterator rend() const
			{
				return const_reverse_iterator(begin());
			}
			
			
			// 23.2.2.2 capacity :
			bool      empty() const
			{
				return first == 0;
			}
			
			size_type size() const
			{
				return 0; // TODO
			}
			size_type max_size() const
			{
				return 0; // TODO
			}	
			void      resize(size_type sz, T c = T())
			{             // TODO
			}

			// element access:
			reference       front()
			{
				return first->value;
			}
			const_reference front() const
			{
				return first->value;
			}
			reference       back()
			{
				return last->prev->value;
			}
			const_reference back() const
			{
				return last->prev->value;
			}

			
			// 23.2.2.3 modifiers:
			void push_front(const T& x)
			{
				if (empty()) {
					assign(1, x);
				} else {
					node* tmp = new node(x);
					tmp->prev = 0;
					tmp->next = first;
					first     = tmp;
				}
			}
			void pop_front()
			{
				delete first->value;
				first->next->prev = NULL;
				first = first->next;
			}

			void push_back(const T& x)
			{
				if (empty()) {
					assign(1, x);
				} else {
					node* tmp = new node(x);
					last->value = x;
					last->next = tmp;
					tmp->next = NULL;
					tmp->prev = last;
					last = tmp;
				}
			}
			void pop_back()
			{
				delete last->value;
				last->prev->next = NULL;
				last = last->prev;
			}

			iterator insert(iterator position, const T& x = T())
			{
				node *tmp = new node(x);
				tmp->next = position.n->next;
				tmp->prev = position.n;
				position.n->next->prev = tmp;
				position.n->next = tmp;				
			}

			void     insert(iterator position, size_type n, const T& x)
			{
				while (n--)
					insert(position, x);
			}
			
			template <class InputIterator>
			void insert(iterator position, InputIterator first, InputIterator last)
			{
				while (first != last)
					insert(position++, *first++);
			}

			iterator erase(iterator position)
			{
				if (last == position.n) {
					if (last == first)
						first = position.n->prev;
					last = position.n->prev;
					if (last != 0)
						last->next = 0;
				} else 
				if (first == position.n) {
					first = position.n->next;					
					if (first != 0)
						first->prev = 0;
				} else {
					if (position.n->next != 0)
						position.n->next->prev = position.n->prev;
					if (position.n->prev != 0)
						position.n->prev->next = position.n->next;
				}
				delete position.n;

				return position;
			}			
			iterator erase(iterator first, iterator last)
			{ // TODO : VERIFY / BUGFIX
				while (first != last)
					erase(first++);
				return first;
			}
			
			void swap(list<T,Allocator> &x)
			{
				swap(first, x.first);
				swap(last, x.last);
			}
			
			void clear()
			{
				while (!empty())
					erase(begin());
			}
			
			// 23.2.2.4 list operations:
			void splice(iterator position, list<T,Allocator>& x)
			{ // TODO
			}			
			void splice(iterator position, list<T,Allocator>& x, iterator i)
			{ // TODO
			}			
			void splice(iterator position, list<T,Allocator>& x, iterator first, iterator last)
			{ // TODO
			}


			void remove(const T &value)
			{
				remove_if(bind2nd(equal_to<T>(), value));
			}

			template <class Predicate> 
			void remove_if(Predicate pred)
			{	// TODO : VERIFY / TEST
				iterator first = begin(), last = end();
				while (first != last) {
					if (pred(*first))
						erase(first);
					first ++ ;
				}
				return first;				
			}
	
			void unique()
			{
				unique(equal_to<T>());
			}			
			template <class BinaryPredicate> 
			void unique(BinaryPredicate binary_pred)
			{ // TODO
			}
			
			
			void merge(list<T,Allocator>& x)
			{
				merge(x, equal_to<T>());
			}			
			template <class Compare>
			void merge(list<T,Allocator>& x, Compare comp)
			{ // TODO
			}
			
			
			void sort()
			{
				sort(less<T>());
			}			
			template <class Compare> 
			void sort(Compare comp)
			{ // TODO
			}
			
			void reverse()
			{ // TODO
			}			
	};
	
    template <class T, class Allocator>
	bool operator==(const list<T,Allocator> &x, const list<T,Allocator> &y)
	{
		return x.size() == y.size() && equal(x.begin(),x.end(),y.begin());
	}
	
	template <class T, class Allocator>
	bool operator< (const list<T,Allocator> &x, const list<T,Allocator> &y)
	{
		return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
	}
	
	template <class T, class Allocator>
	bool operator!=(const list<T,Allocator> &x, const list<T,Allocator> &y)
	{
		return !(x == y);
	}
	
	template <class T, class Allocator>
	bool operator> (const list<T,Allocator> &x, const list<T,Allocator> &y)
	{
		return y < x;
	}
	
	template <class T, class Allocator>
	bool operator>=(const list<T,Allocator> &x, const list<T,Allocator> &y)
	{
		return !(x < y);
	}
	
	template <class T, class Allocator>
	bool operator<=(const list<T,Allocator> &x, const list<T,Allocator> &y)
	{
		return !(y < x);
	}
	
	// specialized algorithms:
	template <class T, class Allocator>
	void swap(list<T,Allocator>& x, list<T,Allocator>& y)
	{
		x.swap(y);
	} 
}

#endif
