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

#include "WOImGuiAbstract.h"
#include "WOImGui_fwd_callbacks.h"
#include <functional>

//Written By Scott Nykl

// In general, a user does not need to use this WOImGui* or any other WOImGui* file. See the
// AftrImGui_* files for gui windows that perform useful functions. Instead of uses WOImGui
// files, the most common usage cases will be to write a function and subscribe that 
// function as a callback to be drawn as a GUI overlay.

namespace Aftr
{

class WOImGui : public WOImGuiAbstract
{
public:

   ///This immediate mode, declaritive GUI, which employs a library called ImGui,
   ///uses functional composition to draw gui widgets. To add any gui widgets you
   ///desire, simply write a method that draws an ImGui TreeNode using the following
   ///syntax:
   /*
      { //Pretend this is in the GLView::loadMap() or some other convenient place
      
         WO_MyAwesomeWO* myWO = WO_MyAwesomeWO::New( ... );
            //Assume that the WO_MyAwesomeWO above defines this method to draw the gui widgets:
            void WO_MyAwesomeWO::my_ImGui_draw_method( int myParam )
            {
               if( ImGui::TreeNode( "My Gui Options" ) )
               {
                  ImGui::Text( "This is my gui" );
                  //ImGui::Checkbox( "Add More Widgets here", &myVal);
                  ImGui::TreePop(); //ends your TreeNode (the "collapse" arrow hides all widgets 
                                    //between here and the above call to ImGui::TreeNode(...)
               }
               ImGui::Separator(); //draws bottom separator
            }
      
         //Now Create the gui and ensure it draws the above function/method via a lambda subscriber.
         //Here we are in the GLView::loadMap() method.
         int theParam = 42;
         WOImGui* gui = WOImGui::New( nullptr );
         gui->subscribe_drawImGuiWidget(
            [this, theParam, gui]()
            {
               //Here is a super neato paradigm that could be extended to support real-time introspection.
               //This is the glue code that is called from within the WOImGui instance...
               //Whenever a WO wants to draw some Gui stuff about that WO's internal state,
               //it simply asks the gui to call a function. That function is this lambda.
               //Since we don't want to put the entire ImGui draw call right here (even though
               //we could), let's just have the lambda call the corresponding WO's drawImGui_
               //method.
               this->myWO->my_ImGui_draw_method( theParam );
            } );
         this->worldLst->push_back( gui );
      }
   */


   /// The callback invoked when this WOImGui is called to draw itself
   using Callback_OnDrawImGui = WOImGui_Callback_OnDrawImGui;

   /// Callback invoked when the window is resized, the new width and height, in pixels, are passed in, respectively.
   using Callback_OnResizeWindow = WOImGui_Callback_OnResizeWindow;

   static WOImGui* New( WOGUI* parentWOGUI = nullptr, float width = 1.0f, float height = 1.0f );
   virtual ~WOImGui();
   virtual void drawImGui_for_this_frame() override;
   void subscribe_drawImGuiWidget( Callback_OnDrawImGui callback );

   //If the any entity using Dear ImGui would like to be notified when the SDL2 window is resized,
   //they may subscribe via a std::function meeting the signature for Callback_OnResizeWindow.
   //This function will be invoked by AftrBurner when a resize occurs.
   void subscribe_onResizeWindow_Notify( Callback_OnResizeWindow callback_resizeOccurred );

   virtual void onResizeWindow( int newWidthInPixels, int newHeightInPixels ) override;

   //These draw functions are only meant as a demo to show off the GUI widget's appearance,
   //see other examples for structuring state in a significantly better way than using
   //static variables inside functions -- this never scales to a multiplicity!
   static void draw_AftrImGui_Demo( WOImGui* gui );
   static void draw_AftrImGui_Demo_Icon_Window();
   //Method returns a tuple of ICON label to ICON unicode code point. For example, if IconsFontAwesome6.h
   //says #define ICON_FA_ADDRESS_BOOK "\xef\x8a\xb9"	// U+f2b9
   // The first value is the name ("ICON_FA_ADDRESS_BOOK") and 
   // the second value is the unicode string ("\xef\x8a\xb9").
   //See the definition for draw_AftrImGui_Demo_Icon_Window() as a way to iterate over all icons.
   static std::vector< std::tuple< const std::string, const std::string > > const& get_font_icons_name_to_unicode();

protected:
   virtual void onCreate( float width, float height ) override;
   WOImGui( WOGUI* parentWOGUI );

private:

   std::vector< Callback_OnDrawImGui >    subscribers_OnDrawImGui;
   std::vector< Callback_OnResizeWindow > subscribers_OnResizeWindow;
};

}

#endif
