/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2016/11/28
/// 
/// @brief  Win32 ウィンドウクラス。
/// 
/// ****************************************************************************




#include "../../CPL_WINDOWS.h"


namespace CPL {
namespace WIN {


  
// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @copydetails Container::Container(bool)
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Window::Window( _in<bool> in_msg_throw )
  : Container( in_msg_throw )
{
  CPL_BLOCK_ONCE
  {
    WNDCLASSEX wcex;
    // 通常ウィンドウ用のウィンドウクラス登録
    memset( &wcex, 0, sizeof(wcex) );
    wcex.cbSize        = sizeof(WNDCLASSEX);
    wcex.hInstance     = GetInstance_();
    wcex.style         = CS_HREDRAW | CS_VREDRAW;

    // MDI子ウィンドウ用にウィンドウクラス登録
    wcex.lpfnWndProc   = (WNDPROC)zzf_StaticProcMdiChild;
    wcex.lpszClassName = SwS("CPL_WIN_MdiChild");

    if( !::RegisterClassEx( &wcex ) )
    {
      throw 0;
    }
  }
}



// _____________________________________________________________________________
/// @brief ウィンドウ作成
/// 
/// @copydetails CPL::WIN::doxycomment::arg_in_hdl_win_parent
/// @copydetails CPL::WIN::doxycomment::arg_in_pos
/// @copydetails CPL::WIN::doxycomment::arg_in_size
/// @copydetails CPL::WIN::doxycomment::arg_in_flag_client_size
/// @copydetails CPL::WIN::doxycomment::arg_in_win_style
/// 
/// @retval true  : 作成成功。
/// @retval false : 作成失敗。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  Window::Create
    ( _in<HWND     > in_hdl_win_parent
    , _in<td_Coord2> in_pos
    , _in<td_Coord2> in_size
    , _in<bool     > in_flag_client_size
    , _in<STYLE    > in_win_style
    )
{
  bool flag_create =
    zzf_Create
      ( in_hdl_win_parent
      , SwS("")
      , in_pos
      , in_size
      , 0
      , in_win_style.style
      , in_win_style.ExStyle.style
      , this
      );
  if( !flag_create )
  {
    return false;
  }

  if( in_flag_client_size )
  {
    SetWindowSize( in_size, true, true );
  }
  
  return true;
}



// _____________________________________________________________________________
/// @brief MDI子ウィンドウの作成
/// 
/// @copydetails Window::Create
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  Window::CreateMdiChild
    ( _in<HWND     > in_hdl_win_parent
    , _in<td_Coord2> in_pos
    , _in<td_Coord2> in_size
    , _in<bool     > in_flag_client_size
    , _in<STYLE    > in_win_style
    )
{
  // クライアントウィンドウのハンドルを求める
  Component* in_ptr_comp = GetHandleToPointer( in_hdl_win_parent );
  MdiWindow* in_ptr_win  = dynamic_cast<MdiWindow*>(in_ptr_comp);
  if( !in_ptr_win )
  {
    return false;
  }
  HWND in_hdl_win_client = in_ptr_win->GetClientWndHandle();

  // MDI子ウィンドウ作成
  m_hdl_window =
    ::CreateMDIWindow
      ( SwS("CPL_WIN_MdiChild")
      , SwS("") // title
      , static_cast<DWORD>(in_win_style.style) | MDIS_ALLCHILDSTYLES
      , in_pos.x, in_pos.y
      , in_size.x-in_pos.x, in_size.y-in_pos.y
      , in_hdl_win_client
      , GetInstance_()
      , (LPARAM)this
      );

  if( !zzf_SetHandle( m_hdl_window ) )
    return false;

  if( in_flag_client_size )
  {
    SetWindowSize( in_size, true, true );
  }

  return true;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// デフォルトプロシージャ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF Window::DefaultProc_( _in<UINT> in_message, _in<WPARAM> in_wparam, _in<LPARAM> in_lparam )
{
  switch( in_message )
  {
  case WM_NCLBUTTONDOWN: // 非クライアントエリアのマウス左ボタンダウン
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      return On_NcMouseDown( eMouseButton::Left );
    }

  case WM_NCRBUTTONDOWN: // 非クライアントエリアのマウス右ボタンダウン
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      return On_NcMouseDown( eMouseButton::Right );
    }

  case WM_NCLBUTTONUP: // 非クライアントエリアのマウス左ボタンアップ
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      return On_NcMouseUp( eMouseButton::Left );
    }

  case WM_NCRBUTTONUP: // 非クライアントエリアのマウス右ボタンアップ
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      return On_NcMouseUp( eMouseButton::Right );
    }

  case WM_NCMOUSEMOVE:
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      return On_NcMouseMove();
    }

  case WM_NCLBUTTONDBLCLK:
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      return On_NcDblClick( eMouseButton::Left );
    }

  case WM_NCRBUTTONDBLCLK:
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      return On_NcDblClick( eMouseButton::Right );
    }

  case WM_NCPAINT:
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_NcPaint();
    }
    
  case WM_NCACTIVATE:
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_NcActive( (int)in_wparam );
    }

  case WM_CLOSE: // ウィンドウを閉じる
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_Close();
    }

  default:
    break;
  }

  return Container::DefaultProc_( in_message, in_wparam, in_lparam );
}



// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// MDI子ウィンドウ 基本プロシージャ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LRESULT CALLBACK
  Window::zzf_StaticProcMdiChild
    ( HWND   in_hdl_window
    , UINT   in_message
    , WPARAM in_wparam
    , LPARAM in_lparam )
{
  SDEF flag = false;
  Window* ptr_comp = nullptr;

  if( in_message == WM_CREATE )
  {
    CREATESTRUCT*    cs  = reinterpret_cast<CREATESTRUCT*>(in_lparam);
    MDICREATESTRUCT* mcs = static_cast<MDICREATESTRUCT*>(cs->lpCreateParams);
    ptr_comp = reinterpret_cast<Window*>(mcs->lParam);
    if( ptr_comp )
    {
      CallStackMsg csm( ptr_comp, in_message, in_wparam, in_lparam );
      ptr_comp->zzf_SetHandle( in_hdl_window );
      flag = ptr_comp->On_Create();
    }
  }
  else
  {
    ptr_comp = static_cast<Window*>(GetHandleToPointer( in_hdl_window ));
    if( ptr_comp  &&  ptr_comp->GetEventMode() != eEventMode::AllCut )
    {
      flag = ptr_comp->DefaultProc_( in_message, in_wparam, in_lparam );
    }
  }

  if( !flag )
  {
    return ::DefMDIChildProc( in_hdl_window, in_message, in_wparam, in_lparam );
  }
  return 0;
}



// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// アクティブ化イベント
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF
  Window::On_Active
    ( _in<int > in_flag_active
    , _in<int > in_flag_min
    , _in<HWND> in_hdl_win_prev
    )
{
  // モーダルウィンドウ処理
  if( sm_ptr_modal_window() )
  {
    if( in_flag_active  &&  sm_ptr_modal_window() != this )
    {
      if( sm_ptr_modal_window()->IsVisible() )
      {
        // モーダルウィンドウをアクティブにする
        ::SetCapture( sm_ptr_modal_window()->GetWindowHandle() );
        ::SetActiveWindow( sm_ptr_modal_window()->GetWindowHandle() );
//        ::MessageBeep( MB_OK );
      }
    }
  }

  return false;
}


// _____________________________________________________________________________
/// @brief リサイズフレームの切り替え
/// 
/// @param[in] in_flag_resize
///   : true  - マウスによるサイズ変更を可能にします。\n
///   : false - マウスによるサイズ変更を不可にします。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Window::ChangeResizeStyle( _in<bool> in_flag_resize )
{
  LONG_PTR style = GetWindowLongPtr( m_hdl_window, GWL_STYLE );
  if( in_flag_resize ){ style |= WS_THICKFRAME;  }
  else                { style &= ~WS_THICKFRAME; }
  ::SetWindowLongPtr( m_hdl_window, GWL_STYLE, style );
}


// _____________________________________________________________________________
/// @brief メニューボックスの表示切り替え
/// タイトル バーにコントロール メニュー ボックスのあるウィンドウ
/// 
/// @param[in] in_sys_menu
///   : true  - タイトルバーのコントロールメニューボックスを表示します。\n
///   : false - タイトルバーのコントロールメニューボックスを無効にします。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Window::ChangeSysMenuStyle( _in<bool> in_sys_menu )
{
  LONG_PTR style = GetWindowLongPtr( m_hdl_window, GWL_STYLE );
  if( in_sys_menu ){ style |= WS_SYSMENU;  }
  else             { style &= ~WS_SYSMENU; }
  ::SetWindowLongPtr( m_hdl_window, GWL_STYLE, style );
}


// _____________________________________________________________________________
/// @brief 最小化ボタン切り替え
/// 
/// @param[in] in_min_box
///   : bool  - 最小化ボタンを表示します。\n
///   : false - 最小化ボタンを無効にします。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Window::ChangeMinBoxStyle( _in<bool> in_min_box )
{
  LONG_PTR style = GetWindowLongPtr( m_hdl_window, GWL_STYLE );
  if( in_min_box ){ style |= WS_MINIMIZEBOX;  }
  else            { style &= ~WS_MINIMIZEBOX; }
  ::SetWindowLongPtr( m_hdl_window, GWL_STYLE, style );
}


// _____________________________________________________________________________
/// @brief 最大化ボタン切り替え
/// 
/// @param[in] in_max_box
///   : bool  - 最大化ボタンを表示します。\n
///   : false - 最大化ボタンを無効にします。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Window::ChangeMaxBoxStyle( _in<bool> in_max_box )
{
  LONG_PTR style = GetWindowLongPtr( m_hdl_window, GWL_STYLE );
  if( in_max_box ){ style |= WS_MAXIMIZEBOX;  }
  else            { style &= ~WS_MAXIMIZEBOX; }
  ::SetWindowLongPtr( m_hdl_window, GWL_STYLE, style );
}


// _____________________________________________________________________________
/// @brief 閉じるボタン表示切り替え
/// 
/// @param[in] in_flag_close
///   : bool  - 閉じるボタンを表示します。\n
///   : false - 閉じるボタンを無効にします。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Window::ChangeCloseBoxStyle( _in<bool> in_flag_close )
{
  HMENU hdl_menu = ::GetSystemMenu( m_hdl_window, in_flag_close );
  ::RemoveMenu( hdl_menu, SC_CLOSE, MF_BYCOMMAND );
}


// _____________________________________________________________________________
/// @brief アイコン変更
/// 
/// @param[in] in_hdl_icon : 設定するアイコンのハンドルを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Window::ChangeIcon( _in<HICON> in_hdl_icon )
{
  SendMessage( m_hdl_window, WM_SETICON, ICON_SMALL, (LPARAM)in_hdl_icon );
}


// _____________________________________________________________________________
/// @brief ウィンドウのモーダル化設定
/// 
/// @param[in] in_flag_modal
///   : true  - ウィンドウをモーダル化します。
///   : false - ウィンドウのモーダル化を解除します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Window::SetModalWindow( _in<bool> in_flag_modal )
{
  if( in_flag_modal )
  {
    sm_ptr_modal_window() = this;
  }
  else
  {
    sm_ptr_modal_window() = nullptr;
  }
}



} // namespace WIN
} // namespace CPL

