// L-12 MCS 360 Mon 20 Sep 2010 : mcs360_list_iterator.h

/* In this file we give a definition of an iterator for double linked list,
   for inclusion in the file "mcs360_double_list.h". 

Observe the definitions of the begin() and end() methods listed
after the definition of the class.  We could have inserted these
definitions just as well in mcs360_double_list.h, but it is cleaner
to define these methods here. */

#ifndef MCS360_LIST_ITERATOR_H
#define MCS360_LIST_ITERATOR_H

class Iterator
{
   friend class List<T>;

   private:
    
      List<T> *parent; /* refers to the list */

      typename List<T>::Node *current;
      /* pointer to the current node in parent */

      Iterator( List<T> *L, Node *n ) :
         parent(L), current(n) {}

   public:

      T& operator*() const // dereferencing operator
      {
         if(current == NULL)
            throw std::invalid_argument("cannot dereference past end()");
         return current->data;
      }

      Iterator& operator++() // prefix increment operator
      {
         if(current == NULL)
            throw std::invalid_argument("cannot go past end()");
         current = current->next;
      }

      Iterator operator++(int) // postfix increment operator
      {
         Iterator return_value = *this;
         ++(*this);
         return return_value;
      }

      bool operator!=(const Iterator &other)
      {
         return current != other.current;
      }

      void insert(T item)
      // inserts the item before the current node if not at end
      // otherwise appends to the end of the list 
      {
          Node *c = this->current;
          if(c == NULL)
          {
             Node *L = this->parent->last;
             L->next = new Node(item);
             L->next->prev = this->parent->last;
             this->parent->last = L->next;
          }
          else
          {
             Node *L = new Node(item);
             L->next = c;
             L->prev = c->prev;
             c->prev = L;
             L->prev->next = L;
          }
      }

};

Iterator begin()
{
   Iterator r(this,this->first);
   return r;
}

Iterator end()
{
   Iterator r(this,NULL);
   return r;
}

#endif

