/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2014/01/24
/// 
/// @brief  Win32 MDIウィンドウ管理。
/// 
/// ****************************************************************************

#pragma once

#include "CPL_WIN_Window.h"


namespace CPL {
namespace WIN {


// _____________________________________________________________________________
/// @brief MDIクライアントウィンドウ
///
// *****************************************************************************
class MdiClientWindow
  : virtual public Window
{
private:
  CPL_WIN_COMPONENT_GET_CLASS_NAME( "CPL_WIN_MdiClientWindow" );

protected:
  static LRESULT CALLBACK
    zzf_StaticProcMdiClient
      ( HWND   in_hdl_window
      , UINT   in_message
      , WPARAM in_wparam
      , LPARAM in_lparam
      );
  CPL_SINGLETON_INIT( WNDPROC, zzf_MDICLIENT_PROC, nullptr )

  CLIENTCREATESTRUCT m_ccs_client;
  Rect               m_client_rect;    // クライアントウィンドウの位置とサイズを保存
  BOOL               m_flag_auto_resize;

  virtual bool
    zzf_DefaultProcMdiClient
      ( UINT   in_message
      , WPARAM in_wparam
      , LPARAM in_lparam
      );

protected:
  virtual void
    SetWindowRect
      ( _in<Rect> in_rect
      , _in<bool> in_flag_redraw
      , _in<int > in_fRectFactor
      ) override
  {
    SetWindowRect( in_rect, in_flag_redraw );
  }
public:
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual bool CreateMdiClient( _in<HWND> in_hdl_win_parent );
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual void
    SetWindowPos( _in<td_Coord2> in_pos, _in<bool> in_flag_redraw = true ) override;
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual void
    SetWindowSize
      ( _in<td_Coord2> in_size
      , _in<bool     > in_flag_redraw = true
      , _in<bool     > in_flag_client_size = false
      ) override;
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual void
    SetWindowRect
      ( _in<td_Coord2> in_pos0
      , _in<td_Coord2> in_pos1
      , _in<bool     > in_flag_redraw = true
      ) override;

  // _____________________________________________________________________________
  /// @brief ウィンドウの４点座標の設定
  /// 
  /// @copydoc doxycomment::arg_in_rect
  /// @param[in] in_flag_redraw
  ///   : 再描画を行うかどうかを指定します。\n
  ///   : true  - 再描画する。\n
  ///   : false - 再描画しない。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual void
    SetWindowRect
      ( _in<Rect> in_rect
      , _in<bool> in_flag_redraw = false
      )
  {
    SetWindowRect
      ( td_Coord2(int(in_rect.left) ,int(in_rect.top))
      , td_Coord2(int(in_rect.right),int(in_rect.bottom))
      , in_flag_redraw
      );
  }

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual void GetAutoResizeRect( rout<Rect> out_rect ) const
  {
    out_rect = m_client_rect;
  }

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual BOOL GetAutoResize() const { return m_flag_auto_resize; }
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual void SetAutoResize( _in<bool> in_flag_resize )
  {
    m_flag_auto_resize = in_flag_resize;
  }

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  MdiClientWindow();


  // _____________________________________________________________________________
  /// @brief MDIクライアントウィンドウ　Pimpl実装用
  ///
  // *****************************************************************************
  class Binder
    : public Window::Binder
  {
  private:
    MdiClientWindow*       getEntity()       { return dynamic_cast<MdiClientWindow*      >(&*impl); }
    MdiClientWindow const* getEntity() const { return dynamic_cast<MdiClientWindow const*>(&*impl); }

  public:
    bool CreateMdiClient( _in<HWND> in_hdl_win_parent )
    {
      return getEntity()->CreateMdiClient( in_hdl_win_parent );
    }
    void SetWindowPos( _in<td_Coord2> in_pos, _in<bool> in_flag_redraw = true )
    {
      getEntity()->SetWindowPos( in_pos, in_flag_redraw );
    }
    void SetWindowSize( _in<td_Coord2> in_size, _in<bool> in_flag_redraw = true )
    {
      getEntity()->SetWindowSize( in_size, in_flag_redraw );
    }
    void
      SetWindowRect
        ( _in<td_Coord2> in_pos0
        , _in<td_Coord2> in_pos1
        , _in<bool     > in_flag_redraw = true
        )
    {
      getEntity()->SetWindowRect( in_pos0, in_pos1, in_flag_redraw );
    }
    void SetWindowRect( _in<Rect> in_rect, _in<bool> in_flag_redraw = true )
    {
      getEntity()->SetWindowRect( in_rect, in_flag_redraw );
    }
    void GetAutoResizeRect( rout<Rect> out_rect ) const
    {
      getEntity()->GetAutoResizeRect( out_rect );
    }

    BOOL GetAutoResize()                     { return getEntity()->GetAutoResize(); }
    void SetAutoResize( BOOL in_flag_resize ){ getEntity()->GetAutoResize(); }

    Binder()
      : Window::Binder( CPL_NEW(MdiClientWindow) ){}
  protected:
    // 継承用
    Binder( MdiClientWindow* in_ptr_mdi_client_window )
      : Window::Binder( in_ptr_mdi_client_window )
    {}
  };

};



// _____________________________________________________________________________
/// @brief MDIウィンドウ
///
// *****************************************************************************
class MdiWindow
  : virtual public Window
{
private:
  CLIENTCREATESTRUCT m_ccs_client;
  BOOL               m_flag_mdi_client;

protected:
  static LRESULT CALLBACK
    zzf_StaticProcMdi(
      HWND in_hdl_window, UINT in_message, WPARAM in_wparam, LPARAM in_lparam );

  Core::Array::DynamicKey<int,MdiClientWindow*> m_client_window_table;

  char_cptr zzf_GetClassNameA() const
  {
    if( m_flag_mdi_client )
      return "CPL_WIN_MdiWindow";
    return Window::zzf_GetClassNameA();
  }
  wchar_t_cptr zzf_GetClassNameW() const
  {
    if( m_flag_mdi_client )
      return L"CPL_WIN_MdiWindow";
    return Window::zzf_GetClassNameW();
  }
  str_cptr zzf_GetClassName() const
  {
    if( m_flag_mdi_client )
      return SwS("CPL_WIN_MdiWindow");
    return Window::zzf_GetClassName();
  }
  virtual MdiClientWindow* On_CreateMdiClient(){ return CPL_NEW(MdiClientWindow); }

public:
  bool
    CreateMdi
      ( _in<td_Coord2> in_ptr_pos          = kPOS_DEFAULT
      , _in<td_Coord2> in_ptr_size         = kSIZE_DEFAULT
      , _in<bool     > in_flag_client_size = false
      , _in<STYLE    > in_win_style        = WS_OVERLAPPEDWINDOW | WS_VISIBLE
      );

  virtual HWND
    GetClientWndHandle() const { return GetWindow( m_hdl_window, GW_CHILD ); }
  virtual MdiClientWindow*
    GetClientWindow( int ID = 0 )
  {
    MdiClientWindow** pp_mdi_clt_win = m_client_window_table.Find( ID );
    return pp_mdi_clt_win ? *pp_mdi_clt_win : nullptr;
  }
  virtual MdiClientWindow const*
    GetClientWindow( int ID = 0 ) const
  {
    MdiClientWindow* const* pp_mdi_clt_win = m_client_window_table.Find( ID );
    return pp_mdi_clt_win ? *pp_mdi_clt_win : nullptr;
  }

  MdiWindow();
  virtual ~MdiWindow();
  

  // _____________________________________________________________________________
  /// @brief MDIウィンドウ　Pimpl実装用
  ///
  // *****************************************************************************
  class Binder
    : public Window::Binder
  {
  private:
    MdiWindow*       getEntity()       { return dynamic_cast<MdiWindow*      >(&*impl); }
    MdiWindow const* getEntity() const { return dynamic_cast<MdiWindow const*>(&*impl); }

  public:
    bool  CreateMdi
      ( _in<td_Coord2> in_pos              = kPOS_DEFAULT
      , _in<td_Coord2> in_size             = kSIZE_DEFAULT
      , _in<bool     > in_flag_client_size = false
      , _in<STYLE    > in_win_style        = WS_OVERLAPPEDWINDOW | WS_VISIBLE
      )
    {
      return getEntity()->CreateMdi( in_pos, in_size, in_flag_client_size, in_win_style );
    }

    HWND             GetClientWndHandle()            { return getEntity()->GetClientWndHandle(); }
    MdiClientWindow* GetClientWindow   ( int ID = 0 ){ return getEntity()->GetClientWindow( ID ); }

    Binder() : Window::Binder( CPL_NEW(MdiWindow) ) {}
  protected:
    // 継承用
    Binder( MdiWindow* in_ptr_mdi_window ) : Window::Binder( in_ptr_mdi_window ) {}
  };

};



} // namespace WIN
} // namespace CPL
