/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2016/12/17
/// 
/// @brief  コンボボックスコンポーネント
/// 
/// ****************************************************************************


#include "CPL_WIN_ComboBox.h"


namespace CPL {
namespace WIN {


// _____________________________________________________________________________
/// @brief コンストラクタ：コンボコンポーネント作成
/// 
/// @param[in] in_hdl_window_parent
///   : 親ウィンドウのハンドルを指定します。
/// @param[in] in_pos  : 左上の座標を指定します。
/// @param[in] in_size : ウィンドウサイズを指定します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ComboBox::ComboBox
( _in<HWND     > in_hdl_window_parent
, _in<td_Coord2> in_pos
, _in<td_Coord2> in_size
) : Component( 1 )
{
  zzf_Create
    ( in_hdl_window_parent, SwS("")
    , in_pos, in_size, 0
    , WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_VSCROLL | CBS_DROPDOWNLIST
    , 0, nullptr
    );
  
  if( !zzf_SetHandle( m_hdl_window ) )
  {
    CPL_THROW( CPL_WIN_MSG_NOT_CREATE_COMBOBOX );
  }

  // 初期カーソル位置セット
  SetIdx( 0 );
}


// _____________________________________________________________________________
/// @brief アイテム選択
/// 
/// @param[in] in_index : 選択するアイテムのインデックスを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ComboBox::SetIdx( _in<int> in_index )
{
  SendMessage( m_hdl_window, CB_SETCURSEL, (WPARAM)in_index, 0L );
}


// _____________________________________________________________________________
/// @brief アイテムの追加
/// 
/// @param[in] in_index
///   : 追加する位置のインデックスを指定します。
/// @param[in] in_ptr_str 
///   : 追加するアイテムの文字列を指定します。
/// 
/// @retval true  : 追加成功。
/// @retval false : 追加失敗。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool ComboBox::AddItem( _in<int> in_index, pin<char> in_ptr_str )
{
  LRESULT hr =
    SendMessageA
      ( m_hdl_window
      , CB_INSERTSTRING
      , (WPARAM)in_index
      , (LPARAM)in_ptr_str
      );

  if( hr == CB_ERR )
  {
    return false;
  }
  return true;
}
/// @copydoc CPL::WIN::ComboBox::AddItem
bool ComboBox::AddItem( _in<int> in_index, pin<wchar_t> in_ptr_str )
{
  LRESULT hr =
    SendMessageW
      ( m_hdl_window
      , CB_INSERTSTRING
      , (WPARAM)in_index
      , (LPARAM)in_ptr_str
      );

  if( hr == CB_ERR )
  {
    return false;
  }
  return true;
}


// _____________________________________________________________________________
/// @brief 選択されているアイテムのインデックスを取得
/// 
/// @return 選択されているアイテムのインデックスを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int  ComboBox::GetIdx() const
{
  return (int)(DWORD)SendMessage( m_hdl_window, CB_GETCURSEL, 0, 0L);
}


// _____________________________________________________________________________
/// @brief アイテム数を取得
/// 
/// @return 現在登録されているアイテム数を返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int  ComboBox::GetNum() const
{
  return (int)(DWORD)SendMessage( m_hdl_window, CB_GETCOUNT, 0, 0L );
}


// _____________________________________________________________________________
/// @brief アイテムの全消去
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ComboBox::Release()
{
  SendMessage( m_hdl_window, CB_RESETCONTENT, 0, 0L );
}


// _____________________________________________________________________________
/// @brief アイテムの文字列を取得
/// 
/// @param[in] in_index
///   : 取得するアイテムのインデックスを指定します。
/// @param[in] out_ptr_buf
///   : 文字列取得用のバッファアドレスを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  ComboBox::GetItemString
    ( _in <int > in_index
    , pout<char> out_ptr_buf
    ) const
{
  char tmp_str[1024];
  SendMessageA( m_hdl_window, CB_GETLBTEXT, (WPARAM)in_index, (LPARAM)tmp_str );
  Core::StringA::str_cpy_( out_ptr_buf, tmp_str );
}
/// @copydoc ComboBox::GetItemString(_in<int>,pout<char>)const
void
  ComboBox::GetItemString
    ( _in <int    > in_index
    , pout<wchar_t> out_ptr_buf
    ) const
{
  wchar_t tmp_str[1024];
  SendMessageW( m_hdl_window, CB_GETLBTEXT, (WPARAM)in_index, (LPARAM)tmp_str );
  Core::StringW::str_cpy_( out_ptr_buf, tmp_str );
}

//void
//  ComboBox::GetItemString(
//    int            in_index,
//    Core::StringA& out_string ) const
//{
//  char tmp_str[1024];
//  SendMessageA( m_hdl_window, CB_GETLBTEXT, (WPARAM)in_index, (LPARAM)tmp_str );
//  out_string = tmp_str;
//}
//void
//  ComboBox::GetItemString(
//    int            in_index,
//    Core::StringW& out_string ) const
//{
//  wchar_t tmp_str[1024];
//  SendMessageW( m_hdl_window, CB_GETLBTEXT, (WPARAM)in_index, (LPARAM)tmp_str );
//  out_string = tmp_str;
//}
//void
//  ComboBox::GetItemString(
//    int          in_index,
//    std::string& out_string ) const
//{
//  char tmp_str[1024];
//  SendMessageA( m_hdl_window, CB_GETLBTEXT, (WPARAM)in_index, (LPARAM)tmp_str );
//  out_string = tmp_str;
//}
//void
//  ComboBox::GetItemString(
//    int           in_index,
//    std::wstring& out_string ) const
//{
//  wchar_t tmp_str[1024];
//  SendMessageW( m_hdl_window, CB_GETLBTEXT, (WPARAM)in_index, (LPARAM)tmp_str );
//  out_string = tmp_str;
//}



// _____________________________________________________________________________
/// @brief アイテムの削除
/// 
/// @param[in] in_index
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ComboBox::DeleteItem( _in<int> in_index )
{
  SendMessage( m_hdl_window, CB_DELETESTRING, (WPARAM)in_index, 0 );
}


// _____________________________________________________________________________
/// @brief 指定したアイテムの名前を変更
/// 
/// @param[in] in_index : 変更するアイテムのインデックスを指定します。
/// @param[in] in_ptr_str : 文字列取得用のバッファアドレスを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ComboBox::ChangeItem( _in<int> in_index, pin<char> in_ptr_str )
{
  DeleteItem( in_index );
  AddItem( in_index, in_ptr_str );
  SetIdx( in_index );
}
/// @copydoc CPL::WIN::ComboBox::ChangeItem(_in<int>,pin<char>)
void ComboBox::ChangeItem( _in<int> in_index, pin<wchar_t> in_ptr_str )
{
  DeleteItem( in_index );
  AddItem( in_index, in_ptr_str );
  SetIdx( in_index );
}


// _____________________________________________________________________________
/// @brief クローンの取得
/// 
/// @param[in] in_hdl_window_parent
///   : 親ウィンドウのハンドルを指定します。
/// @param[in] in_offs_x
///   : ｘ座標のオフセットを指定します。
/// @param[in] in_offs_y
///   : ｙ座標のオフセットを指定します。
/// 
/// @return 生成された新しいコンボボックスのポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component*
  ComboBox::CreateClone
    ( _in<HWND> in_hdl_window_parent
    , _in<int > in_offs_x
    , _in<int > in_offs_y
    ) const
{
  try{
    auto hdl_window_parent = in_hdl_window_parent;
    Rect rt;
    this->GetWindowRect( rt );
    if( hdl_window_parent == nullptr )
    {
      hdl_window_parent = this->GetParentWindowHandle();
    }

    ComboBox* pCB =
      CPL_NEW(ComboBox)
        ( in_hdl_window_parent
        , td_Coord2( int(rt.left + in_offs_x), int(rt.top + in_offs_y) )
        , td_Coord2( int(rt.GetWidth()),       int(rt.GetHeight()) )
        );
    if( pCB )
    {
      pCB->SetFont( this->GetFont() );
      // リストコピー
      Core::String str;
      int list_num = this->GetNum();
      for( int i = 0; i < list_num; ++i )
      {
        this->GetItemString( i, str );
        pCB->AddItem( -1, str );
      }
      return pCB;
    }
    else
    {
      return nullptr;
    }
  }
  catch(...)
  {
    return nullptr;
  }
}


} // namespace WIN
} // namespace CPL

