/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2010/X/X - 2017/02/01
/// 
/// @brief  ペインコンテナクラス
/// 
/// ****************************************************************************

#include "CPL_GUC_Pane.h"

namespace CPL {
namespace GUC {

  
// _____________________________________________________________________________
/// @brief コンポーネント標準背景カラー。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<DrawColorSet> Pane::GetDefaultColor_PaneBG()
{
  static auto
    sp_color =
      CPL_MAKE_SHARED
        ( DrawColorSet
        , ColorPattern::DynamicBG()
        );
  return sp_color;
}

// _____________________________________________________________________________
/// @brief コンポーネント標準フレームカラー。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<DrawColorSet> Pane::GetDefaultColor_PaneFrame()
{
  static auto
    sp_color =
      CPL_MAKE_SHARED
        ( DrawColorSet
        , ColorPattern::DynamicFrame()
        );
  return sp_color;
}

// _____________________________________________________________________________
/// @brief デフォルトテキストカラー。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<DrawColorSet> Pane::GetDefaultColor_PaneText()
{
  static auto
    sp_color =
      CPL_MAKE_SHARED
        ( DrawColorSet
        , ColorPattern::DynamicText()
        );
  return sp_color;
}


// _____________________________________________________________________________
/// @brief コンストラクタ。
/// 
/// @copydetails doxycomment::arg_in_sp_component_for_parent
/// @copydoc doxycomment::arg_in_position_for_component
/// @copydoc doxycomment::arg_in_size_for_component
/// @param[in] in_flag_pane_type
///   : 分割タイプを指定します。\n
///   : false - 横分割\n
///   : true  - 縦分割
/// @param[in] in_flag_pane_variable
///   : ペインサイズを可変にするかどうかを指定します。\n
///   : false - サイズ固定。
///   : true  - サイズ可変。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pane::Pane
( _in<sdptr<Component>> in_sp_component_for_parent
, _in<float2          > in_position_for_component
, _in<float2          > in_size_for_component
, _in<bool            > in_flag_pane_type
, _in<bool            > in_flag_pane_variable
) : Container
    ( in_sp_component_for_parent
    , in_position_for_component
    , in_size_for_component
    )
  , m_flag_pane_type( in_flag_pane_type )
  , m_flag_pane_variable( in_flag_pane_variable )
  , m_changing_container_index( -1 )
{
  m_scale_table.push_back( 0 );

  zzf_setupDrawState( true, false, true );

  // 
}


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pane::Pane( cref<Pane> in_pane )
  : td_base( in_pane )
  , m_scale_table( in_pane.m_scale_table )
  , m_changing_container_index( in_pane.m_changing_container_index )
  , m_flag_pane_type( in_pane.m_flag_pane_type )
  , m_flag_pane_variable( in_pane.m_flag_pane_variable )
{
}


// _____________________________________________________________________________
/// @brief デストラクタ。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pane::~Pane()
{
  // 今のところとくに何もしない。
}

//// _____________________________________________________________________________
///// @brief 子供の追加 = アイテムの追加として拡張する。
///// 
///// @copydetails SmartLinkTree::AddLinkChild
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//sdptr<Component>
//  Pane::AddLinkChild
//    ( _in<sdptr<Component>> in_sp_comp_new
//    )
//{
//  auto res = td_base::AddLinkChild( in_sp_comp_new );
//
//  auto child_num = this->GetChildLinkNum();
//  //
//  float scale = 1.0f;
//  if( child_num <= 1 )
//  {
//    scale = 1.0f;
//  }
//  else
//  {
//    scale = float( child_num - 1 ) / float( child_num );
//  }
//
//  //
//  CPL_LOOP2R( m_scale_table.size(), idx )
//  {
//    m_scale_table[idx] *= scale;
//  }
//  //
//  m_scale_table.push_back( 1.0f );
//
//  AutoRepositionItems();
//
//  return res;
//}
//
//
//// _____________________________________________________________________________
///// @brief アイテムの追加。
///// 
///// @param[in] in_sp_comp_new
/////   : 追加するコンポーネント。
///// @param[in] in_sp_comp_next
/////   : 追加する位置の次のコンポーネント。\n
/////   : nullptrを指定すると、子供の末尾に追加される。\n
/////   : なお、in_sp_comp_nextが子供でない場合、nullptrが渡されたものとして振舞う。
///// @param[in] in_new_rate
/////   : 子供が２つ以上となる場合に適応される、追加コンポーネントの表示割合。(0.0f - 1.0f)\n
/////   : 0.0以下または1.0以上を指定すると、デフォルト値(1.0f/アイテム数)が適応される。
///// 
///// @return 追加したコンポーネント。
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//sdptr<Component>
//  Pane::EntryItem
//    ( _in<sdptr<Component>> in_sp_comp_new
//    , _in<sdptr<Component>> in_sp_comp_prev
//    , _in<float           > in_new_rate
//    )
//{
//  auto sp_comp_prev = in_sp_comp_prev;
//  if( sp_comp_prev  &&  sp_comp_prev->GetLinkParent() != GetLinkMyself() )
//  {
//    sp_comp_prev = nullptr;
//  }
//  if( sp_comp_prev )
//  {
//    sp_comp_prev->AddLinkPrev( in_sp_comp_new );
//  }
//  ef( in_sp_comp_new->GetLinkParent() != GetLinkMyself() )
//  {
//    AddLinkChild( in_sp_comp_new );
//  }
//  //
//  in_sp_comp_new->SetBelongComponent( GetLinkMyself() );
//
//  auto child_num = this->GetChildLinkNum();
//  //
//  float scale = 1.0f;
//  if( child_num <= 1 )
//  {
//    scale = 1.0f;
//  }
//  ef( 0.0f < in_new_rate  &&  in_new_rate < 1.0f )
//  {
//    scale = 1.0f - in_new_rate;
//  }
//  else
//  {
//    scale = float( child_num - 1 ) / float( child_num );
//  }
//
//  //
//  CPL_LOOP2R( m_scale_table.size(), idx )
//  {
//    m_scale_table[idx] *= scale;
//  }
//  //
//  m_scale_table.push_back( 1.0f );
//
//  AutoRepositionItems();
//
//  return in_sp_comp_new;
//}


// _____________________________________________________________________________
/// @brief in_index番目のコンポーネントを取得。
/// 
/// @param[in] in_index : 取得するアイテムコンポーネントのインデックス。
/// 
/// @return
/// in_index番目のコンポーネントのスマポを返す。\n
/// 範囲外のインデックスを指定すると、nullptr相当のスマポが返る。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<Component>
  Pane::GetItemComponent( _in<size_t> in_index ) const
{
  auto sp_comp = GetLinkChild();
  size_t index = in_index;
  while( sp_comp )
  {
    if( index == 0 )
    {
      return sp_comp;
    }
    sp_comp = sp_comp->GetLinkNext();
    --index;
  }

  return nullptr;
}


// _____________________________________________________________________________
/// @brief アイテムの整列。
/// 
/// @return アイテム保持していない場合false、それ以外はtrueを返す。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int Pane::AutoRepositionItems()
{
  auto sp_comp = GetLinkChild();
  if( sp_comp == nullptr )
  {
    return false;
  }

  auto child_num = GetChildLinkNum();
  if( (child_num + 1) != m_scale_table.size() )
  {
    //CPL_OUTPUT( SwS("AutoRepositionItems : adjust scale table\n") );
    m_scale_table.resize( child_num + 1 );
    float count = 0;
    int idx = 0;
    if( m_flag_pane_type == 0 ) // 横分割タイプ。
    {
      while( sp_comp )
      {
        count += sp_comp->GetSize().x;
        m_scale_table[ ++idx ] = count;
        sp_comp = sp_comp->GetLinkNext();
      }
    }
    else // 縦分割タイプ。
    {
      while( sp_comp )
      {
        count += sp_comp->GetSize().y;
        m_scale_table[ ++idx ] = count;
        sp_comp = sp_comp->GetLinkNext();
      }
    }
    for( auto& scale : m_scale_table )
    {
      scale /= count;
    }
  }

  int dbg_count = 0;
  auto const   size_client = GetSize();
  auto const   fw          = GetFrameSize();
  float const* scale       = &m_scale_table[0];
  sp_comp = GetLinkChild();
  while( sp_comp )
  {
    float scale_low  = scale[0];
    float scale_high = scale[1];
    ++scale;

    if( m_flag_pane_type == 0 ) // 横分割タイプ。
    {
      sp_comp->SetRectCoord
        ( float4
            ( size_client.x * scale_low + (sp_comp->GetLinkPrev() != nullptr) * fw
            , 0
            , size_client.x * scale_high - (sp_comp->GetLinkNext() != nullptr) * fw
            , size_client.y
            )
        );
    }
    else // 縦分割タイプ。
    {
      sp_comp->SetRectCoord
        ( float4
            ( 0
            , size_client.y * scale_low + (sp_comp->GetLinkPrev() != nullptr) * fw
            , size_client.x
            , size_client.y * scale_high - (sp_comp->GetLinkNext() != nullptr) * fw
            )
        );
    }

    sp_comp = sp_comp->GetLinkNext();
    ++dbg_count;
  }

  return true;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::CreateClone
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<Component>
  Pane::CreateClone
    ( _in<sdptr<Component>> in_sp_component_for_parent
    , _in<float2          > in_offset_position_from_original
    ) const
{
  return
    zzz_CreateClone_Basic<td_self>
      ( in_sp_component_for_parent
      , in_offset_position_from_original
      );
}


// _____________________________________________________________________________
/// @brief マウスダウンイベント。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  Pane::On_MouseDown
    ( _in<sdptr<Component>> in_sp_component
    , _in<float           > in_mouse_x
    , _in<float           > in_mouse_y
    , _in<eMouseButton    > in_type_mouse_btn
    )
{
  if( in_sp_component == this->GetLinkMyself() )
  {
    if( m_flag_pane_variable )
    {
      SetCapture( GetLinkMyself() );
      m_changing_container_index = -1;
      // どのコンテナの間がクリックされたかを検査。
      if( m_flag_pane_type == false ) // 横。
      {
        // 子供コンテナループ。
        auto sp_comp = GetLinkChild();
        while( sp_comp )
        {
          auto rt = sp_comp->GetRectCoord();
          if( rt.right < in_mouse_x )
          {
            ++m_changing_container_index;
          }
          else
          {
            break;
          }
          sp_comp = sp_comp->GetLinkNext();
        }
        if( sp_comp == nullptr )
        {
          m_changing_container_index = -1;
        }
      }
      else // 縦
      {
        // 子供コンテナループ。
        auto sp_comp = GetLinkChild();
        while( sp_comp )
        {
          auto rt = sp_comp->GetRectCoord();
          if( rt.bottom < in_mouse_y )
          {
            ++m_changing_container_index;
          }
          else
          {
            break;
          }
          sp_comp = sp_comp->GetLinkNext();
        }
        if( sp_comp == nullptr )
        {
          m_changing_container_index = -1;
        }
      }

      //
      int child_num = static_cast<int>(GetChildLinkNum());
      if( m_changing_container_index >= child_num )
      {
        m_changing_container_index = child_num - 1;
      }

      //Update();
    }
  }

  return
    td_base::On_MouseDown
      ( in_sp_component
      , in_mouse_x
      , in_mouse_y
      , in_type_mouse_btn
      );
}


// _____________________________________________________________________________
/// @brief マウスアップイベント。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  Pane::On_MouseUp
    ( _in<sdptr<Component>> in_sp_component
    , _in<float           > in_mouse_x
    , _in<float           > in_mouse_y
    , _in<eMouseButton    > in_type_mouse_btn
    )
{
  if( in_sp_component == this->GetLinkMyself() )
  {
    m_changing_container_index = -1;
    SetCapture( nullptr );
    Update();
  }

  return
    td_base::On_MouseUp
      ( in_sp_component
      , in_mouse_x
      , in_mouse_y
      , in_type_mouse_btn
      );
}


// _____________________________________________________________________________
/// @brief マウスムーブイベント。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  Pane::On_MouseMove
    ( _in<sdptr<Component>> in_sp_component
    , _in<float           > in_mouse_x
    , _in<float           > in_mouse_y
    )
{
  if( in_sp_component   == this->GetLinkMyself()  &&
      GetCapture() == this->GetLinkMyself()  &&
      WIN::Mouse::GetDownL() )
  {
    auto sp_change_comp = zzf_getChangingComponent_();
    if( sp_change_comp )
    {
      const auto   child_num   = GetChildLinkNum();
      const float2 size_client = this->GetSize();
      //const float  frame_size  = this->GetFrameSize();
      const int    change_idx  = m_changing_container_index;
      float scale_limit_step, scale_new;
      // 計算。
      if( m_flag_pane_type == 0 ) // 横分割
      {
        scale_limit_step = GetLineHeight() * 2 / float( size_client.x );
        scale_new = float( in_mouse_x ) / float( size_client.x );
      }
      else // 縦分割
      {
        scale_limit_step = GetLineHeight() * 2 / float( size_client.y );
        scale_new = float( in_mouse_y ) / float( size_client.y );
      }
      // 補正。
      scale_new =
        Clamp
          ( scale_new
          , m_scale_table[change_idx] + scale_limit_step
          , m_scale_table[change_idx + 2] - scale_limit_step
          );
      // 設定。
      m_scale_table[m_changing_container_index + 1] = scale_new;

      AutoRepositionItems();
      //Update();
    }
  }

  return
    td_base::On_MouseMove
      ( in_sp_component
      , in_mouse_x
      , in_mouse_y
      );
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::MouseEventInterface::On_MouseEnter
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  Pane::On_MouseEnter
    ( _in<sdptr<Component>> in_sp_comp_enter
    , _in<sdptr<Component>> in_sp_comp_leave
    )
{
  if( in_sp_comp_enter == GetLinkMyself()  &&  m_flag_pane_variable )
  {
    Update();
  }
  return td_base::On_MouseEnter( in_sp_comp_enter, in_sp_comp_leave );
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::MouseEventInterface::On_MouseLeave
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  Pane::On_MouseLeave
    ( _in<sdptr<Component>> in_sp_comp_leave
    , _in<sdptr<Component>> in_sp_comp_enter
    )
{
  if( in_sp_comp_leave == GetLinkMyself()
   && m_flag_pane_variable )
  {
    Update();
  }
  return td_base::On_MouseLeave( in_sp_comp_leave, in_sp_comp_enter );
}


// _____________________________________________________________________________
/// @brief 変更中の左側もしくは上側のコンテナのスマポを取得。
/// 
/// 変更中でない場合はnulptr相当のスマポが返る。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<Component> Pane::zzf_getChangingComponent_() const
{
  auto idx = m_changing_container_index;
  if( idx == -1 )
  {
    return nullptr;
  }

  auto sp_comp = GetLinkChild();
  while( sp_comp  &&  idx )
  {
    sp_comp = sp_comp->GetLinkNext();
    --idx;
  }
  return sp_comp;
}


//// _____________________________________________________________________________
///// @brief クライアント描画イベント。
///// 
///// タイトルの描画。
//// _____________________________________________________________________________
//void Pane::On_DrawClient( short4 in_rect )
//{
//  const int  frame_size  = this->GetFrameSize();
//  const int  line_height = this->GetLineHeight();
//  DX::SpRectColor4P sp_color = GetDefaultColor_Text()->sp_color_default;
//
//  auto sp_comp = GetLinkChild();
//  while( sp_comp )
//  {
//    auto title = sp_comp->GetText();
//    switch( m_flag_pane_type )
//    {
//    case FPt_HORIZONTAL_UPPER_TITLE: // 横＋上タイトル。
//      zzf_DrawText(
//        short4(
//          in_rect.left + frame_size, in_rect.top + frame_size,
//          in_rect.right - frame_size, frame_size + line_height ),
//        title,
//        sp_color,
//        0.0f, float2( 0, 0 ),
//        DX::kFDM_X_LEFT | DX::kFDM_Y_TOP );
//        break;
//
//    case FPt_HORIZONTAL_LOWER_TITLE: // 横＋下タイトル。
//      break;
//
//    case FPt_VIRTICAL_LEFT_TITLE:    // 縦＋左タイトル。
//      break;
//
//    case FPt_VIRTICAL_RIGHT_TITLE:   // 縦＋右タイトル。
//      break;
//    }
//
//    sp_comp = sp_comp->GetLinkNext();
//  }
//}


} // namespace GUC
} // namespace CPL