//
// This file is part of MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2015 Richard S. Smith and collaborators.
//
// If you use MorphoGraphX in your work, please cite:
//   http://dx.doi.org/10.7554/eLife.05864
//
// MorphoGraphX is free software, and is licensed under under the terms of the 
// GNU General (GPL) Public License version 2.0, http://www.gnu.org/licenses.
//
#ifndef CIRC_ITERATOR_H
#define CIRC_ITERATOR_H

#include <Config.hpp>

#include <iterator>

namespace mgx {
  /**
   * \class CircIterator CircIterator.hpp <CircIterator.hpp>
   *
   * Creates a circular iterator from a range of forward iterators
   */
  template <typename ForwardIterator> class CircIterator {
  public:
    typedef std::forward_iterator_tag iterator_category;
    typedef typename std::iterator_traits<ForwardIterator>::value_type value_type;
    typedef typename std::iterator_traits<ForwardIterator>::difference_type difference_type;
    typedef typename std::iterator_traits<ForwardIterator>::pointer pointer;
    typedef typename std::iterator_traits<ForwardIterator>::reference reference;
  
    CircIterator() {}
  
    CircIterator(const ForwardIterator& f, const ForwardIterator& l, const ForwardIterator& c)
      : first(f), last(l), init(c), cur(c) {}
  
    CircIterator(const ForwardIterator& f, const ForwardIterator& l)
      : first(f), last(l), init(l), cur(l) {}
  
    CircIterator(const CircIterator& copy)
      : first(copy.first), last(copy.last), init(copy.init), cur(copy.cur) {}
  
    CircIterator& operator++()
    {
      ++cur;
      if(cur == last)
        cur = first;
      if(cur == init)
        cur = last;
      return *this;
    }
  
    CircIterator operator++(int)
    {
      CircIterator temp(*this);
      this->operator++();
      return temp;
    }
  
    reference operator*() {
      return *cur;
    }
    pointer operator->() {
      return cur.operator->();
    }
  
    bool operator==(const ForwardIterator& other) const {
      return cur == other;
    }
  
    bool operator==(const CircIterator& other) const {
      return cur == other.cur;
    }
  
    bool operator!=(const ForwardIterator& other) const {
      return cur != other;
    }
  
    bool operator!=(const CircIterator& other) const {
      return cur != other.cur;
    }
  
    ForwardIterator base() const {
      return cur;
    }
  
  protected:
    ForwardIterator first, last, init, cur;
  };
}
#endif
