#pragma once
#include "AftrConfig.h"
#ifdef AFTR_CONFIG_USE_IMGUI

#include <functional>
#include "SelectionQueryResult.h"
#include "Mat4.h"

namespace Aftr
{

   class WorldContainer;

/// Written by Scott Nykl.
/// Let's a user manipulate the pose of any WO, view the coordinate frames of any two WOs in
/// in each other's frame, and easily adjust pose via keyboard or mouse input. See 
/// modules/TestIMGUI for examples.
class AftrImGui_WO_Editor
{
   struct BiModal_WO_Selection_State;

public:
   struct Mouse_MutatePose_State;
   
   AftrImGui_WO_Editor( const std::string& editor_window_name = "WO Editor" );
   void draw( SelectionQueryResult const& q, WorldContainer const& cont, std::function<Camera*()> cam_functor = nullptr ) const;

   void onResizeWindow( int newWidthPix, int newHeightPix ) { this->onLayoutChange = true; }

   void draw_global_pose( WO* wo ) const noexcept;
   void draw_alternative_pose_input( WO* wo ) const noexcept;
   void draw_local_pose( WO* wo ) const noexcept;
   void draw_relative_pose( WO const* wo, WorldContainer const& cont, Camera* cam = nullptr ) const noexcept;

   bool draw_Mouse_MutatePose_State( Mouse_MutatePose_State* state, std::string const& text = "Mutate Pose" ) const noexcept;

   void draw_wo_info( WO const* wo ) const noexcept;

   template<typename T>
   static std::string to_string_xyz_ypr_deg( Mat4T<T> const& pose, unsigned int const numDecimals = 3 );

   static std::string to_string_WOid_label_or_nullptr( WO const* wo );

   struct Select_WO_from_container
   {
      WO* selected_wo{ nullptr };
      bool isCam{ false };
   };
   /// Example usage to ensure this draws each frame:
   /// if( WO* sel = this->draw_Popup_Select_WO_from_container( cont ); sel != nullptr )
   ///    std::cout << "Selected WO: " << sel->getID() << "\n";
   /// If cam is non-null, that cam will also appear in the popup of selectable objects since
   /// the camera typically isn't in the default WorldContainer.
   /// If the camera *is* the WO* returned, the second return param will be true
   Select_WO_from_container draw_Popup_Select_WO_from_container( WorldContainer const& cont, Camera* cam = nullptr, std::string const& but_text = "Select WO" ) const;

   struct Mouse_MutatePose_State
   {
      enum class TRANSFORM_STATE { PENDING, CANCELLED, APPLIED };
      WO* w = nullptr;
      Mat4 orig_pose; //stores orientation and position of WO immediately before mouse mutations began
      Mat4 pending_xform; //stores the final xform applied to WO over course of mutation.
      std::string cmd;
      //start_pixel and delta_pixel are non-nullopt when an active mouse pose mutation is occurring
      std::optional< VectorI > start_pixel; //.x and .y store the pixel location reported by ImGui::GetMousePos()
      std::optional< VectorI > delta_pixel; //.x and .y store the pixel location reported by ImGui::GetMousePos()
      TRANSFORM_STATE xform_status = TRANSFORM_STATE::PENDING;
   };

private:

   /// Optionally, append the Camera* to the end of the list as a selection option.
   Select_WO_from_container getMostRecentlySelectedWO_either_LeftClicked_or_SelectedFromMenu(
      BiModal_WO_Selection_State& inout_selectionState,
      SelectionQueryResult const& q, 
      WorldContainer const& cont, 
      Camera* cam = nullptr,
      std::string const& but_text = "Select WO") const;

   SelectionQueryResult query; ///< Stores most recent successful query (non-nullptr WO and coordinate)

   const std::string editor_window_name;
   mutable bool onLayoutChange{ true };
   
   //This stores the ungly state needed to handle selecting a WO via a Left-CRTL click OR by selecting
   //a specific WO from a menu list of WOs. This stateful struct is only used by the
   //getMostRecentlySelectedWO_either_LeftClicked_or_SelectedFromMenu() method.
   struct BiModal_WO_Selection_State
   {
      Select_WO_from_container old_leftClicked_wo;                  //used by getMostRecentlySelectedWO_either_LeftClicked_or_SelectedFromMenu
      Select_WO_from_container old_popupSel_wo;                     //used by getMostRecentlySelectedWO_either_LeftClicked_or_SelectedFromMenu
      SelectionQueryResult::clock_type::time_point popupSel_time;
   };
   
   mutable BiModal_WO_Selection_State recent_selection_state_for_WO; //stores state that is mutated by used by getMostRecentlySelectedWO_either_LeftClicked_or_SelectedFromMenu
   mutable Mouse_MutatePose_State mutate_pose_state;

   mutable Select_WO_from_container rel_obj; //used by draw_relative_pose
   mutable bool expand_Global_Pose_TreeNode{ true };
   mutable bool expand_Alternative_Pose_Input_TreeNode{ true };
   mutable bool expand_Local_Pose_TreeNode{ true };
   mutable bool expand_Relative_Pose_TreeNode{ true };
   mutable bool expand_WO_info_TreeNode{ true };

   mutable std::string draw_alternative_pose_input__input_buffer = "Copy/Paste or Type your desired inputs here...\n"; //stores the string passed into fromString_opt(...)
   mutable std::string draw_alternative_pose_input__result_buffer; //stores the feedback on the parsing of the orientation.

};

} //namespace Aftr
#endif