// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef EIGEN_COREITERATORS_H
#define EIGEN_COREITERATORS_H

namespace Eigen {

/* This file contains the respective InnerIterator definition of the expressions defined in Eigen/Core
 */

namespace internal {

template<typename XprType, typename EvaluatorKind>
class inner_iterator_selector;

}

/** \class InnerIterator
  * \brief An InnerIterator allows to loop over the element of any matrix expression.
  *
  * \warning To be used with care because an evaluator is constructed every time an InnerIterator iterator is constructed.
  *
  * TODO: add a usage example
  */
template<typename XprType>
class InnerIterator
{
  protected:
    typedef internal::inner_iterator_selector<XprType, typename internal::evaluator_traits<XprType>::Kind> IteratorType;
    typedef internal::evaluator<XprType> EvaluatorType;
    typedef typename internal::traits<XprType>::Scalar Scalar;
  public:
    /** Construct an iterator over the \a outerId -th row or column of \a xpr */
    InnerIterator(const XprType &xpr, const Index &outerId)
        : m_eval(xpr), m_iter(m_eval, outerId, xpr.innerSize())
    {}

    /// \returns the value of the current coefficient.
    EIGEN_STRONG_INLINE Scalar
    value() const
    {
        return m_iter.value();
    }
    /** Increment the iterator \c *this to the next non-zero coefficient.
      * Explicit zeros are not skipped over. To skip explicit zeros, see class SparseView
      */
    EIGEN_STRONG_INLINE InnerIterator&
    operator++()
    {
        m_iter.operator++();
        return *this;
    }
    /// \returns the column or row index of the current coefficient.
    EIGEN_STRONG_INLINE Index
    index() const
    {
        return m_iter.index();
    }
    /// \returns the row index of the current coefficient.
    EIGEN_STRONG_INLINE Index
    row() const
    {
        return m_iter.row();
    }
    /// \returns the column index of the current coefficient.
    EIGEN_STRONG_INLINE Index
    col() const
    {
        return m_iter.col();
    }
    /// \returns \c true if the iterator \c *this still references a valid coefficient.
    EIGEN_STRONG_INLINE
    operator bool() const
    {
        return m_iter;
    }

  protected:
    EvaluatorType m_eval;
    IteratorType m_iter;
  private:
    // If you get here, then you're not using the right InnerIterator type, e.g.:
    //   SparseMatrix<double,RowMajor> A;
    //   SparseMatrix<double>::InnerIterator it(A,0);
    template<typename T>
    InnerIterator(const EigenBase<T>&,Index outer);
};

namespace internal {

// Generic inner iterator implementation for dense objects
template<typename XprType>
class inner_iterator_selector<XprType, IndexBased>
{
  protected:
    typedef evaluator<XprType> EvaluatorType;
    typedef typename traits<XprType>::Scalar Scalar;
    enum { IsRowMajor = (XprType::Flags&RowMajorBit)==RowMajorBit };

  public:
    EIGEN_STRONG_INLINE
    inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &innerSize)
        : m_eval(eval), m_inner(0), m_outer(outerId), m_end(innerSize)
    {}

    EIGEN_STRONG_INLINE Scalar
    value() const
    {
        return (IsRowMajor) ? m_eval.coeff(m_outer, m_inner)
               : m_eval.coeff(m_inner, m_outer);
    }

    EIGEN_STRONG_INLINE inner_iterator_selector&
    operator++()
    {
        m_inner++;
        return *this;
    }

    EIGEN_STRONG_INLINE Index
    index() const
    {
        return m_inner;
    }
    inline Index
    row() const
    {
        return IsRowMajor ? m_outer : index();
    }
    inline Index
    col() const
    {
        return IsRowMajor ? index() : m_outer;
    }

    EIGEN_STRONG_INLINE
    operator bool() const
    {
        return m_inner < m_end && m_inner>=0;
    }

  protected:
    const EvaluatorType& m_eval;
    Index m_inner;
    const Index m_outer;
    const Index m_end;
};

// For iterator-based evaluator, inner-iterator is already implemented as
// evaluator<>::InnerIterator
template<typename XprType>
class inner_iterator_selector<XprType, IteratorBased>
    : public evaluator<XprType>::InnerIterator
{
  protected:
    typedef typename evaluator<XprType>::InnerIterator Base;
    typedef evaluator<XprType> EvaluatorType;

  public:
    EIGEN_STRONG_INLINE
    inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &/*innerSize*/)
        : Base(eval, outerId)
    {}
};

} // end namespace internal

} // end namespace Eigen

#endif // EIGEN_COREITERATORS_H
