#include "printf/unparse.h"

#include "ta_parameter.hpp"
#include "graphics_primitive.hpp"
#include "texture.hpp"

struct vertex {
  vec2 p;
  vec2 t;
};

const vertex quad_vertices[] = {
  { { 0, 0 }, {0, 0} },
  { { 1, 0 }, {1, 0} },
  { { 1, 1 }, {1, 1} },
  { { 0, 1 }, {0, 1} },
};

static inline vec2 transform_glyph_texture(const vec2& t, int char_code)
{
  int row = char_code / glyph::row_stride;
  int col = char_code % glyph::row_stride;

  return {
    (float)(col * glyph::width  + t.x * glyph::width) / (float)(glyph::texture_width),
    (float)(row * glyph::height + t.y * glyph::height) / (float)(glyph::texture_height),
  };
}

static inline vec3 transform_glyph_position(const vec2& p, float x, float y, float z)
{
  return {
    p.x * glyph::width + x,
    p.y * glyph::height + y,
    z
  };
}

void transfer_global_polygon_glyph(ta_parameter_writer& writer)
{
  uint32_t texture_size = tsp_instruction_word::texture_u_size::from_int(128)
                        | tsp_instruction_word::texture_v_size::from_int(256)
                        | tsp_instruction_word::dst_alpha_instr::one;

  global_polygon_textured(writer,
                          para_control::list_type::punch_through,
                          texture::offset::tandy1k,
                          texture_size,
                          texture_control_word::pixel_format::_4bpp_palette);
}

void transfer_glyph(ta_parameter_writer& writer, int c, float x, float y, float z,
                    int base_color)
{
  vec3 ap = transform_glyph_position(quad_vertices[0].p, x, y, z);
  vec3 bp = transform_glyph_position(quad_vertices[1].p, x, y, z);
  vec3 cp = transform_glyph_position(quad_vertices[2].p, x, y, z);
  vec3 dp = transform_glyph_position(quad_vertices[3].p, x, y, z);

  vec2 at = transform_glyph_texture(quad_vertices[0].t, c);
  vec2 bt = transform_glyph_texture(quad_vertices[1].t, c);
  vec2 ct = transform_glyph_texture(quad_vertices[2].t, c);
  vec2 dt = transform_glyph_texture(quad_vertices[3].t, c);

  quad_type_3(writer,
              ap, at,
              bp, bt,
              cp, ct,
              dp, dt,
              base_color);
}

int transfer_string(ta_parameter_writer& writer, const char * s,
                    float x, float y, float z,
                    int base_color)
{
  const uint8_t * u8 = (const uint8_t *)s;
  int len = 0;
  while (*u8) {
    len += 1;
    transfer_glyph(writer, *u8++, x, y, z, base_color);
    x += glyph::hori_advance;
  }
  return len;
}

int transfer_integer(ta_parameter_writer& writer, int n,
                     float x, float y, float z,
                     int length, int fill,
                     int base_color)
{
  char buf[16];

  int len = unparse_base10(buf, n, length, fill);
  buf[len] = 0;

  transfer_string(writer, buf, x, y, z, base_color);

  return len;
}

int transfer_hex_integer(ta_parameter_writer& writer, int n,
                         float x, float y, float z,
                         int length, int fill,
                         int base_color)
{
  char buf[16];

  int len = unparse_base16(buf, n, length, fill);
  buf[len] = 0;

  transfer_string(writer, buf, x, y, z, base_color);

  return len;
}

void transfer_rectangle(ta_parameter_writer& writer,
                        float x, float y, float z,
                        float width, float height,
                        int base_color)
{
  quad_type_0(writer,
              {x + 0, y + 0, z},
              {x + width, y + 0, z},
              {x + width, y + height, z},
              {x + 0, y + height, z},
              base_color);
}

void transfer_vertical_border(ta_parameter_writer& writer, float x, float y, int length)
{
  quad_type_0(writer,
              {x + 0, y + 0, 1.0/7.0},
              {x + 1, y + 0, 1.0/7.0},
              {x + 1, y + length, 1.0/7.0},
              {x + 0, y + length, 1.0/7.0},
              0x2a3536);

  quad_type_0(writer,
              {x + 1, y + 0, 1.0/5.0},
              {x + 2, y + 0, 1.0/5.0},
              {x + 2, y + length, 1.0/5.0},
              {x + 1, y + length, 1.0/5.0},
              0x202829);

  quad_type_0(writer,
              {x + 2, y + 0, 1.0/10.0},
              {x + 3, y + 0, 1.0/10.0},
              {x + 3, y + length, 1.0/10.0},
              {x + 2, y + length, 1.0/10.0},
              0x101414);
}

void transfer_horizontal_border(ta_parameter_writer& writer, float x, float y, int length)
{
  quad_type_0(writer,
              {x + 0, y + 0, 1.0/7.0},
              {x + 0, y + 1, 1.0/7.0},
              {x + length, y + 1, 1.0/7.0},
              {x + length, y + 0, 1.0/7.0},
              0x2a3536);

  quad_type_0(writer,
              {x + 0, y + 1, 1.0/5.0},
              {x + 0, y + 2, 1.0/5.0},
              {x + length, y + 2, 1.0/5.0},
              {x + length, y + 1, 1.0/5.0},
              0x202829);

  quad_type_0(writer,
              {x + 0, y + 2, 1.0/10.0},
              {x + 0, y + 3, 1.0/10.0},
              {x + length, y + 3, 1.0/10.0},
              {x + length, y + 2, 1.0/10.0},
              0x101414);
}
