text: #ifndef IMGUI_NODE_HELPER_H_
  #define IMGUI_NODE_HELPER_H_
  
  #include <string>
  #include <vector>
  #include <map>
  
  #include "../contrib/imgui/include/imgui.h" 
  #include "../contrib/imgui/include/imgui_impl_glfw.h"
  #include "../contrib/imgui/include/imgui_impl_opengl3.h"
  #include "../contrib/imgui-node-editor/Include/imgui_node_editor.h"
  
  namespace ed = ax::NodeEditor;
  
  /*
  Enum Types
  */
  enum class PinType
  {
      Flow,
      Bool,
      Int,
      Float,
      String,
      Object,
      Function,
      Delegate,
  };
  
  enum class PinKind
  {
      Output,
      Input
  };
  
  enum class NodeType
  {
      Blueprint,
      Simple,
      Tree,
      Comment
  };
  
  /*
  Structs
  */
  struct Node;
  struct Pin
  {
      ed::PinId   ID;
      ::Node*     Node;
      std::string Name;
      PinType     Type;
      PinKind     Kind;
  
      Pin(int id, const char* name, PinType type):
          ID(id), Node(nullptr), Name(name), Type(type), Kind(PinKind::Input)
      {
      }
  };
  
  struct Node
  {
      ed::NodeId ID;
      std::string Name;
      std::vector<Pin> Inputs;
      std::vector<Pin> Outputs;
      ImColor Color;
      NodeType Type;
      ImVec2 Size;
  
      std::string State;
      std::string SavedState;
  
      Node(int id, const char* name, ImColor color = ImColor(255, 255, 255)):
          ID(id), Name(name), Color(color), Type(NodeType::Blueprint), Size(0, 0)
      {
      }
  };
  
  struct Link
  {
      ed::LinkId ID;
  
      ed::PinId StartPinID;
      ed::PinId EndPinID;
  
      ImColor Color;
  
      Link(ed::LinkId id, ed::PinId startPinId, ed::PinId endPinId):
          ID(id), StartPinID(startPinId), EndPinID(endPinId), Color(255, 255, 255)
      {
      }
  };
  
  /*
  Helper variables
  */
  struct NodeIdLess
  {
      bool operator()(const ed::NodeId& lhs, const ed::NodeId& rhs) const
      {
          return lhs.AsPointer() < rhs.AsPointer();
      }
  };
  
  static const int            s_PinIconSize = 24;
  static std::vector<Node>    s_Nodes;
  static std::vector<Link>    s_Links;
  static const float          s_TouchTime = 1.0f;
  static std::map<ed::NodeId, float, NodeIdLess> s_NodeTouchTime;
  static int s_NextId = 1;
  
  /*
  Functions utility
  */
  static int GetNextId(){
      return s_NextId++;
  }
  
  static ed::LinkId GetNextLinkId()
  {
      return ed::LinkId(GetNextId());
  }
  
  static void TouchNode(ed::NodeId id)
  {
      s_NodeTouchTime[id] = s_TouchTime;
  }
  
  static float GetTouchProgress(ed::NodeId id)
  {
      auto it = s_NodeTouchTime.find(id);
      if (it != s_NodeTouchTime.end() && it->second > 0.0f)
          return (s_TouchTime - it->second) / s_TouchTime;
      else
          return 0.0f;
  }
  
  static void UpdateTouch()
  {
      const auto deltaTime = ImGui::GetIO().DeltaTime;
      for (auto& entry : s_NodeTouchTime)
      {
          if (entry.second > 0.0f)
              entry.second -= deltaTime;
      }
  }
  
  static Node* FindNode(ed::NodeId id)
  {
      for (auto& node : s_Nodes)
          if (node.ID == id)
              return &node;
  
      return nullptr;
  }
  
  static Link* FindLink(ed::LinkId id)
  {
      for (auto& link : s_Links)
          if (link.ID == id)
              return &link;
  
      return nullptr;
  }
  
  static Pin* FindPin(ed::PinId id)
  {
      if (!id)
          return nullptr;
  
      for (auto& node : s_Nodes)
      {
          for (auto& pin : node.Inputs)
              if (pin.ID == id)
                  return &pin;
  
          for (auto& pin : node.Outputs)
              if (pin.ID == id)
                  return &pin;
      }
  
      return nullptr;
  }
  
  static bool IsPinLinked(ed::PinId id)
  {
      if (!id)
          return false;
  
      for (auto& link : s_Links)
          if (link.StartPinID == id || link.EndPinID == id)
              return true;
  
      return false;
  }
  
  static bool CanCreateLink(Pin* a, Pin* b)
  {
      if (!a || !b || a == b || a->Kind == b->Kind || a->Type != b->Type || a->Node == b->Node)
          return false;
  
      return true;
  }
  
  /*
  Functions Node creation
  */
  static void BuildNode(Node* node){
      for (auto& input : node->Inputs)
      {
          input.Node = node;
          input.Kind = PinKind::Input;
      }
  
      for (auto& output : node->Outputs)
      {
          output.Node = node;
          output.Kind = PinKind::Output;
      }
  }
  
  void BuildNodes(){
      for (auto& node : s_Nodes)
          BuildNode(&node);
  }
  
  static Node* SpawnInputActionNode(){
      s_Nodes.emplace_back(GetNextId(), "InputAction Fire", ImColor(255, 128, 128));
      s_Nodes.back().Outputs.emplace_back(GetNextId(), "", PinType::Delegate);
      s_Nodes.back().Outputs.emplace_back(GetNextId(), "Pressed", PinType::Flow);
      s_Nodes.back().Outputs.emplace_back(GetNextId(), "Released", PinType::Flow);
  
      BuildNode(&s_Nodes.back());
  
      return &s_Nodes.back();
  }
  
  static void init_ImguiNodeHelper(){
      Node* node;
  
      node = SpawnInputActionNode();      ed::SetNodePosition(node->ID, ImVec2(-252, 220));
      node = SpawnInputActionNode();      ed::SetNodePosition(node->ID, ImVec2(-300, 351));
      node = SpawnInputActionNode();      ed::SetNodePosition(node->ID, ImVec2(-238, 504));
      node = SpawnInputActionNode();      ed::SetNodePosition(node->ID, ImVec2(71, 80));
      node = SpawnInputActionNode();      ed::SetNodePosition(node->ID, ImVec2(168, 316));
  
      ed::NavigateToContent();
  
      BuildNodes();
  }
  
  static void run_ImguiNodeHelper(){
      for (auto& node : s_Nodes){
          ed::BeginNode(node.ID);
          ImGui::PushID(node.ID.AsPointer());
  
      }
  }
  
  #endif