// CC0

#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui_internal.h>

#define isdigit(c) (c >= '0' && c <= '9')

namespace ImGui
{
  float strToFloat (const char *s) // atof from minilibc
  {
    float a = 0.0;
    bool neg = false;
    int e = 0;
    int c;
    if (*s == '-')
    {
      neg = true;
      ++s;
    }
    while ((c = *s++) != '\0' && c != ' ' && isdigit(c)) {
      a = a*10.0f + (c - '0');
    }
    if (c == '.') {
      while ((c = *s++) != '\0' && c != ' ' && isdigit(c)) {
        a = a*10.0f + (c - '0');
        e = e-1;
      }
    }
    while (e < 0) {
      a *= 0.1f;
      e++;
    }
    return neg ? -a : a;
  }

  int tokenlLength (const char* str)
  {
    const char* c = str;
    for (; c - str < 16; ++c)
    {
      if (*c == ' ' || *c == '\0' )
      {
        return int(c - str);
      }
    }

    return 16;
  }

  void DrawCmdList (ImDrawList* theDrawList, const ImVec2 thePivot, const char* theCmdList, const ImU32 theColor)
  {
    enum class State
    {
      None,
      RectFilled, // r left top right bottom
      Line, // l thickness p0.x p0.y p1.x p1.y
    };

    State state = State::None;

    float cmdArgs[8] = {};
    int cmdArgNum = 0;

    const char* c = theCmdList;
    while (*c)
    {
      switch (*c)
      {
        case ';': // execute command
        {
          switch (state)
          {
            case State::RectFilled:
            {
              theDrawList->AddRectFilled (thePivot + ImVec2 (cmdArgs[0], cmdArgs[1]),
                                          thePivot + ImVec2 (cmdArgs[2], cmdArgs[3]), theColor);
              break;
            }
            case State::Line:
            {
               theDrawList->AddLine (thePivot + ImVec2 (cmdArgs[1], cmdArgs[2]),
                                     thePivot + ImVec2 (cmdArgs[3], cmdArgs[4]), theColor, cmdArgs[0]);
              break;
            }
            default:
              break;
          }

          state = State::None;
          break;
        }
        case 'r':
        {
          state = State::RectFilled;
          cmdArgNum = 0;
          break;
        }
        case 'l':
        {
          state = State::Line;
          cmdArgNum = 0;
          break;
        }
        default:
        {
          cmdArgs[cmdArgNum++ % 8] = strToFloat (c);
          break;
        }
      }

      c += tokenlLength (c) + 1; // next cmd
    }
  }

  // Demo widget using DrawCmdList
  bool CircleVectorButton (const char* theID, const float theRadius, const char* theCmdList)
  {
    ImGuiWindow* window = ImGui::GetCurrentWindow();
    if (window->SkipItems)
        return false;

    const ImGuiID id = window->GetID (theID);

    const ImVec2 size (theRadius * 2, theRadius * 2);
    const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
    const ImRect image_bb(window->DC.CursorPos, window->DC.CursorPos + size);
    ImGui::ItemSize(bb);
    if (!ImGui::ItemAdd(bb, id))
        return false;

    bool hovered, held;
    bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held);

    // Render
    const ImU32 col = ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);

    window->DrawList->AddCircleFilled (bb.Min + ImVec2 (theRadius, theRadius), theRadius, col, 24);

    DrawCmdList (window->DrawList, bb.GetCenter(), theCmdList, ImGui::GetColorU32 (ImGuiCol_Text));

    return pressed;
  }
}