#include "holly/background.hpp"
#include "holly/holly.hpp"
#include "holly/ta_bits.hpp"

#include "ta_parameter.hpp"

#include "scene/tracker/scene.hpp"

#include "notes.hpp"
#include "channel_status.hpp"
#include "texture.hpp"
#include "graphics_primitive.hpp"
#include "widget/button_label.hpp"
#include "widget/button_icon.hpp"
#include "widget/left_aligned.hpp"
#include "widget/top_aligned.hpp"
#include "playlist.hpp"
#include "interpreter.hpp"
#include "icons.hpp"
#include "metadata.hpp"
#include "tracklist.hpp"
#include "cover.hpp"

#include "scene/options/scene.hpp"

#include "cursor.hpp"

static void play_click()
{
  using namespace interpreter;
  printf("play\n");
  state.reverse = false;
  state.current_tick_rate = state.default_tick_rate;
  interpreter::unpause();
}

static void pause_click()
{
  printf("pause\n");
  interpreter::pause();
}

static void prev_click()
{
  printf("prev\n");
  playlist::prev();
}

static void next_click()
{
  printf("next\n");
  playlist::next();
}

static void rrr_click()
{
  using namespace interpreter;
  printf("rr\n");
  if (state.reverse)
    state.current_tick_rate = state.current_tick_rate * 22 / 23;
  state.reverse = true;
}

static void rr_click()
{
  using namespace interpreter;
  printf("rr\n");
  state.current_tick_rate = state.current_tick_rate * 23 / 22;
}

static void ff_click()
{
  using namespace interpreter;
  printf("ff\n");
  state.current_tick_rate = state.current_tick_rate * 22 / 23;
}

static void fff_click()
{
  using namespace interpreter;
  printf("fff\n");
  state.current_tick_rate = state.current_tick_rate / 2;
}

static void repeat_click()
{
  using namespace interpreter;
  printf("repeat\n");
  state.repeat = !state.repeat;
}

#define __length(c) ((sizeof (c)) / (sizeof (c[0])))

widget::button_icon play_button(75, 60, icons::play, play_click);
widget::button_icon pause_button(75, 33, icons::pause, pause_click);

widget::button_icon prev_button(60, 30, icons::prev, prev_click);
widget::button_icon next_button(60, 30, icons::next, next_click);
widget::button_icon repeat_button(37, 30, icons::repeat, repeat_click);

widget::button_icon rrr_button(39, 21, icons::rrr, rrr_click);
widget::button_icon rr_button(39, 21, icons::rr, rr_click);
widget::button_icon ff_button(39, 21, icons::ff, ff_click);
widget::button_icon fff_button(39, 21, icons::fff, fff_click);

widget::widget * play_pause_children[] = {
  &play_button,
  &pause_button,
};
int play_pause_length = __length(play_pause_children);

widget::widget * prev_next_children[] = {
  &prev_button,
  &next_button,
  &repeat_button,
};
int prev_next_length = __length(prev_next_children);

widget::widget * ff_rr_children[] = {
  &rrr_button,
  &rr_button,
  &ff_button,
  &fff_button,
};
int ff_rr_length = __length(ff_rr_children);

widget::top_aligned play_pause(0, 0, 1, play_pause_children, play_pause_length);

widget::left_aligned prev_next(0, 15, 1, prev_next_children, prev_next_length);

widget::left_aligned ff_rr(0, 67, 1, ff_rr_children, ff_rr_length);

widget::widget * prev_next_ff_rr_children[] = {
  &prev_next,
  &ff_rr,
};
int prev_next_ff_rr_length = __length(prev_next_ff_rr_children);

widget::container prev_next_ff_rr(0, 0, 159, 85, prev_next_ff_rr_children, prev_next_ff_rr_length);

widget::widget * top_children[] = {
  &play_pause,
  &prev_next_ff_rr,
};
int top_length = __length(top_children);

widget::left_aligned top(0, 0, 20, top_children, top_length);

namespace scene::tracker {

  const float cover_x = 480;
  const float cover_y = 5;
  static bool cover_zoom = false;
  static bool options = false;
  static bool last_a[4] = {};
  static bool last_start[4] = {};

  const struct scene::scene scene = {
    .ta_alloc = ta_alloc_ctrl::pt_opb::_32x4byte
              | ta_alloc_ctrl::tm_opb::no_list
              | ta_alloc_ctrl::t_opb::_32x4byte
              | ta_alloc_ctrl::om_opb::no_list
              | ta_alloc_ctrl::o_opb::no_list,
    .opb_size = {
      .opaque = 0,
      .opaque_modifier = 0,
      .translucent = 32 * 4,
      .translucent_modifier = 0,
      .punch_through = 32 * 4
    },
    .transfer = transfer,
    .interrupt = interpreter::interrupt,
    .init = init,
    .done = done,
  };

  void init()
  {
    background_parameter2(texture_memory_alloc.background[1].start,
                          0x000000);
    holly.VO_BORDER_COL = 0x000000;

    ::scene::options::init();

    float y = 8 + ((glyph::vert_advance + 5) * 2) + 8;
    top.freeze(5, y);

    playlist::next();

    tracklist::init(top.width + 5, 5);
  }

  void update_pick(cursor::cursor& c)
  {
    widget::widget * w = top.pick(c.x, c.y);
    if (w != nullptr) {
      w->click();
    } else {
      tracklist::update_pick(c);
    }
  }

  static bool a_click(int i)
  {
    bool last = last_a[i];
    cursor::cursor& c = cursor::state[i];
    last_a[i] = c.a;
    return c.a && c.a != last;
  }

  void update()
  {
    for (int i = 0; i < 4; i++) {
      cursor::cursor& c = cursor::state[i];
      if (c.active) {
        if (cover_zoom) {
          if (a_click(i))
            cover_zoom = false;
        } else {
          if (c.x >= cover_x && c.x <= (cover_x + 128) &&
              c.y >= cover_y && c.y <= (cover_y + 128)) {
            if (a_click(i))
              cover_zoom = true;
          } else {
            if (c.a)
              update_pick(c);
          }
        }
      }
    }
  }

  void update_start()
  {
    for (int i = 0; i < 4; i++) {
      cursor::cursor& c = cursor::state[i];
      if (c.active) {
        if (c.start && c.start != last_start[i])
          options = !options;
        last_start[i] = c.start;
      }
    }
  }

  void draw_button_labels(ta_parameter_writer& writer)
  {
    using namespace interpreter;

    transfer_global_polygon_glyph(writer);

    {
      float ratio = (float)state.default_tick_rate / (float)state.current_tick_rate;

      float x = 100;
      float y = 100;
      transfer_string(writer, "speed:    .  x",
                      x, y, 1.0 / 10.0,
                      0xa7a7a7);
      if (state.reverse)
        transfer_glyph(writer, '-',
                       x + glyph::hori_advance * 7, y, 1.0 / 10.0,
                       0xffffff);

      transfer_integer(writer, (int)ratio,
                       x + glyph::hori_advance * 8, y, 1.0 / 10.0,
                       2, ' ',
                       0xffffff);

      float ratio_fraction = (ratio - ((int)ratio)) * 100;

      transfer_integer(writer, (int)ratio_fraction,
                       x + glyph::hori_advance * 11, y, 1.0 / 10.0,
                       2, '0',
                       0xffffff);
    }

    {
      float x = 100;
      float y = 48;
      transfer_string(writer, "repeat:",
                      x, y, 1.0 / 10.0,
                      0xa7a7a7);

      x += glyph::hori_advance * (7 + 2);

      if (state.repeat) {
        transfer_string(writer, "on",
                        x, y, 1.0 / 10.0,
                        0xffffff);
      } else {
        transfer_string(writer, "off",
                        x, y, 1.0 / 10.0,
                        0xffffff);
      }
    }
  }

  void transfer(ta_multiwriter& multi)
  {
    update_start();

    metadata::draw(multi, 5, 8);
    top.draw(multi);
    draw_button_labels(multi.pt);
    tracklist::draw(multi, top.width + 5, 5);
    float y = top.y() + top.height + 5;
    channel_status::draw(multi, 5, y + 3);
    cover::draw(multi, cover_x, cover_y, cover_zoom);
    y += channel_status::height + 10;
    notes::draw(multi, 5, y);

    if (options) {
      ::scene::options::transfer(multi);
    } else {
      update();
    }
  }

  int done()
  {
    return -1;
  }
}
