#pragma once
/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2015/10/10 - 2016/12/16
/// 
/// @brief  簡易エディタ
/// 
/// ****************************************************************************

#include "CPL_GUC_TextBox.h"
#include "CPL_GUC_Window.h"

namespace CPL {
namespace GUC {

// _____________________________________________________________________________
/// @brief エディタ
/// 
// *****************************************************************************
class Editor
  : public RenderOwner
  , public EditBase
{
  using td_base = RenderOwner;
  using td_self = Editor;
  friend Factory<td_self>;
  friend CallPrivateConstructor<td_self>;

  using SpString = sdptr<td_DefString>;
  using ArraySpString = std::deque<SpString>;
  using SpFontMng     = sdptr<DX::FontDrawManager>;

  static constexpr int kDRAW_OFFS_X = 2;
  static constexpr int kDRAW_OFFS_Y = 2;
public:
  Editor
  ( _in<sdptr<Component>> in_sp_component_for_parent
  , _in<float2          > in_position_for_component
  , _in<float2          > in_size_for_component
  , _in<SpFontMng       > in_sp_font_mng_default = nullptr
  );
  Editor( cref<Editor> in_editor );

  void Copy();
  void Paste();
  void Delete();
  void AllSelect();
  
  int2 InsertChar( pin<td_DefChar> in_char, pin<int2> in_ptr_idxs_insert = nullptr );
  /// @copydoc InsertChar(pin<td_DefChar>,pin<int2>)
  int2 InsertChar( _in<int> in_char, pin<int2> in_ptr_idxs_insert = nullptr )
  {
    int c[] = { in_char, 0 };
    return InsertChar( (td_DefChar const*)c, in_ptr_idxs_insert );
  }
  int2 InsertString( _in<td_DefString> in_str, pin<int2> in_ptr_idxs_insert = nullptr );

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  sdptr<Component>
    CreateClone
      ( _in<sdptr<Component>> in_sp_component_for_parent       = nullptr
      , _in<float2          > in_offset_position_from_original = float2{0,0}
      ) const override;
protected:
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  eEventReturnID
    On_Size( _in<sdptr<Component>> in_sp_component );

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  eEventReturnID
    On_MouseDown
      ( _in<sdptr<Component>> in_sp_component
      , _in<float           > in_mouse_x
      , _in<float           > in_mouse_y
      , _in<eMouseButton    > in_type_mouse_btn
      ) override;

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  eEventReturnID
    On_MouseUp
      ( _in<sdptr<Component>> in_sp_component
      , _in<float           > in_mouse_x
      , _in<float           > in_mouse_y
      , _in<eMouseButton    > in_type_mouse_btn
      ) override;

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  eEventReturnID
    On_MouseMove
      ( _in<sdptr<Component>> in_sp_component
      , _in<float           > in_mouse_x
      , _in<float           > in_mouse_y
      ) override;

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  eEventReturnID
    On_KeyDown
      ( _in<sdptr<Component>> in_sp_component
      , _in<int             > in_virtual_key_code
      ) override;

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  eEventReturnID
    On_Char
      ( _in<sdptr<Component>> in_sp_component
      , _in<TCHAR           > in_char_code
      , _in<int             > in_key_data
      ) override;

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  eEventReturnID
    On_Timer( _in<int> in_timer_ID ) override;

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  eEventReturnID
    On_MouseWheel
      ( _in<sdptr<Component>> in_sp_component
      , _in<WORD            > in_fw_keys
      , _in<short           > in_z_delta  
      ) override;

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  eEventReturnID
    On_UserProc
      ( _in<sdptr<Component>> in_sp_component
      , _in<long            > in_message
      , _in<WPARAM          > in_wparam
      , _in<LPARAM          > in_lparam
      ) override;
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  void On_DrawClient( _in<float4> in_rect ) override;

private:
  ArraySpString m_list_string;
  SpFontMng     m_sp_font_mng;
  U32x2         m_size_line_max{ 0, 0 };

  struct CaretInfo
  {
    //int2 pos0{ 0, 0 }
    //   , pos1{ 0, 0 };
    int height{ 1 }
      , width { 1 };
    int2 idx0{ 0, 0 }
       , idx1{ 0, 0 };

    int2 GetLowIndex() const
    {
      if( *(S64*)&idx0 < *(S64*)&idx1 )
        return idx0;
      return idx1;
    }
    int2 GetHighIndex() const
    {
      if( *(S64*)&idx0 < *(S64*)&idx1 )
        return idx1;
      return idx0;
    }
  };
  CPL_SINGLETON( CaretInfo, sm_caret )

  using td_FDM_CD = DX::FontDrawManager::CaretData;
  U16
    zzf_getCaretData_by_Position_
      ( rout<td_FDM_CD> out_caret_data
      , _in <float    > in_mouse_x
      , _in <float    > in_mouse_y
      , _in <float    > in_width_return = 100000.0f
      );
  U16
    zzf_getCaretData_by_Index_
      ( rout<td_FDM_CD> out_caret_data
      , _in <int2     > in_idxs
      );
  void
    zzf_DeleteSelectStrings
      ( rio<int2> io_idx_begin
      , rio<int2> io_idx_end
      );
  int2  zzf_reviseIndex_( pin<int2> in_ptr_idxs );
  int2  zzf_insertEnter_( pin<int2> in_ptr_idxs_insert );
  void  zzf_getDrawTextColor_
          ( rout<DX::RectColor4P> out_color_text
          , rout<DX::RectColor4P> out_rev_color_text
          );
  U32x2 zzf_computeWorkingAreaSize_() const;
  bool  zzf_keyDown_Delete_();
  bool  zzf_keyDown_BackSpace_();
  bool  zzf_keyDown_Left_();
  bool  zzf_keyDown_Right_();
  bool  zzf_keyDown_Home_();
  bool  zzf_keyDown_End_();
  bool  zzf_keyDown_Up_();
  bool  zzf_keyDown_Down_();
  void  zzf_updateCaret_();
};


// _____________________________________________________________________________
/// @brief エディタをクライアントに持つウィンドウオブジェクト
// *****************************************************************************
class EditorWindow
  : public Window
{
  using td_base = Window;
  using td_self = EditorWindow;
  friend Factory<td_self>;
  friend CallPrivateConstructor<td_self>;

  using SpFontMng = sdptr<DX::FontDrawManager>;
public:
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  sdptr<Component>
    CreateClone
      ( _in<sdptr<Component>> in_sp_component_for_parent       = nullptr
      , _in<float2          > in_offset_position_from_original = float2{0,0}
      ) const override;

protected:
  EditorWindow
  ( _in<sdptr<Component>> in_sp_component_for_parent
  , _in<float2          > in_position_for_component
  , _in<float2          > in_size_for_component
  , _in<SpFontMng       > in_sp_font_mng_default = nullptr
  );
  EditorWindow( cref<EditorWindow> in_edit_win );
  
  eEventReturnID
    On_Size( _in<sdptr<Component>> in_sp_component );
private:
  sdptr<Editor> m_sp_editor;
};



} // namespace GUC
} // namespace CPL
