/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2014/05/17 - 2017/02/01
/// 
/// @brief  ダイアログ関連。
/// 
/// ****************************************************************************

#include "CPL_GUC_DialogWindow.h"
#include "CPL_GUC_FrameEvent.h"

namespace CPL {
namespace GUC {

// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @copydoc doxycomment::arg_in_sp_component_for_parent
/// @param[in] in_title
///   : ダイアログのタイトルを指定します。
/// @param[in] in_sp_comp_items
///   : 配置するコンポーネントのスマートポインタを指定します。
/// @param[in] in_type_button
///   : 表示するボタンタイプを指定します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DialogWindow::DialogWindow
( _in<sdptr<Component>> in_sp_component_for_parent
, _in<td_DefString    > in_title
, _in<sdptr<Component>> in_sp_comp_items
, _in<eButtonType     > in_type_button
) : td_base
    ( Factory<Container>::Create // バックレイヤーの作成。
        ( in_sp_component_for_parent
            ? in_sp_component_for_parent
            : SmartCast<GUC::FrameEvent*>(WIN::GetWinFrame())->GetMasterLayer(0)->GetLinkParent()
        , float2( 0, 0 )
        , float2( 10000, 10000 )
        )
    , kPOS_DEFAULT  // pos
    , kSIZE_DEFAULT // size
    )
{
  SetTitle( in_title );

  // バックレイヤーの設定。
  m_sp_backlayer = GetLinkParent();
  auto sp_color =
    CPL_MAKE_SHARED
      ( DrawColorSet
      , CDI::ColorType( 0.0f, 0.0f, 0.0f, 0.5f )
      );
  m_sp_backlayer->SetColorParameterBG( sp_color );
  m_sp_backlayer->SetStateDrawBG( true );

  auto sp_client = GetComponent_RenderClient();
  float top_y = 0;

  // アイテム配置
  if( in_sp_comp_items )
  {
    SetComponent_ItemsForm( in_sp_comp_items );
  }

  // ボタン配置簡略化用に配置用のコンテナを作成。
  m_sp_btn_form =
    Factory<GUC::Container>::Create( sp_client, float2{0,0}, float2{1,1} );
  m_sp_btn_form->SetStateDrawBG( false );
  m_sp_btn_form->SetStateDrawClient( true );

  float2 const btn_size{ 80.0f, 20.0f };
  float base_left = 0.0f;
  sdptr<Button> sp_btn_last; // 最後に作成されたボタンを保持

  // ボタンコンテナ作成簡易化用関数
  auto _makeButton =
    [&]( _in<td_DefString> in_str )->sdptr<Button>
    {
      auto sp_btn =
        Factory<GUC::Button>::Create
          ( m_sp_btn_form
          , float2{ base_left, 0 }
          , btn_size
          , in_str
          , CPL_GUC_DEF_STR("")
          );
      base_left += btn_size.x + m_space_btn;
      return sp_btn;
    };
  bool const is_jpn = (in_type_button & BIT15) != 0;

  // [OK] button
  if( in_type_button & eButtonType::Ok )
  {
    m_sp_btn_OK =
    _makeButton( is_jpn ? CPL_GUC_DEF_STR("ＯＫ") : CPL_GUC_DEF_STR("OK") );
  }
  // [YES] button
  if( in_type_button & eButtonType::Yes )
  {
    m_sp_btn_YES =
    _makeButton( is_jpn ? CPL_GUC_DEF_STR("はい") : CPL_GUC_DEF_STR("YES") );
  }
  // [NO] button
  if( in_type_button & eButtonType::No )
  {
    m_sp_btn_NO =
    _makeButton( is_jpn ? CPL_GUC_DEF_STR("いいえ") : CPL_GUC_DEF_STR("NO") );
  }
  // [ADD]
  if( in_type_button & eButtonType::Add )
  {
    m_sp_btn_ADD = 
    _makeButton( is_jpn ? CPL_GUC_DEF_STR("追加") : CPL_GUC_DEF_STR("ADD") );
  }
  // [DELETE]
  if( in_type_button & eButtonType::Delete )
  {
    m_sp_btn_DELETE =
    _makeButton( is_jpn ? CPL_GUC_DEF_STR("削除") : CPL_GUC_DEF_STR("DELETE") );
  }
  // [RETRY] button
  if( in_type_button & eButtonType::Retry )
  {
    m_sp_btn_RETRY =
    _makeButton( is_jpn ? CPL_GUC_DEF_STR("再試行") : CPL_GUC_DEF_STR("RETRY") );
  }
  // [CANCEL] button
  if( in_type_button & eButtonType::Cancel )
  {
    m_sp_btn_CANCEL =
    _makeButton( is_jpn ? CPL_GUC_DEF_STR("キャンセル") : CPL_GUC_DEF_STR("CANCEL") );
  }

  m_sp_btn_form->AdjustSize();

  AutoRepositionItems( 1 );
}


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DialogWindow::DialogWindow( cref<td_self> in_dialog_window )
  : td_base( in_dialog_window )
  , m_space_btn( in_dialog_window.m_space_btn )
  , m_space_frame( in_dialog_window.m_space_frame )
{
  auto& dw = in_dialog_window;
  m_sp_backlayer  = FindComponent_by_UserID( dw.m_sp_backlayer  );
  m_sp_comp_items = FindComponent_by_UserID( dw.m_sp_comp_items );
  m_sp_btn_form   = FindComponent_by_UserID( dw.m_sp_btn_form   );

  m_sp_btn_OK     = FindComponentT_by_UserID<Button>( dw.m_sp_btn_OK     );
  m_sp_btn_CANCEL = FindComponentT_by_UserID<Button>( dw.m_sp_btn_CANCEL );
  m_sp_btn_YES    = FindComponentT_by_UserID<Button>( dw.m_sp_btn_YES    );
  m_sp_btn_NO     = FindComponentT_by_UserID<Button>( dw.m_sp_btn_NO     );
  m_sp_btn_RETRY  = FindComponentT_by_UserID<Button>( dw.m_sp_btn_RETRY  );
  m_sp_btn_ADD    = FindComponentT_by_UserID<Button>( dw.m_sp_btn_ADD    );
  m_sp_btn_DELETE = FindComponentT_by_UserID<Button>( dw.m_sp_btn_DELETE );

  m_sp_backlayer ->SetAutoUserID();
  m_sp_comp_items->SetAutoUserID();
  m_sp_btn_form  ->SetAutoUserID();
  m_sp_btn_OK    ->SetAutoUserID();
  m_sp_btn_CANCEL->SetAutoUserID();
  m_sp_btn_YES   ->SetAutoUserID();
  m_sp_btn_NO    ->SetAutoUserID();
  m_sp_btn_RETRY ->SetAutoUserID();
  m_sp_btn_ADD   ->SetAutoUserID();
  m_sp_btn_DELETE->SetAutoUserID();
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::CreateClone
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<Component>
  DialogWindow::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 配置やサイズの自動調整
/// 
/// @param[in] in_type_adjust
///   : 自動サイズ調整の方法を指定します。\n
///   : 0 - サイズ調整しない。\n
///   : 1 - ウィンドウサイズをアイテムサイズに合わせます。\n
///   : 2 - アイテムサイズをウィンドウサイズに合わせます。
/// @param[in] in_btn_space
///   : ボタンの間隔を指定します。
///
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  DialogWindow::AutoRepositionItems
    ( _in<int  > in_type_adjust
    , _in<float> in_btn_space
    )
{
  auto sp_client = GetComponent_RenderClient();

  // ウィンドウサイズをアイテムサイズに合わせる。
  if( in_type_adjust == 1 )
  {
    // ダイアログの必要サイズを計算。
    auto size_items = m_sp_comp_items ? m_sp_comp_items->GetSize() : float2{0,0};
    auto size_btns  = m_sp_btn_form->GetSize();
    float2 size_client =
    { Max<float>( size_items.x, size_btns.x ) + m_space_frame * 2
    , size_items.y + in_btn_space + size_btns.y + m_space_frame * 2
    };

    // ボタン位置調整
    m_sp_btn_form->SetPosition
      ( float2
        { size_client.x - size_btns.x - m_space_frame
        , size_client.y - size_btns.y - m_space_frame
        }
      );

    sp_client->AdjustSize( float2(m_space_frame) );
    GetComponent_RenderBox()->SetSize( size_client );
    AdjustSize();
  }
  else
  // アイテムサイズをウィンドウサイズに合わせる。
  if( in_type_adjust == 2 )
  {
    auto size_auto_client = zzz_calculateDefaultClientRect();
    float2 size_client = size_auto_client.Size();
    float2 size_btns   = m_sp_btn_form->GetSize();
    // アイテムサイズ変更
    CPL_SAFE_PTR(m_sp_comp_items)->SetSize
      ( float2( size_client.x - m_space_frame * 2
              , size_client.y - size_btns.y - m_space_frame * 3 )
      );
    // ボタン位置調整
    m_sp_btn_form->SetPosition
      ( float2
        { size_client.x - size_btns.x - m_space_frame
        , size_client.y - size_btns.y - m_space_frame
        }
      );
  }
}


// _____________________________________________________________________________
/// @brief ダイアログの中心位置への移動
/// 
/// @param[in] in_sp_component_for_parent
///   : 親となるコンポーネントのスマートポインタを指定します。\n
///   : この親に対して中心に配置されます。\n
///   : nullptrを指定することも可能で、その場合はルートウィンドウの中心に配置されます。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  DialogWindow::AutoCenterPosition
    ( _in<sdptr<Component>> in_sp_component_for_parent
    )
{
  WIN::Rect rect_client_for_frame;
  WIN::GetWinFrame()->GetClientRect( rect_client_for_frame );
  float4 rect =
    in_sp_component_for_parent
      ? in_sp_component_for_parent->GetRectCoord()
      : float4{ 0,0
              , static_cast<float>(rect_client_for_frame.right)
              , static_cast<float>(rect_client_for_frame.bottom) };
  if( in_sp_component_for_parent )
  {
    MappingPosition
      ( in_sp_component_for_parent->GetLinkParent()
      , GetBelongComponent(eParentType::Position)
      , (float2*)&rect
      , 2
      );
  }
  float2 xy_center( (rect.left+rect.right) / 2.0f, (rect.top+rect.bottom) / 2.0f );
  float2 xy_top = int2{ xy_center - this->GetSize() / 2.0f }; // 一度intを通すことで少数を切り捨てている。
  this->SetPosition( xy_top );
}



// _____________________________________________________________________________
/// @copydoc CPL::GUC::WindowEventInterface::On_Show
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GUC::eEventReturnID
  DialogWindow::On_Show
    ( _in<sdptr<Component>> in_sp_component
    , _in<BOOL            > in_show_flag
    )
{
  if( in_sp_component == GetLinkMyself() )
  {
    this->m_sp_backlayer->SetStateVisible( in_show_flag != 0 );
  }

  return td_base::On_Show( in_sp_component, in_show_flag );
}

// _____________________________________________________________________________
/// @copydoc WindowEventInterface::On_Size
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GUC::eEventReturnID
  DialogWindow::On_Size( _in<sdptr<Component>> in_sp_component )
{
  auto res = td_base::On_Size( in_sp_component );

  if( in_sp_component == GetLinkMyself() )
  {
    AutoRepositionItems( 2 );
  }

  return res;
}

//// _____________________________________________________________________________
///// @brief コンストラクタ
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//DialogWindow::DialogWindow
//( _in<CreateInfo> in_create_info
//) : td_CPL_GUC_DialogBase
//    ( Factory<Container>::Create // バックレイヤーの作成。
//        ( in_create_info.in_sp_component_for_parent
//            ? in_create_info.in_sp_component_for_parent
//            : SmartCast<GUC::FrameEvent*>(WIN::GetWinFrame())->GetDrawForm(0)->GetLinkParent()
//        , &short2( 0, 0 )
//        , &short2( 10000, 10000 )
//        )
//    , in_create_info.in_ptr_pos
//    , in_create_info.in_ptr_size
//    )
//{
//  int const  space = 5;
//  auto&      ci = in_create_info;
//  auto const fw = GetFrameSize();
//  auto const th = ci.in_title ? GetTitleHeight() : 0;
//
//  // バックレイヤーの設定。
//  m_sp_backlayer = GetLinkParent();
//  auto sp_color =
//    CPL_MAKE_SHARED
//      ( DrawColorSet
//      , CDI::ColorType( 0.0f, 0.0f, 0.0f, 0.5f )
//      );
//  m_sp_backlayer->SetColorParameterBG( sp_color );
//  //m_sp_backlayer->SetStateVisible( true );
//  m_sp_backlayer->SetStateDrawBG( true );
//
//  // タイトルチェック。
//  if( ci.in_title )
//  {
//    SetTitle( ci.in_title );
//  }
//  SetTitle( SwS("abcdefg") );
//
//  // メッセージチェック。
//  if( ci.in_message )
//  {
//    auto sp_item_msg =
//      Factory<Label>::Create
//        ( GetClient()
//        , ci.in_message
//        , &short2( space, space )
//        , nullptr
//        );
//  }
//
//  // 構築用の簡易テンプレート指定のチェック。
//  bool is_template_build = (ci.in_type_num > 0 && ci.in_type_table);
//  if( is_template_build )
//  {
//    short4 rect_item_prev(0, space, 0, space);
//    short2 pos_item_new( space );
//    auto sp_item_top = GetClient()->GetLinkChild();
//    auto sp_item_end = sp_item_top ? sp_item_top->GetLinkEnd() : nullptr;
//    if( sp_item_end )
//    {
//      pos_item_new.y = sp_item_end->GetRectCoord().bottom + space;
//    }
//    auto* type_array = ci.in_type_table;
//    CPL_LOOP2( ci.in_type_num, idx )
//    {
//      auto type = type_array[ idx ];
//      if( sp_item_end )
//      {
//        auto rect_end = sp_item_end->GetRectCoord();
//        rect_item_prev.left  = rect_end.left;
//        rect_item_prev.right = rect_end.right;
//      }
//      short2 pos_new( rect_item_prev.right+space, rect_item_prev.top );
//      Core::String text, msg;
//      //
//      switch( type )
//      {
//      case bTN_OK:     text = SwS("OK");     break;
//      case bTN_CANCEL: text = SwS("Cancel"); break;
//      case bTN_YES:    text = SwS("Yes");    break;
//      case bTN_NO:     text = SwS("No");     break;
//      case bTN_RETRY:  text = SwS("Entry");  break;
//      }
//      // ボタン作成。
//      sp_item_end =
//        Factory<Button>::Create
//          ( GetClient()
//          , text
//          , msg
//          , &pos_new
//          , nullptr
//          );
//    }
//  }
//
//  // サイズが指定されていない場合、自動調整する。
//  if( ci.in_ptr_size == nullptr )
//  {
//    this->GetClient()->AdjustSize( short2(fw,fw) );
//    this->AdjustSize( short2(fw,fw) );
//    this->SetStateDrawBG( true );
//  }
//
//  // 位置が指定されていない場合、自動調整する。
//  if( ci.in_ptr_pos == nullptr )
//  {
//    auto sp_comp_area = ci.in_sp_component_for_parent; // エリア取得用コンポーネント。
//    while( sp_comp_area  &&  typeid(*sp_comp_area) == typeid(Layer) ) // レイヤーコンテナは除外。
//    {
//      sp_comp_area = sp_comp_area->GetLinkParent();
//    }
//    //
//    short2 size_backlayer;
//    if( sp_comp_area )
//    {
//      size_backlayer = sp_comp_area->GetSize();
//    }
//    else
//    {
//      size_backlayer = this->GetSubjectWindow()->GetClientSize();
//    }
//
//    //
//    auto center = size_backlayer / 2;
//    auto size_herf = this->GetSize() / 2;
//    this->SetPosition( center - size_herf );
//  }
//
//  auto const rect_self   = GetRectCoord();
//  auto const rect_client = GetClient()->GetRectCoord();
//  auto const size_adj    = GetClient()->GetAdjustSize( true );
//  auto const width       = rect_self.Width();
//  auto const height      = rect_self.Height();
//  short4 const rect_work
//    ( rect_client.left
//    , rect_client.top
//    , rect_client.left + size_adj.x + fw
//    , rect_client.top  + size_adj.y + fw
//    );
//  //SetupWorkingArea
//  AutoRepositionItems
//    ( &GetClientRect()//short4( fw, fw + th, width - fw * 2, height - fw * 2 ) // client area
//    , &rect_work // working area
//    );
//  //AutoRepositionItems();
//}


// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @copydoc doxycomment::arg_in_sp_component_for_parent
/// @param[in] in_title : ダイアログのタイトルを指定します。
/// @param[in] in_message : ダイアログ内に表示するメッセージを指定します。
/// @param[in] in_type_buttons
///   : ボタンタイプの組み合わせを指定します。\n
///   : 詳しくはeButtonTypeを参照してください。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MessageDialog::MessageDialog
( _in<sdptr<Component>> in_sp_component_for_parent
, pin<td_DefChar      > in_title
, pin<td_DefChar      > in_message
, _in<eButtonType     > in_type_buttons
) : DialogWindow
    ( in_sp_component_for_parent
    , in_title
    , Factory<TextBox>::Create
      ( in_sp_component_for_parent
      , float2(5.0f)
      , kSIZE_DEFAULT
      , CPL_GUC_DEF_STR(" ")
      ) // 親のコンポーネントは仮指定
    , in_type_buttons
    )
{
  if( auto p = std::dynamic_pointer_cast<TextBox>(GetComponent_ItemsForm()) )
  {
    p->SetText( in_message );
  }
}


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MessageDialog::MessageDialog( cref<MessageDialog> in_message_dialog )
  : td_base( in_message_dialog )
{
}


} // namespace GUC
} // namespace CPL
