#include "local.h"


#define UI_NUM_VERTEXES (1024 * 1024)
#define UI_NUM_INDEXES  (1024 * 1024)
#define UI_NUM_GROUPS   1024

static int run_ui_recording = 0;
static alias_ui * run_ui_instance = NULL;
static alias_ui_OutputGroup run_ui_groups[UI_NUM_GROUPS];

static inline void _text_size(alias_ui *_ui, const char * buffer, float size, float _max_width, float * out_width, float * out_height) {
  (void)_ui;
  (void)_max_width;
  replacement_MeasureTextEx(buffer, size, 0, out_width, out_height);
}

static inline void _text_draw(alias_ui *_ui, const char * buffer, float x, float y, float _width, float size, alias_Color color) {
  (void)_ui;
  (void)_width;
  replacement_DrawText(buffer, x, y, size, color);
}

static inline void _start_ui(void) {
  static alias_ui_Input input;

  if(run_ui_instance == NULL) {
    // TODO proper init/shutdown
    alias_ui_initialize(NULL, &run_ui_instance);
  }

  if(!run_ui_recording) {
    input.screen_size.width = Engine_render_get_width();
    input.screen_size.height = Engine_render_get_height();
    input.text_size = _text_size;
    input.text_draw = _text_draw;

    alias_ui_begin_frame(run_ui_instance, alias_default_MemoryCB(), &input);
    run_ui_recording = 1;

    alias_ui_begin_stack(run_ui_instance);
  }
}

void Engine_ui_image(struct Image * img) {
  _start_ui();
  struct LoadedResource * resource = Engine__load_image(img);
  alias_ui_image(run_ui_instance, resource->image.width, resource->image.height, 0, 0, 1, 1, resource->id);
}

void Engine_ui_align_fractions(float x, float y) {
  _start_ui();
  alias_ui_align_fractions(run_ui_instance, x, y);
}

void Engine_ui_font_size(alias_R size) {
  _start_ui();
  alias_ui_font_size(run_ui_instance, size);
}

void Engine_ui_font_color(alias_Color color) {
  _start_ui();
  alias_ui_font_color(run_ui_instance, color);
}

void Engine_ui_text(const char * format, ...) {
  _start_ui();

  va_list ap;
  va_start(ap, format);
  alias_ui_textv(run_ui_instance, format, ap);
  va_end(ap);
}

void Engine_ui_vertical(void) {
  _start_ui();
  alias_ui_begin_vertical(run_ui_instance);
}

void Engine_ui_horizontal(void) {
  _start_ui();
  alias_ui_begin_horizontal(run_ui_instance);
}

void Engine_ui_stack(void) {
  _start_ui();
  alias_ui_begin_stack(run_ui_instance);
}

void Engine_ui_end(void) {
  _start_ui();
  alias_ui_end(run_ui_instance);
}

void Engine__update_ui(void) {
  Engine__update_state_hud();

  if(!run_ui_recording) {
    return;
  }

  alias_ui_end(run_ui_instance); // end stack

  uint32_t num_vertexes = 0, num_indexes = 0, num_groups = 0;
  alias_ui_stats(run_ui_instance, &num_vertexes, &num_indexes, &num_groups);

  uint32_t * indexes;
  struct BackendUIVertex * vertexes;

  BackendUIVertex_begin_draw(num_indexes, &indexes, num_vertexes, &vertexes);

  alias_ui_Output output = {
      .num_groups = 0
    , .max_groups = UI_NUM_GROUPS
    , .groups = run_ui_groups
    , .num_indexes = 0
    , .index_sub_buffer = (alias_memory_SubBuffer) {
        .pointer = indexes
      , .count = num_indexes
      , .stride = sizeof(*indexes)
      , .type_format = alias_memory_Format_Uint32
      , .type_length = 1
      }
    , .num_vertexes = 0
    , .xy_sub_buffer = (alias_memory_SubBuffer) {
        .pointer = (uint8_t *)vertexes + offsetof(struct BackendUIVertex, xy)
      , .count = num_vertexes
      , .stride = sizeof(*vertexes)
      , .type_format = alias_memory_Format_Float32
      , .type_length = 2
      }
    , .rgba_sub_buffer = (alias_memory_SubBuffer) {
        .pointer = (uint8_t *)vertexes + offsetof(struct BackendUIVertex, rgba)
      , .count = num_vertexes
      , .stride = sizeof(*vertexes)
      , .type_format = alias_memory_Format_Float32
      , .type_length = 4
      }
    , .st_sub_buffer = (alias_memory_SubBuffer) {
        .pointer = (uint8_t *)vertexes + offsetof(struct BackendUIVertex, st)
      , .count = num_vertexes
      , .stride = sizeof(*vertexes)
      , .type_format = alias_memory_Format_Float32
      , .type_length = 2
      }
    };
  
  alias_ui_end_frame(run_ui_instance, alias_default_MemoryCB(), &output);
  run_ui_recording = 0;

  for(uint32_t g = 0; g < output.num_groups; g++) {
    uint32_t length = run_ui_groups[g].length;
    if(length == 0) {
      continue;
    }

    struct LoadedResource * material = Engine__loaded_resource_by_id(run_ui_groups[g].texture_id);

    BackendUIVertex_draw(&material->image, run_ui_groups[g].index, run_ui_groups[g].length);
  }

  BackendUIVertex_end_draw();
}