#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <unistd.h>
#include <assert.h>
#include <memory>
#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>

#include "nanovg.h"
#define NANOVG_GLES3_IMPLEMENTATION
#include "nanovg_gl.h"
#include "nanovg_gl_utils.h"

#include "common/framebuffer.h"
#include "common/touch.h"


#define COLOR_WHITE nvgRGBA(255, 255, 255, 255)
#define MAX_TEXT_SIZE 2048

extern const uint8_t bin_opensans_regular[] asm("_binary_opensans_regular_ttf_start");
extern const uint8_t *bin_opensans_regular_end asm("_binary_opensans_regular_ttf_end");


int main(int argc, char** argv) {
  int err;

  // spinner
  int fb_w, fb_h;
  std::unique_ptr<FrameBuffer> fb = std::make_unique<FrameBuffer>("text", 0x00001000, false,
                                          &fb_w, &fb_h);
  assert(fb);

  NVGcontext *vg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
  assert(vg);

  int font = nvgCreateFontMem(vg, "regular", (unsigned char*)bin_opensans_regular, (bin_opensans_regular_end - bin_opensans_regular), 0);
  assert(font >= 0);

  // Awake
  fb->set_power(HWC_POWER_MODE_NORMAL);
  set_brightness(255);

  glClearColor(0.1, 0.1, 0.1, 1.0);
  glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  nvgBeginFrame(vg, fb_w, fb_h, 1.0f);

  // background
  nvgBeginPath(vg);
  NVGpaint bg = nvgLinearGradient(vg, fb_w, 0, fb_w, fb_h,
  nvgRGBA(0, 0, 0, 175), nvgRGBA(0, 0, 0, 255));
  nvgFillPaint(vg, bg);
  nvgRect(vg, 0, 0, fb_w, fb_h);
  nvgFill(vg);


  // Text
  nvgFillColor(vg, COLOR_WHITE);
  nvgFontSize(vg, 75.0f);

  if (argc >= 2) {
    float x = 150;
    float y = 150;

    // Copy text
    char * text = (char *)malloc(MAX_TEXT_SIZE);
    strncpy(text, argv[1], MAX_TEXT_SIZE);

    float lineh;
    nvgTextMetrics(vg, NULL, NULL, &lineh);

    // nvgTextBox strips leading whitespace. We have to reimplement
    char * next = strtok(text, "\n");
    while (next != NULL){
      nvgText(vg, x, y, next, NULL);
      y += lineh;
      next = strtok(NULL, "\n");
    }
  }

  // Button
  int b_x = 1500;
  int b_y = 800;
  int b_w = 300;
  int b_h = 150;

  nvgBeginPath(vg);
  nvgFillColor(vg, nvgRGBA(8, 8, 8, 255));
  nvgRoundedRect(vg, b_x, b_y, b_w, b_h, 20);
  nvgFill(vg);

  nvgFillColor(vg, nvgRGBA(255, 255, 255, 255));
  nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
  nvgText(vg, b_x+b_w/2, b_y+b_h/2, "Exit", NULL);

  nvgBeginPath(vg);
  nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 50));
  nvgStrokeWidth(vg, 5);
  nvgRoundedRect(vg, b_x, b_y, b_w, b_h, 20);
  nvgStroke(vg);

  // Draw to screen
  nvgEndFrame(vg);
  fb->swap();
  assert(glGetError() == GL_NO_ERROR);


  // Wait for button
  TouchState touch;
  touch_init(&touch);

  while (true){
    int touch_x = -1, touch_y = -1;
    int res = touch_poll(&touch, &touch_x, &touch_y, 0);
    if (res){

      if (touch_x > b_x && touch_x < b_x + b_w){
        if (touch_y > b_y && touch_y < b_y + b_h){
          return 1;
        }
      }
    }

    usleep(1000000 / 60);
  }

  return 0;
}
