/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2016/12/19
/// 
/// @brief  階層リストクラス関連。
/// 
/// ****************************************************************************

#pragma once

#include "CPL_Core_DoublyList.h"


namespace CPL {
namespace Core {
namespace List {



// _____________________________________________________________________________
/// @brief 階層リストのノード要素クラス
/// 
/// ※ TreeElementは必ずDoublyElementが継承されていないといけない。\n
///    DoublyElement基本クラスに含まれていない場合、テンプレートの第二引数に指定
///    すること。
///
// *****************************************************************************
template< class T_TE_LinkType, class T_BaseClass = Default_ >
class TreeElement
  : public
      Traits::IfDefaultType<
        T_BaseClass, DoublyElement<T_TE_LinkType>, T_BaseClass >::type
{
  typedef typename
    Traits::IfDefaultType<
      T_BaseClass,
      DoublyElement<T_TE_LinkType>,
      T_BaseClass >::type                         base_class;
  typedef TreeElement<T_TE_LinkType, T_BaseClass> type_this;
  typedef type_this*                              this_pointer;
  typedef type_this const*                        this_cpointer;
public:
  typedef type_this                               TypeTreeElement;
  typedef T_TE_LinkType                           TypeLink;
  typedef T_TE_LinkType*                          TypeLinkPointer;
  typedef T_TE_LinkType const*                    TypeLinkCPointer;
  typedef T_TE_LinkType volatile*                 TypeLinkVPointer;
  typedef T_TE_LinkType cpl_cv*                   TypeLinkCVPointer;

  template<class T,class U> friend class List::DoublyElement;
  template<class T,class U> friend class List::TreeElement;
protected:
  mutable this_pointer m_ptr_parent; // 親へのポインタ
  mutable this_pointer m_ptr_child;  // 子供の先頭へのポインタ

  void zzf_setParent( this_pointer parent ){ m_ptr_parent = parent; }
  void zzf_setChild( this_pointer child ){ m_ptr_child = child; }
  
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  TypeLinkPointer
    zzf_getThisElementType(){
      return static_cast<TypeLinkPointer>(this); }
  TypeLinkCPointer
    zzf_getThisElementType() const {
      return static_cast<TypeLinkCPointer>(this); }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  TypeLinkCPointer zzf_getRoot() const
  {
    TypeLinkCPointer p = zzf_getThisElementType();
    while( p->GetNodeParent() )
    {
      p = p->GetNodeParent();
    }
    return p->GetNodeTop();
  }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  TypeLinkCPointer zzf_getNextAll() const 
  {
    if( this->m_ptr_child )
    {
      return this->GetNodeChild();
    }
    else
    if( this->m_ptr_next )
    {
      return this->GetNodeNext();
    }
    else
    {
      this_cpointer ptr_node = this;
      while( ptr_node )
      {
        TypeLinkCPointer sub_ptr_node_parent = ptr_node->GetNodeParent();

        if( sub_ptr_node_parent  &&
            sub_ptr_node_parent->GetNodeNext() )
        {
          TypeLinkCPointer sub_ptr_node =
            static_cast<TypeLinkCPointer>(sub_ptr_node_parent->GetNodeNext());
          ptr_node = static_cast<TypeLinkCPointer>( sub_ptr_node );
          break;
        }
        ptr_node = ptr_node->GetNodeParent();
      }
      return static_cast<TypeLinkCPointer>(ptr_node);
    }
  }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  TypeLinkCPointer zzf_getPrevAll() const
  {
    TypeLinkCPointer temp_ptr_node = GetNodePrev();
    if( !temp_ptr_node  &&  m_ptr_parent )
    {
      temp_ptr_node = GetNodeParent()->GetNodePrev();
    }

    while( temp_ptr_node )
    {
      if( !temp_ptr_node->GetNodeChild() )
      {
        break;
      }
      temp_ptr_node = temp_ptr_node->GetNodeChild();
      temp_ptr_node = temp_ptr_node->GetNodeEnd();
    }

    return temp_ptr_node;
  }


  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 前方解除
  void zzf_detachPrev()
  {
    TypeLinkPointer
      sub_ptr_this = static_cast<TypeLinkPointer>(this);

    if( sub_ptr_this->m_ptr_prev )
    {
      sub_ptr_this->m_ptr_prev->zzf_setNext( sub_ptr_this->m_ptr_next );
    }
    else
    if( m_ptr_parent )
    {
      m_ptr_parent->zzf_setChild(
        static_cast<TypeLinkPointer>(sub_ptr_this->GetNodeNext()) );
    }
  }
  
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 後方解除
  void zzf_detachNext()
  {
    TypeLinkPointer
      sub_ptr_this = static_cast<TypeLinkPointer>(this);

    if( sub_ptr_this->m_ptr_next )
    {
      sub_ptr_this->m_ptr_next->zzf_setPrev( sub_ptr_this->m_ptr_prev );
    }
  }
//  void _Clear(){ m_ptr_parent = m_ptr_next = this->m_ptr_prev = nullptr; }

public:
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 前の要素を取得
  TypeLinkPointer GetNodePrev(){
    return static_cast<TypeLinkPointer>(this->m_ptr_prev); }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 前の要素を取得 const仕様
  TypeLinkCPointer GetNodePrev() const {
    return static_cast<TypeLinkCPointer>(this->m_ptr_prev); }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 前の要素を取得　※ オフセットあり
  TypeLinkPointer GetNodePrev( U32 in_offset ){
    return StaticConstCast<TypeLinkPointer>( this->zzf_getNodePrevOffs( in_offset ) ); }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 前の要素を取得　※ オフセットあり const仕様
  TypeLinkCPointer GetNodePrev( U32 in_offset ) const {
    return this->zzf_getNodePrevOffs( in_offset ); }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 先頭の要素を取得
  TypeLinkPointer GetNodeTop(){
    return StaticConstCast<TypeLinkPointer>( this->zzf_getNodeTop() ); }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 先頭の要素を取得　※ const仕様
  TypeLinkCPointer GetNodeTop() const {
    return static_cast<TypeLinkCPointer>( this->zzf_getNodeTop() ); }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 次の要素を取得
  TypeLinkPointer GetNodeNext(){
    return static_cast<TypeLinkPointer>(this->m_ptr_next); }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 次の要素を取得 const仕様
  TypeLinkCPointer GetNodeNext() const {
    return static_cast<TypeLinkCPointer>(this->m_ptr_next); }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 次の要素を取得　※ オフセットあり
  TypeLinkPointer GetNodeNext( U32 in_offset ){
    return StaticConstCast<TypeLinkPointer>( this->zzf_getNodeNextOffs( in_offset ) ); }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 次の要素を取得　※ オフセットあり const仕様
  TypeLinkCPointer GetNodeNext( U32 in_offset ) const {
    return static_cast<TypeLinkCPointer>(this->zzf_getNodeNextOffs( in_offset )); }
  
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 最後尾の要素を取得
  TypeLinkPointer GetNodeEnd(){
    return StaticConstCast<TypeLinkPointer>( this->zzf_getNodeEnd() ); }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 最後尾の要素を取得　※ const仕様
  TypeLinkCPointer GetNodeEnd() const {
    return static_cast<TypeLinkCPointer>( this->zzf_getNodeEnd() ); }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // オフセット分進んだ要素を取得
  TypeLinkPointer GetNodeOffset( S32 in_offset ){
    return StaticConstCast<TypeLinkPointer>( this->zzf_getNodeOffset( in_offset ) ); }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // オフセット分進んだ要素を取得　※ const仕様
  TypeLinkCPointer GetNodeOffset( S32 in_offset ) const {
    return static_cast<TypeLinkCPointer>( this->zzf_getNodeOffset( in_offset ) ); }



  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 親を取得
  TypeLinkPointer GetNodeParent() {
    return static_cast<TypeLinkPointer>(this->m_ptr_parent); }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 親を取得 const仕様
  TypeLinkCPointer GetNodeParent() const {
    return static_cast<TypeLinkCPointer>(m_ptr_parent); }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 子供の先頭を取得
  TypeLinkPointer GetNodeChild(){
    return static_cast<TypeLinkPointer>(m_ptr_child); }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 子供の先頭を取得 const仕様
  TypeLinkCPointer GetNodeChild() const {
    return static_cast<TypeLinkCPointer>(m_ptr_child); }
  
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 一番最上階のトップを取得
  TypeLinkPointer GetNodeRoot(){
    return const_cast<TypeLinkPointer>(zzf_getRoot()); }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 一番最上階のトップを取得 const仕様
  TypeLinkCPointer GetNodeRoot() const {
    return zzf_getRoot(); }
  
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 全体で次の要素を取得する
  TypeLinkPointer GetNodeNextAll(){
    return const_cast<TypeLinkPointer>(zzf_getNextAll()); }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 全体で次の要素を取得する　※ const仕様
  TypeLinkCPointer GetNodeNextAll() const {
    return zzf_getNextAll(); }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 全体で前(前に子孫がある場合は最後の子孫)の要素を取得する
  TypeLinkPointer GetNodePrevAll(){
    return const_cast<TypeLinkPointer>(zzf_getPrevAll()); }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 全体で前(前に子孫がある場合は最後の子孫)の要素を取得する　※ const仕様
  TypeLinkCPointer GetNodePrevAll() const {
    return zzf_getPrevAll(); }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 指定したノードが上位クラスに存在するかどうかチェック
  // 戻り値 : true（存在する）
  //         false（存在しない）
  template<class T_NodeType>
  bool  CheckNodeUpClass( T_NodeType in_node ) const
  {
    TypeLinkCPointer ptr_parent = GetNodeParent();
    while( ptr_parent )
    {
      if( ptr_parent->zzf_getThisElementType() == in_node->zzf_getThisElementType() )
      {
        return true;
      }
      ptr_parent = ptr_parent->GetNodeParent();
    }
    return false;
  }
  
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 指定したノードが下位クラスに存在するかどうかチェック
  // 戻り値 : true（存在する）
  //         false（存在しない）
  template<class T_NodeType>
  bool  CheckNodeDownClass( T_NodeType in_node ) const
  {
    if( in_node )
    {
      return in_node->CheckNodeUpClass( this );
    }
    return false;
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 指定したノードが管理するツリー内にあるかどうかチェック
  // 戻り値 : true（存在する）
  //         false（存在しない）
  template<class T_NodeType>
  bool  CheckNodeAllClass( T_NodeType in_node ) const
  {
    TypeLinkCPointer
      ptr_check = GetNodeRoot();
    while( ptr_check )
    {
      if( ptr_check == in_node )
      {
        return true;
      }
      if( ptr_check->CheckNodeDownClass( in_node ) )
      {
        return true;
      }
      ptr_check = ptr_check->GetNodeNext();
    }
    return false;
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 自身をリストから除外
  // 戻り値 : 次のノードを返す
  TypeLinkPointer Detach()
  {
    TypeLinkPointer
      sub_ptr_this = static_cast<TypeLinkPointer>(this);

    TypeLinkPointer
      ret = static_cast<TypeLinkPointer>(sub_ptr_this->GetNodeNext());
    zzf_detachPrev();
    zzf_detachNext();
    sub_ptr_this->m_ptr_prev = nullptr;
    sub_ptr_this->m_ptr_next = nullptr;
    m_ptr_parent = nullptr;
    return ret;
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 前に追加
  template<class T_NodeType>
  TypeLinkPointer AddNodePrev( T_NodeType io_ptr_node )
  {
    io_ptr_node->Detach();
    io_ptr_node->zzf_setPrev( this->m_ptr_prev );
    io_ptr_node->zzf_setNext( this );
    io_ptr_node->zzf_setParent( m_ptr_parent );

    if( this->m_ptr_prev )
    {
      this->m_ptr_prev->zzf_setNext( io_ptr_node );
    }
    else
    if( this->m_ptr_parent )
    {
      this->m_ptr_parent->zzf_setChild( io_ptr_node );
    }
    this->m_ptr_prev = io_ptr_node;

    return static_cast<TypeLinkPointer>(io_ptr_node);
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 後に追加
  template<class T_NodeType>
  TypeLinkPointer AddNodeNext( T_NodeType io_ptr_node )
  {
    TypeLinkPointer
      sub_ptr_this = static_cast<TypeLinkPointer>(this);

    io_ptr_node->TypeTreeElement::Detach();
    io_ptr_node->zzf_setPrev( sub_ptr_this );
    io_ptr_node->zzf_setNext( sub_ptr_this->m_ptr_next );
    io_ptr_node->zzf_setParent( m_ptr_parent );

    if( sub_ptr_this->m_ptr_next )
    {
      sub_ptr_this->m_ptr_next->zzf_setPrev( io_ptr_node );
    }
    sub_ptr_this->m_ptr_next = io_ptr_node;

    return static_cast<TypeLinkPointer>(io_ptr_node);
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 先頭に追加
  template<class T_NodeType>
  TypeLinkPointer AddNodeTop( T_NodeType io_ptr_node )
  {
//    io_ptr_node->Detach();
    return GetNodeTop()->AddNodePrev( io_ptr_node );
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 最後尾に追加
  template<class T_NodeType>
  TypeLinkPointer AddNodeEnd( T_NodeType io_ptr_node )
  {
    TypeLinkPointer
      sub_ptr_this =
        static_cast<TypeLinkPointer>(this);
    TypeLinkPointer
      sub_ptr_end  =
        static_cast<TypeLinkPointer>( sub_ptr_this->GetNodeEnd() );
    this_pointer ptr_end = static_cast<this_pointer>(sub_ptr_end);

//    io_ptr_node->Detach();
    return ptr_end->AddNodeNext( io_ptr_node );
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 子供を追加（子供の最後尾に追加される）
  // 戻り値 : 追加したポインタを返す
  template<class T_NodeType>
  TypeLinkPointer AddNodeChild( T_NodeType io_ptr_node )
  {
    static_cast<this_pointer>(io_ptr_node)->Detach();

    if( m_ptr_child )
    {
      static_cast<this_pointer>(m_ptr_child)->AddNodeEnd( io_ptr_node );
    }
    else
    {
      m_ptr_child = io_ptr_node;
    }
    static_cast<this_pointer>(io_ptr_node)->zzf_setParent( this );
    return static_cast<TypeLinkPointer>(io_ptr_node);
  }
  
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 一つ前に移動
  void  MoveNodePrev()
  {
    if( this->m_ptr_prev )
    {
      GetNodePrev()->AddNodePrev( this );
    }
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 指定したノードの前に移動
  template<class T_NodeType>
  void  MoveNodePrev( T_NodeType io_ptr_node )
  {
    io_ptr_node->AddNodePrev( this );
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 一つ次に移動
  void  MoveNodeNext()
  {
    if( this->m_ptr_next )
    {
      GetNodeNext()->AddNodeNext( this );
    }
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 指定したノードの次に移動
  template<class T_NodeType>
  void  MoveNodeNext( T_NodeType io_ptr_node )
  {
    io_ptr_node->AddNodeNext( this );
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 先頭に移動
  void  MoveNodeTop()
  {
    if( this->m_ptr_prev )
    {
      GetNodeTop()->AddNodePrev( this );
    }
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 最後尾に移動
  void  MoveNodeEnd()
  {
    if( this->m_ptr_next )
    {
      GetNodeEnd()->AddNodeNext( this );
    }
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 一つ上のクラスに移動
  void  MoveNodeParent()
  {
    if( m_ptr_parent )
    {
      m_ptr_parent->AddNodeNext( this );
    }
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 交換
  // 交換失敗でfalseを返す
  template<class T_NodeType>
  bool  SwapNode( T_NodeType io_ptr_node )
  {
    // 自己交換判定
    if( io_ptr_node->zzf_getThisElementType() == this )
    {
      return false;
    }
    // 交換できるかどうかチェック
    if( CheckNodeUpClass( io_ptr_node )  ||  CheckNodeDownClass( io_ptr_node ) )
    {
      return false;
    }
    if( this->m_ptr_prev == io_ptr_node )
    {
      GetNodePrev()->AddNodeNext( io_ptr_node );
    }
    else
    if( this->m_ptr_next == io_ptr_node )
    {
      GetNodeNext()->AddNodePrev( io_ptr_node );
    }
    else
    {
      if( m_ptr_parent  &&  this->m_ptr_prev == nullptr ) // 親があって前がないということは子供の先頭
      {
        m_ptr_parent->zzf_setChild( io_ptr_node );
      }
      if( io_ptr_node->GetNodeParent()  &&  io_ptr_node->GetNodePrev() == nullptr )
      {
        io_ptr_node->GetNodeParent()->zzf_setChild( this );
      }
      Swap( this->m_ptr_prev, io_ptr_node->m_ptr_prev );
      Swap( this->m_ptr_next, io_ptr_node->m_ptr_next );
    }
    return true;
  }

private:
  int zzf_getNodeClassNum_( ValueType<false> is_basecast ) const { return 1; }
  int zzf_getNodeClassNum_( ValueType<true>  is_basecast ) const
  {
    return static_cast<DoublyElement<T_TE_LinkType> const*>(this)->GetNodeNum();
  }
public:
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 自分の階数のノード数を取得
  int   GetNodeClassNum() const
  {
    return
      zzf_getNodeClassNum_
        ( ValueType<std::is_convertible< base_class, DoublyElement<T_TE_LinkType>>::value>()
        );
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 子供の個数を取得
  int   GetNodeChildNum() const
  {
    TypeLinkCPointer p = GetNodeChild();
    int  num = 0;

    while( p )
    {
      num += p->GetNodeChildNum() + 1;
      p = p->GetNodeNext();
    }
    return num;
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 全ノード数を取得
  int   GetNodeNum() const
  {
    TypeLinkCPointer ptr_root = GetNodeRoot();
    int num = 0;
    while( ptr_root )
    {
      num += ptr_root->GetNodeChildNum() + 1;
      ptr_root = ptr_root->GetNodeNext();
    }
    return num;
  }

protected:
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 継承用コンストラクタ　※ １引数仕様
  template<class T0>
  TreeElement( T0 in_param0 )
    : base_class( in_param0 )
    , m_ptr_parent(nullptr)
    , m_ptr_child(nullptr)
  {}
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 継承用コンストラクタ　※ ２引数仕様
  template<class T0, class T1>
  TreeElement( T0 in_param0, T1 in_param1 )
    : base_class( in_param0, in_param1 )
    , m_ptr_parent(nullptr)
    , m_ptr_child(nullptr)
  {}
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 継承用コンストラクタ　※ ３引数仕様
  template<class T0, class T1, class T2>
  TreeElement( T0 in_param0, T1 in_param1, T2 in_param2 )
    : base_class( in_param0, in_param1, in_param2 )
    , m_ptr_parent(nullptr)
    , m_ptr_child(nullptr)
  {}

public:
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  TreeElement()
    : m_ptr_parent(nullptr)
    , m_ptr_child(nullptr)
  {}
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ~TreeElement()
  {
    if( m_ptr_child ) // 子供があれば全ての子供の親ポインタをクリア
    {
      TypeLinkPointer ptr_child = GetNodeChild();
      while( ptr_child )
      {
        ptr_child->m_ptr_parent = nullptr;
        ptr_child = static_cast<TypeLinkPointer>(ptr_child->GetNodeNext());
      }
    }
    // 子どものみ参照されている場合もあるので、子どもはここで削除するべきではない。
    // 必要に応じて、継承先で処理を決めること。

    Detach();
  }
};



/// @cond
namespace zzz_ {
// =============================================================================
// 階層リストクラス（ツリークラス）
// =============================================================================
template< class T_zbTN_Type,
          class T_zbTN_TypeNode>
class BaseTreeNode
  : public Core::BaseObject
  , public TreeElement
      < T_zbTN_TypeNode
      , DoublyElement< T_zbTN_TypeNode >
      >
{
protected:
  using TYPE_PTR       = ptr<T_zbTN_Type>;
  using TYPE_CONST_PTR = cptr<T_zbTN_Type>;
  using TYPE_REF       = ref<T_zbTN_Type>;
  using TYPE_CONST_REF = cref<T_zbTN_Type>;

  template<class T, class TN>
  friend class BaseTreeNode;

  T_zbTN_Type m_instance;

private:
  typedef BaseTreeNode< T_zbTN_Type, T_zbTN_TypeNode > type_this;
public:
  typedef type_this TypeBaseTreeNode;

  TYPE_PTR       operator ->()       { return &m_instance; }
  TYPE_CONST_PTR operator ->() const { return &m_instance; }
  TYPE_PTR       get()               { return &m_instance; }
  TYPE_CONST_PTR get()         const { return &m_instance; }

  BaseTreeNode(){}
  BaseTreeNode( TYPE_CONST_REF r )
    : m_instance( r )
  {}
};
} // namespace zzz_
/// @endcond



// _____________________________________________________________________________
/// @brief 階層リストクラス（ツリークラス）
///
// *****************************************************************************
template< class T_TN_Type,
          class T_TN_TypeNode = Default_ >
class TreeNode
  : public
      zzz_::BaseTreeNode
        < T_TN_Type
        , typename
          Traits::IfDefaultType
            < T_TN_TypeNode
            , TreeNode<T_TN_Type>
            , T_TN_TypeNode
            >::type
        >
{
  using TypeNode =
    typename Traits::IfDefaultType<T_TN_TypeNode, TreeNode<T_TN_Type>,  T_TN_TypeNode >::type;
  using TypeNodePtr =
    typename Traits::IfDefaultType<T_TN_TypeNode, TreeNode<T_TN_Type>*, T_TN_TypeNode*>::type;
  using type_this =
    TreeNode<T_TN_Type, T_TN_TypeNode>;
protected:
public:
  TreeNode(){}
  TreeNode( cref<T_TN_Type> r )
    : zzz_::BaseTreeNode< T_TN_Type, TypeNode >( r )
  {}

  typedef type_this TypeTreeNode;
};


} // namespace List
} // namespace Core
} // namespace CPL
