/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2010/X/X - 2016/02/16
/// 
/// @brief  描画コンポーネント管理フレーム
/// 
/// ****************************************************************************


#include "CPL_GUC_FrameEvent.h"


namespace CPL {
namespace GUC {


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// FrameEventコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FrameEvent::FrameEvent
( _in<sdptr<DX::Graphics_i_>> in_sp_graphics
, _in<sdptr<DX::Input      >> in_sp_input
) : DX::FrameEvent( in_sp_graphics, in_sp_input )
//  , m_flag_updating( false )
{
  m_sp_static_param_hold = GUC::Component::sm_param();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// デストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FrameEvent::~FrameEvent()
{
  // ノードの解放
  if( m_sp_comp_form_root )
  {
    m_sp_comp_form_root->DetachAll();
  }
  //int z_order_num = m_sp_comp_form_list.GetNum();
  //for( int i = 0; i < z_order_num; ++i )
  //{
  //  m_sp_comp_form_list[ i ].ReleaseNode();
  //}
  //GUC::Component::StaticRelease();
}


// _____________________________________________________________________________
/// @brief GUCの初期化
/// 
/// @param[in] in_sp_graphics
///   : グラフィックスオブジェクトを指すスマートポインタを指定します。
/// @param[in] in_sp_font
///   : デフォルトで使用するフォントオブジェクトへのスマートポインタを指定します。
/// @param[in] in_num_masterlayer
///   : マスターレイヤーの数を指定します。\n
///   : 基本的にデフォルト値で良いため、省略します。
/// 
/// @retval true  : 初期化成功
/// @retval false : 初期化失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  FrameEvent::GUC_Initialized
    ( _in<sdptr<DX::Graphics_i_    >> in_sp_graphics
    , _in<sdptr<DX::FontDrawManager>> in_sp_font
    , _in<int                       > in_num_masterlayer
    )
{
  if( !in_sp_graphics )
  {
    return false;
  }
  if( in_num_masterlayer <= 0 )
  {
    return false;
  }

  GUC::Initialize( in_sp_graphics->GetDevice(), in_sp_font );

  // ルートコンテナの作成。
  // ※ ルートのみファクトリを用いてはいけない。
  m_sp_comp_form_root = CPL_MAKE_SHARED( GUC::Layer, this );
  m_sp_comp_form_root->SetLinkMyself( m_sp_comp_form_root );

  m_comp_form_wp_list.resize( in_num_masterlayer );

  auto size = GetClientSize();

  for( int i = 0; i < in_num_masterlayer; ++i )
  {
    auto sp_layer_master =
      Factory<GUC::MasterLayer>::Create( m_sp_comp_form_root );
    m_comp_form_wp_list[ i ] = sp_layer_master;

    sp_layer_master->SetSize( size );
  }

  return true;
}


//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//// アイテムコンポーネントとの当たり判定
//// io_mouse_x および io_mouse_y はルート階層での座標を入力、
//// ヒットした場合、ヒットしたコンポーネントのローカル座標に変換される
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//sdptr<GUC::Component>
//  FrameEvent::hitItemComponent_
//    ( _in<SpComponent_> in_sp_component
//    , rio<float       > io_mouse_x
//    , rio<float       > io_mouse_y
//    )
//{
//  if( !in_sp_component->IsVisible() )
//  {
//    return nullptr;
//  }
//
//  auto x = io_mouse_x;
//  auto y = io_mouse_y;
//  SpComponent_ ret_sp_comp;
//
//  if( in_sp_component )
//  {
//    if( in_sp_component->IsDrawOwner() )
//    {
//      ret_sp_comp = hitItemComponent_This_( in_sp_component, x, y );
//      if( ret_sp_comp )
//      {
//        auto x2 = io_mouse_x;
//        auto y2 = io_mouse_y;
//        SpComponent_ ret_sp_comp_child =
//          hitItemComponent_Child_( in_sp_component, x2, y2 );
//        if( ret_sp_comp_child )
//        {
//          ret_sp_comp = ret_sp_comp_child;
//          io_mouse_x = x2;
//          io_mouse_y = y2;
//        }
//        else
//        {
//          io_mouse_x = x;
//          io_mouse_y = y;
//        }
//      }
//    }
//    else
//    {
//      ret_sp_comp = hitItemComponent_Child_( in_sp_component, io_mouse_x, io_mouse_y );
//      if( !ret_sp_comp )
//      {
//        ret_sp_comp = hitItemComponent_This_( in_sp_component, io_mouse_x, io_mouse_y );
//      }
//    }
//  }
//
//  return ret_sp_comp;
//}
//
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//// アイテムコンポーネントとの当たり判定　※ 子供のみ対象
//// io_mouse_x および io_mouse_y はルート階層での座標を入力、
//// ヒットした場合、ヒットしたコンポーネントのローカル座標に変換される
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//sdptr<Component>
//  FrameEvent::hitItemComponent_Child_
//    ( _in<SpComponent_> in_sp_component
//    , rio<float       > io_mouse_x
//    , rio<float       > io_mouse_y
//    )
//{
//  SpComponent_ sp_comp_child = in_sp_component->GetLinkChild();
//  if( sp_comp_child )
//  {
//    sp_comp_child = sp_comp_child->GetLinkEnd();
//  }
//
//  float x = io_mouse_x;
//  float y = io_mouse_y;
//
//  while( sp_comp_child )
//  {
//    SpComponent_ sp_comp_hit = hitItemComponent_( sp_comp_child, x, y );
//
//    if( sp_comp_hit )
//    {
//      io_mouse_x = x;
//      io_mouse_y = y;
//      return sp_comp_hit;
//    }
//
//    sp_comp_child = sp_comp_child->GetLinkPrev();
//  }
//
//  return nullptr;
//}
//
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//// アイテムコンポーネントとの当たり判定　※ 自身のみ対象
//// io_mouse_x および io_mouse_y はルート階層での座標を入力、
//// ヒットした場合、ヒットしたコンポーネントのローカル座標に変換される
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//sdptr<Component>
//  FrameEvent::hitItemComponent_This_
//    ( _in<SpComponent_> in_sp_component
//    , rio<float       > io_mouse_x
//    , rio<float       > io_mouse_y
//    )
//{
//  if( in_sp_component->IsVisible() )
//  {
//    // 自身の判定
//    float top_offs_x = 0;
//    float top_offs_y = 0;
//    SpComponent_ tmp_sp_comp = in_sp_component->GetBelongComponent();
//    while( tmp_sp_comp )
//    {
//      auto pos = tmp_sp_comp->GetPosition();
//      top_offs_x += pos.x;
//      top_offs_y += pos.y;
//      tmp_sp_comp = tmp_sp_comp->GetBelongComponent();
//    }
//
//    if( in_sp_component->IsHit( io_mouse_x - top_offs_x, io_mouse_y - top_offs_y ) )
//    {
//      auto pos = in_sp_component->GetPosition();
//      io_mouse_x -= (top_offs_x + pos.x);
//      io_mouse_y -= (top_offs_y + pos.y);
//
//      return in_sp_component;
//    }
//  }
//
//  return nullptr;
//}


//// _____________________________________________________________________________
///// @brief 
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//void FrameEvent::zzf_UpdateWindowBuffer()
//{
//  if( !m_flag_updating )
//  {
//    size_t timer_ID = (-1<<16) + eID::UpdateWindowBuffer;
//    //size_t timer_ID = eID::UpdateWindowBuffer;
//    SetTimer( GetWindowHandle(), timer_ID, 100, nullptr );
//    m_flag_updating = true;
//  }
//}


/*
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// コンポーネント登録
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void FrameEvent::EntryDrawComponent(
      SpComponent in_sp_component,
      Z_ORDER_ID      in_z_order_ID )
{
  if( m_sp_comp_form_list[ in_z_order_ID ] )
  {
    m_sp_comp_form_list[ in_z_order_ID ].AddNodeEnd( in_sp_component );
  }
  else
  {
    m_sp_comp_form_list[ in_z_order_ID ] = in_sp_component;
  }
}*/


// _____________________________________________________________________________
/// @copydoc CPL::WIN::Component::On_MouseMove
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF FrameEvent::On_MouseMove()
{
  float x = static_cast<float>(WIN::Mouse::GetX());
  float y = static_cast<float>(WIN::Mouse::GetY());

//  CPL_OUTPUT( SwS("On_MouseMove(%d, %d)\n"), x, y );

  SpComponent_ sp_comp_cap = GUC::Component::GetCapture();
  if( sp_comp_cap )
  {
    float2 pos( x, y );
    GUC::Component::MappingPosition
      ( nullptr
      , sp_comp_cap
      , (float2_ptr)&pos
      , 1
      );

    sp_comp_cap->call_On_MouseMove( sp_comp_cap, pos.x, pos.y );
  }
  else
  {
    static wkptr<GUC::Component> wp_comp_old;

    SpComponent_ sp_comp_hit =
    //  hitItemComponent_( m_sp_comp_form_root, x, y );
      m_sp_comp_form_root->IsHitChild( x, y );

    if( sp_comp_hit )
    {
      if( wp_comp_old.lock() != sp_comp_hit )
      {
        GUC::Component::SetActiveComponent( sp_comp_hit );

        if( auto sp_comp = wp_comp_old.lock() )
        {
          sp_comp->call_On_MouseLeave( wp_comp_old.lock(), sp_comp_hit ); // マウスがコンポーネントから出た場合
        }

        wp_comp_old = sp_comp_hit;

        if( sp_comp_hit )
        {
          sp_comp_hit->call_On_MouseEnter( sp_comp_hit, wp_comp_old.lock() ); // マウスがコンポーネントへ侵入した場合
        }
      }

      sp_comp_hit->call_On_MouseMove( sp_comp_hit, x, y );
    }
  }

  return false;
}


// _____________________________________________________________________________
/// @copydoc CPL::WIN::Component::On_MouseDown
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF FrameEvent::On_MouseDown( _in<eMouseButton> in_mouse_btn )
{
  float x = static_cast<float>(WIN::Mouse::GetX());
  float y = static_cast<float>(WIN::Mouse::GetY());
  
  if( GUC::Component::GetCapture() )
  {
    float2 pos( x, y );
    GUC::Component::MappingPosition
      ( nullptr
      , GUC::Component::GetCapture()
      , (float2_ptr)&pos
      , 1
      );

    GUC::Component::GetCapture()->
      call_On_MouseDown( GUC::Component::GetCapture(), pos.x, pos.y, in_mouse_btn );
  }
  else
  {
    SpComponent_ sp_comp_hit = m_sp_comp_form_root->IsHitChild( x, y );
    // hitItemComponent_( m_sp_comp_form_root, x, y );

    if( sp_comp_hit )
    {
      sp_comp_hit->call_On_MouseDown( sp_comp_hit, x, y, in_mouse_btn );
    }
  }

  return false;
}


// _____________________________________________________________________________
/// @copydoc CPL::WIN::Component::On_MouseUp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF FrameEvent::On_MouseUp( _in<eMouseButton> in_mouse_btn )
{
  float x = static_cast<float>(WIN::Mouse::GetX());
  float y = static_cast<float>(WIN::Mouse::GetY());
  
  if( GUC::Component::GetCapture() )
  {
    float2 pos( x, y );
    GUC::Component::MappingPosition
      ( nullptr
      , GUC::Component::GetCapture()
      , (float2_ptr)&pos
      , 1
      );

    GUC::Component::GetCapture()->
      call_On_MouseUp( GUC::Component::GetCapture(), pos.x, pos.y, in_mouse_btn );
  }
  else
  {
    SpComponent_ sp_comp_hit =
    //  hitItemComponent_( m_sp_comp_form_root, x, y );
      m_sp_comp_form_root->IsHitChild( x, y );

    if( sp_comp_hit )
    {
      sp_comp_hit->call_On_MouseUp( sp_comp_hit, x, y, in_mouse_btn );
    }
  }

  return false;
}

// _____________________________________________________________________________
/// @copydoc CPL::WIN::Component::On_MouseWheel
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF FrameEvent::On_MouseWheel( _in<WORD> in_fw_keys, _in<short> in_z_delta )
{
  float x = static_cast<float>(WIN::Mouse::GetX());
  float y = static_cast<float>(WIN::Mouse::GetY());
  
  if( GUC::Component::GetCapture() )
  {
    float2 pos( x, y );
    GUC::Component::MappingPosition
      ( nullptr
      , GUC::Component::GetCapture()
      , (float2_ptr)&pos
      , 1
      );

    GUC::Component::GetCapture()->
      call_On_MouseWheel
        ( GUC::Component::GetCapture()
        , in_fw_keys
        , in_z_delta
        );
  }
  else
  {
    SpComponent_ sp_comp_hit =
    //  hitItemComponent_( m_sp_comp_form_root, x, y );
      m_sp_comp_form_root->IsHitChild( x, y );

    if( sp_comp_hit )
    {
      sp_comp_hit->call_On_MouseWheel
        ( GUC::Component::sm_sp_ac_comp()
        , in_fw_keys
        , in_z_delta
        );
    }
  }

  return false;
}


//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//// マウスダブルクリックイベント
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//SDEF FrameEvent::On_DblClick( MOUSe_BTN in_mouse_btn )
//{
//  int x = WIN::Mouse::GetX();
//  int y = WIN::Mouse::GetY();
//  
//  if( GUC::Component::GetCapture() )
//  {
//    short2 pos( x, y );
//    GUC::Component::MappingPosition(
//      nullptr, GUC::Component::GetCapture(),
//      (short2_ptr)&pos, 1 );
//
//    GUC::Component::GetCapture()->
//      call_On_DblClick( GUC::Component::GetCapture(), pos.x, pos.y );
//  }
//  else
//  {
//    SpComponent sp_comp_hit =
//      hitItemComponent_( m_sp_comp_form_root, x, y );
//
//    if( sp_comp_hit )
//    {
//      sp_comp_hit->call_On_DblClick( sp_comp_hit, x, y );
//    }
//  }
//
//  return false;
//}


// _____________________________________________________________________________
/// @copydoc CPL::WIN::Component::On_KeyDown
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF FrameEvent::On_KeyDown( _in<int> in_virtual_key_code )
{
  if( GUC::Component::GetFocus() )
  {
    GUC::Component::GetFocus()->
      call_On_KeyDown( GUC::Component::GetFocus(), in_virtual_key_code );
  }

  return false;
}


// _____________________________________________________________________________
/// @copydoc CPL::WIN::Component::On_KeyUp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF FrameEvent::On_KeyUp( _in<int> in_virtual_key_code )
{
  if( GUC::Component::GetFocus() )
  {
    GUC::Component::GetFocus()->
      call_On_KeyUp( GUC::Component::GetFocus(), in_virtual_key_code );
  }

  return false;
}


// _____________________________________________________________________________
/// @copydoc CPL::WIN::Component::On_Char
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF FrameEvent::On_Char( _in<int> in_char_code, _in<int> in_key_data )
{
  if( GUC::Component::GetFocus() )
  {
    auto* is_type_edit = dynamic_cast<EditBase*>(&*GUC::Component::GetFocus());
    if( is_type_edit )
    {
      GUC::Component::GetFocus()->call_On_Char
        ( GUC::Component::GetFocus()
        , in_char_code
        , in_key_data
        );
    }
  }

  return false;
}


// _____________________________________________________________________________
/// @copydoc CPL::WIN::Window::On_Paint
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF FrameEvent::On_Paint()
{
  if( m_sp_comp_form_root == nullptr )
  {
    return false;
  }

  auto sp_comp_layer =
    std::dynamic_pointer_cast<GUC::Container>(m_sp_comp_form_root->GetLinkChild());

  while( sp_comp_layer )
  {
    sp_comp_layer->On_Paint( nullptr, sp_comp_layer->GetPosition() );
//    sp_comp_layer->zzf_CallChildPaint( nullptr, GUC::Container::CCPID_ALL_ITEM );
    
//    m_sprite_mng.Transrate( GetDevice() );

    sp_comp_layer =
      std::dynamic_pointer_cast<GUC::Container>(sp_comp_layer->GetLinkNext());
  }

  return false;
}


// _____________________________________________________________________________
/// @copydoc CPL::WIN::Component::On_Timer
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF FrameEvent::On_Timer( _in<int> in_timer_ID )
{
//  GUC::FrameEvent::On_Timer( in_ID );

  int comp_ID  = in_timer_ID >> 16;
  int timer_ID = in_timer_ID & 0xffff;

  GUC::Component* ptr_comp = GUC::Component::ID_to_Pointer( comp_ID );
  if( ptr_comp )
  {
    ptr_comp->On_Timer( timer_ID );
  }

  return false;
}


// _____________________________________________________________________________
/// @copydoc CPL::WIN::Container::On_Command
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF
  FrameEvent::On_Command
    ( _in<int > in_ctrl_ID
    , _in<int > in_notify_code
    , _in<HWND> in_hdl_ctrl_win
    )
{
  //if( WIN::kID_CPL <= in_ctrl_ID  &&  in_ctrl_ID < WIN::kID_CPL_USER )
  //{
  //  if( auto ptr_win = GetHandleToPointer( in_hdl_ctrl_win ) )
  //  {
  //    ptr_win->
  //  }
  //}

  return
    CPL_GUC_FrameEventBase::On_Command
      ( in_ctrl_ID
      , in_notify_code
      , in_hdl_ctrl_win
      );
}


// _____________________________________________________________________________
/// @copydoc CPL::WIN::Component::On_UserProc
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF
  FrameEvent::On_UserProc
    ( _in<HWND  > in_hdl_window
    , _in<UINT  > in_message
    , _in<WPARAM> in_wparam
    , _in<LPARAM> in_lparam
    )
{
  //switch( in_message )
  //{
  //case eID::UpdateWindowBuffer:
  //  if( in_lparam )
  //  {
  //    if( !m_flag_updating )
  //    {
  //      size_t timer_ID = (-1<<16) + eID::UpdateWindowBuffer;
  //      SetTimer( GetWindowHandle(), timer_ID, 100, nullptr );
  //      m_flag_updating = true;
  //    }
  //  }
  //  break;
  //}

  return false;
}


// _____________________________________________________________________________
/// @copydoc CPL::WIN::Component::On_Size
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF FrameEvent::On_Size( _in<eSizeMode> in_size_mode )
{
  if( m_sp_comp_form_root  &&  m_sp_comp_form_root->GetLinkChild() )
  {
    float2 size_client = GetClientSize();

    for( auto& wp_comp : m_comp_form_wp_list )
    {
      auto sp_comp = wp_comp.lock();
      sp_comp->GetComponent_for_DrawingOwner()->SetSize( size_client );
      sp_comp->GetComponent_for_OverLayer()->SetSize( size_client );
    }
  }

  return false;
}


} // namespace GUC
} // namespace CPL



