/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2014/01/20
/// 
/// @brief  イテレータ関連
/// 
/// ****************************************************************************

#pragma once

#include "../Base/CPL_Core_Basic.h"
#include "../Memory/CPL_Core_Allocator.h"


namespace CPL {
namespace Core {
namespace Itr {



// _____________________________________________________________________________
/// @brief イテレータ基底クラス
///
/// @tparam T_Pointer    : ポインタ型を指定。
/// @tparam T_Iterator   : 最派生クラスを指定。
/// @tparam N_AccessOffs : 通常のイテレータでは0, 逆イテレータで-1を指定。
// *****************************************************************************
template
< class T_Pointer
, class T_Iterator
, int   N_AccessOffs >
class base_iterator_
{
  using type_this = base_iterator_< T_Pointer, T_Iterator, N_AccessOffs >;
  friend type_this;
  friend T_Iterator;
protected:
  //using type_iiobj = T_TIObject;

public:
  using type_target = typename Traits::RemovePointer<T_Pointer>::type;

  using type_target_ptr  = type_target*;  // type_targetがconstの場合、type_target_cptrと同じ。
  using type_target_cptr = type_target const*;
  using type_target_ref  =
    typename Traits::AlterReference<T_Pointer>::type; // type_targetがconstの場合、type_target_crefと同じ。
  using type_target_cref =
    typename Traits::AlterReference<type_target_cptr>::type;
  using type_itr         = T_Iterator;
  using type_itr_ptr     = type_itr*;
  using type_itr_cptr    = type_itr const*;
  using type_itr_ref     = type_itr&;
  using type_itr_cref    = type_itr const&;

private:
  type_target_ptr m_ptr_target;
  int             m_status_end{ 0 }; // 主にリスト系で終端を判断するために用意。
                                     // 0:通常 1:末尾+1 -1:先頭-1

protected:
  type_itr_ref
    zzf_getItr_() noexcept {
      return *static_cast<type_itr_ptr>(this); }

  type_itr_cref
    zzf_getItr_() const noexcept {
      return *static_cast<type_itr_cptr>(this); }

  type_target_ptr
    zzf_getTargetPtr_() noexcept {
      return m_status_end ? nullptr : m_ptr_target + N_AccessOffs; }

  type_target_ptr
    zzf_getTargetPtr_() const noexcept {
      return m_status_end ? nullptr : m_ptr_target + N_AccessOffs; }

  void
    zzf_setTargetPtr_( type_target_ptr in_ptr_target )
  {
    m_ptr_target = in_ptr_target;
  }

  int  zzf_getFlagEnd_() const
  {
    return m_status_end;
  }
  void zzf_setFlagEnd_( int in_flag )
  {
    m_status_end = in_flag;
  }

  base_iterator_( type_target_ptr in_ptr_target, int in_status_end ) noexcept
    : m_ptr_target( in_ptr_target )
    , m_status_end( in_status_end )
  {}
  base_iterator_( type_this const& in_itr, int in_status_end ) noexcept
    : m_ptr_target( in_itr.m_ptr_target )
    , m_status_end( in_status_end )
  {}
public:
  base_iterator_() noexcept
    : m_ptr_target( nullptr )
  {}
  base_iterator_( nullptr_t ) noexcept
    : m_ptr_target( nullptr )
  {}
  base_iterator_( type_target_ptr in_ptr_target ) noexcept
    : m_ptr_target( in_ptr_target )
  {}
  base_iterator_( type_itr const& itr ) noexcept
    : m_ptr_target( itr.m_ptr_target )
  {}

//  type_target_ptr         ptr()       {
//                                return m_ptr; }
//  type_target_ptr   ptr() const {
//                                return m_ptr; }
  type_target_ptr         operator ->()       noexcept {
                                                      return m_ptr_target+N_AccessOffs; }
  type_target_ptr         operator ->() const noexcept {
                                                      return m_ptr_target+N_AccessOffs; }
  type_target_ref         operator * ()       noexcept {
                                                      return m_ptr_target[N_AccessOffs]; }
  type_target_ref         operator * () const noexcept {
                                                      return m_ptr_target[N_AccessOffs]; }
  //type_target_ptr*        operator & ()       noexcept {
  //                                                    return &m_ptr_target.get_(); }
  //type_target_ptr const*  operator & () const noexcept {
  //                                                    return &m_ptr_target.get_(); }

  type_this& operator = ( type_this const& in_itr )
  {
    m_ptr_target = in_itr.m_ptr_target;
    return *this;
  }

  template<class T>
  bool operator == ( const T& in_itr ) const noexcept
  {
    return
      m_ptr_target == in_itr.m_ptr_target  &&
      m_status_end == in_itr.m_status_end;
  }

  template<class T>
  bool operator != ( const T& in_itr ) const noexcept
  {
    return !(*this == in_itr);
  }

  bool operator == ( nullptr_t ) const noexcept
  {
    return m_ptr_target == nullptr;//((void*)&*zzf_getItr_() == (void*)&*type_itr((type_target_ptr)null));
  }

  bool operator != ( nullptr_t ) const noexcept
  {
    return !(*this == nullptr);
  }

  bool operator ! () const noexcept
  {
    return (*this == nullptr);
  }
  
  operator bool() const noexcept
  {
    return !(operator!());
  }
};


// _____________________________________________________________________________
/// @brief 双方向イテレータ基底クラス
/// 
/// 末尾イテレータは、コンストラクタの引数の0番目に最後の要素、1番目にtrueを指定する。
///
/// @copydetails base_iterator_
/// @tparam T_Add : +operator用クラスを指定。
/// @tparam T_Sub : -operator用クラスを指定。
// *****************************************************************************
template
< class T_Pointer
, class T_Iterator
, int   N_AccessOffs
, class T_Add
, class T_Sub >
class bidirectional_iterator_
  : public base_iterator_<T_Pointer,T_Iterator,N_AccessOffs>
{
  using type_base = base_iterator_<T_Pointer, T_Iterator,N_AccessOffs>;
  friend T_Add;
  friend T_Sub;
  friend bidirectional_iterator_;//<T_Pointer,T_Iterator,N_AccessOffs,T_Add,T_Sub>;
  friend type_base;
  //auto& access_status_(){ return type_base::m_status_end; }
protected:
  using type_itr        = typename type_base::type_itr;
  using type_target_ref = typename type_base::type_target_ref;
public:
  template<class... T_Params>
  bidirectional_iterator_( T_Params&&... args )
    : type_base( std::forward<T_Params>(args)... )
  {}

  // ++()
  type_itr& operator ++() {
    return T_Add::Call( static_cast<T_Iterator*>(this) ); }
  // ()++
  type_itr operator ++(int) {
    type_itr itr( *static_cast<T_Iterator*>(this) );
    T_Add::Call( this );
    return itr; }
  // +()
  type_itr operator +() const {
    return ++type_itr( *static_cast<T_Iterator const*>(this) ); }
      
  // --()
  type_itr& operator --() {
    return T_Sub::Call( static_cast<T_Iterator*>(this) ); }
  // ()--
  type_itr operator --(int) {
    type_itr itr( *static_cast<T_Iterator*>(this) );
    T_Sub::Call( this );
    return itr; }
  // -()
  type_itr operator -() const {
    return --type_itr( *static_cast<T_Iterator const*>(this) ); }
};


// _____________________________________________________________________________
/// @brief ランダムアクセスイテレータ基底クラス
///
/// 末尾イテレータは、コンストラクタの引数の0番目に最後の要素、1番目にtrueを指定する。
///
/// @copydetails base_iterator_
/// @tparam T_Add : +operator用クラスを指定。
/// @tparam T_Sub : -operator用クラスを指定。
// *****************************************************************************
template
< class T_Pointer
, class T_Iterator
, int   N_AccessOffs
, class T_Add
, class T_Sub >
class random_access_iterator_
  : public bidirectional_iterator_<T_Pointer, T_Iterator, N_AccessOffs, T_Add, T_Sub>
{
  using type_base =
    bidirectional_iterator_<T_Pointer, T_Iterator, N_AccessOffs, T_Add, T_Sub>;
  using type_this =
    random_access_iterator_<T_Pointer, T_Iterator, N_AccessOffs, T_Add, T_Sub>;
  using type_itr        = typename type_base::type_itr;
  using type_target_ref = typename type_base::type_target_ref;
public:
  template<class... T_Params>
  random_access_iterator_( T_Params&&... args )
    : type_base( std::forward<T_Params>(args)... )
  {}

  // +=
  template<class T_TypeValue>
  type_itr& operator += ( T_TypeValue val ) {
    return T_Add::Call( this, val ); }
  // +
  template<class T_TypeValue>
  type_itr  operator +  ( T_TypeValue val ) const {
    return T_Add::Call( &type_itr(*this), val ); }

  // -=
  template<class T_TypeValue>
  type_itr& operator -= ( T_TypeValue val ) {
      return T_Sub::Call( this, val ); }
  // -
  template<class T_TypeValue>
  type_itr  operator -  ( T_TypeValue val ) const {
    return T_Sub::Call( &type_itr(*this), val ); }

  // []
  template<class T_Idx>
  type_target_ref operator[]( T_Idx in_index )
  {
    return this->zzf_getTargetPtr_()[ in_index ];
  }
  // [] const
  template<class T_Idx>
  type_target_ref operator[]( T_Idx in_index ) const
  {
    return this->zzf_getTargetPtr_()[ in_index ];
  }

  // <
  bool operator < ( type_itr in_itr ) const
  {
    return this->zzf_getTargetPtr_() < &*in_itr;
  }
  // >
  bool operator > ( type_itr in_itr ) const
  {
    return this->zzf_getTargetPtr_() > &*in_itr;
  }
  // <=
  bool operator <= ( type_itr in_itr ) const
  {
    return this->zzf_getTargetPtr_() <= &*in_itr;
  }
  // >=
  bool operator >= ( type_itr in_itr ) const
  {
    return this->zzf_getTargetPtr_() >= &*in_itr;
  }
};


} // namespace iterator
} // namespace Core
} // namespace CPL
