#include "switch.h"

#include <Arduino.h>

#include "roo_display/image/image.h"
#include "roo_display/internal/raw_streamable_overlay.h"
#include "roo_display/ui/tile.h"

#include "roo_windows/widgets/resources/circle.h"
#include "roo_windows/widgets/resources/circular_shadow.h"

using namespace roo_display;

namespace roo_windows {

namespace {

const ::roo_display::Pictogram& slider_18();
const ::roo_display::Pictogram& slider_24();
const ::roo_display::Pictogram& slider_36();
const ::roo_display::Pictogram& slider_48();

static constexpr int kSwitchAnimationMs = 120;
}  // namespace

bool Switch::onSingleTapUp(XDim x, YDim y) {
  toggle();
  anim_ = millis() & 0x7FFF;
  return Widget::onSingleTapUp(x, y);
}

int16_t Switch::time_animating_ms() const {
  return (millis() & 0x7FFF) - (anim_ & 0x7FFF);
}

void Switch::paintWidgetContents(const Canvas& canvas, Clipper& clipper) {
  if (isAnimating()) {
    int16_t ms = time_animating_ms();
    if (ms < 0 || ms > kSwitchAnimationMs) {
      // Done animating.
      anim_ = 0x8000;
    }
  }
  Widget::paintWidgetContents(canvas, clipper);
  if (isAnimating()) {
    setDirty();
  }
}

void Switch::paint(const Canvas& canvas) const {
  const Theme& th = theme();
  Color circleColor =
      isOn() ? th.color.highlighterColor(canvas.bgcolor()) : th.color.surface;
  Color sliderColor = isOn() ? th.color.highlighterColor(canvas.bgcolor())
                             : th.color.defaultColor(canvas.bgcolor());
  int16_t xoffset;
  if (isAnimating()) {
    int16_t ms = time_animating_ms();
    if (ms < 0 || ms > kSwitchAnimationMs) {
      xoffset = isOn() ? Scaled(19) : 0;
    } else {
      int16_t progress = Scaled(ms * 19) / kSwitchAnimationMs;
      xoffset = isOn() ? progress : Scaled(19) - progress;
    }
  } else {
    xoffset = isOn() ? Scaled(19) : 0;
  }
#if ROO_WINDOWS_ZOOM >= 200
  auto slider = slider_48();
  auto circle = circle_48();
  auto shadow = circular_shadow_48();
#elif ROO_WINDOWS_ZOOM >= 150
  auto slider = slider_36();
  auto circle = circle_36();
  auto shadow = circular_shadow_36();
#elif ROO_WINDOWS_ZOOM >= 100
  auto slider = slider_24();
  auto circle = circle_24();
  auto shadow = circular_shadow_24();
#else
  auto slider = slider_18();
  auto circle = circle_18();
  auto shadow = circular_shadow_18();
#endif
  slider.color_mode().setColor(sliderColor);
  circle.color_mode().setColor(circleColor);
  // leaving shadow as black.
  Box outer(0, 0, Scaled(42) - 1, Scaled(24) - 1);
  auto composite = MakeDrawableRawStreamable(
      Overlay(outer, slider, kCenter | kMiddle,
              Overlay(shadow.anchorExtents(), shadow, kCenter | kMiddle, circle,
                      kCenter | kMiddle),
              kLeft.shiftBy(xoffset) | kMiddle));

  roo_display::Tile toggle(&composite, outer, kMiddle);
  canvas.drawTiled(toggle, bounds(), kCenter | kMiddle, isInvalidated());
}

Dimensions Switch::getSuggestedMinimumDimensions() const {
  return Dimensions(Scaled(42), Scaled(24));
}

namespace {

// Image file slider_18 26x11, 4-bit Alpha,  RLE, 65 bytes.
static const uint8_t slider_18_data[] PROGMEM = {
    0x30, 0x18, 0x09, 0x63, 0x01, 0x50, 0x38, 0x0A, 0x05, 0x03, 0x30,
    0x38, 0x0A, 0x25, 0x81, 0x30, 0x18, 0x0A, 0x45, 0x01, 0x03, 0x80,
    0x93, 0x50, 0x68, 0x04, 0x50, 0x03, 0x80, 0x93, 0x50, 0x68, 0x04,
    0x50, 0x03, 0x80, 0x93, 0x50, 0x68, 0x04, 0x50, 0x30, 0x18, 0x09,
    0x35, 0x06, 0x80, 0x45, 0x81, 0x10, 0x38, 0x0A, 0x25, 0x03, 0x30,
    0x38, 0x0A, 0x05, 0x03, 0x50, 0x18, 0x09, 0x63, 0x01, 0x30,
};

const ::roo_display::Pictogram& slider_18() {
  static ::roo_display::Pictogram value(Box(0, 0, 25, 10), Box(0, 0, 25, 10),
                                        slider_18_data, Alpha4(color::Black));
  return value;
}

// Image file slider_24 34x14, 4-bit Alpha,  RLE, 81 bytes.
static const uint8_t slider_24_data[] PROGMEM = {
    0x40, 0x30, 0x48, 0x0A, 0x25, 0x04, 0x03, 0x60, 0x28, 0x0B, 0x05, 0x02,
    0x30, 0x28, 0x0B, 0x25, 0x02, 0x28, 0x0B, 0x45, 0x10, 0x38, 0x0B, 0x45,
    0x03, 0x04, 0x80, 0xA0, 0x50, 0x68, 0x07, 0x50, 0x48, 0x0A, 0x15, 0x06,
    0x80, 0xB5, 0x50, 0x68, 0x09, 0x05, 0x04, 0x80, 0xA0, 0x50, 0x68, 0x07,
    0x50, 0x40, 0x38, 0x0A, 0x05, 0x06, 0x80, 0x75, 0x03, 0x18, 0x0A, 0x05,
    0x06, 0x80, 0x75, 0x20, 0x28, 0x0B, 0x25, 0x02, 0x30, 0x28, 0x0B, 0x05,
    0x02, 0x60, 0x30, 0x48, 0x0A, 0x25, 0x04, 0x03, 0x40,
};

const ::roo_display::Pictogram& slider_24() {
  static ::roo_display::Pictogram value(Box(0, 0, 33, 13), Box(0, 0, 33, 13),
                                        slider_24_data, Alpha4(color::Black));
  return value;
}

// Image file slider_36 52x22, 4-bit Alpha,  RLE, 149 bytes.
static const uint8_t slider_36_data[] PROGMEM = {
    0x71, 0x01, 0x02, 0x80, 0xB4, 0x30, 0x20, 0x17, 0x70, 0x38, 0x0C, 0x25,
    0x03, 0x73, 0x02, 0x80, 0xC6, 0x50, 0x27, 0x02, 0x80, 0xD0, 0x50, 0x25,
    0x02, 0x80, 0xD2, 0x50, 0x24, 0x80, 0xD4, 0x53, 0x03, 0x80, 0xD4, 0x50,
    0x32, 0x80, 0xB3, 0x50, 0x68, 0x09, 0x65, 0x10, 0x18, 0x0B, 0x35, 0x06,
    0x80, 0x96, 0x50, 0x10, 0x28, 0x0B, 0x35, 0x00, 0x68, 0x09, 0x55, 0x02,
    0x03, 0x80, 0xB3, 0x50, 0x06, 0x80, 0x95, 0x50, 0x03, 0x80, 0xB3, 0x50,
    0x06, 0x80, 0x95, 0x50, 0x30, 0x28, 0x0B, 0x35, 0x00, 0x68, 0x09, 0x55,
    0x02, 0x01, 0x80, 0xB3, 0x50, 0x06, 0x80, 0x95, 0x50, 0x11, 0x80, 0xB3,
    0x50, 0x06, 0x80, 0x95, 0x52, 0x03, 0x80, 0xB2, 0x50, 0x06, 0x80, 0x94,
    0x50, 0x33, 0x80, 0xB2, 0x50, 0x68, 0x09, 0x55, 0x40, 0x28, 0x0B, 0x15,
    0x06, 0x80, 0x94, 0x50, 0x25, 0x02, 0x80, 0xD0, 0x50, 0x27, 0x02, 0x80,
    0xC6, 0x50, 0x27, 0x30, 0x38, 0x0C, 0x25, 0x03, 0x77, 0x01, 0x02, 0x80,
    0xB4, 0x30, 0x20, 0x17, 0x10,
};

const ::roo_display::Pictogram& slider_36() {
  static ::roo_display::Pictogram value(Box(0, 0, 51, 21), Box(0, 0, 51, 21),
                                        slider_36_data, Alpha4(color::Black));
  return value;
}

// Image file slider_48 68x28, 4-bit Alpha,  RLE, 196 bytes.
static const uint8_t slider_48_data[] PROGMEM = {
    0x72, 0x81, 0x13, 0x48, 0x0D, 0x05, 0x81, 0x43, 0x17, 0x72, 0x02, 0x04,
    0x80, 0xD6, 0x50, 0x40, 0x27, 0x50, 0x10, 0x48, 0x0E, 0x25, 0x04, 0x01,
    0x72, 0x01, 0x80, 0xE6, 0x50, 0x17, 0x01, 0x80, 0xF0, 0x50, 0x15, 0x01,
    0x80, 0xF2, 0x50, 0x14, 0x04, 0x80, 0xF2, 0x50, 0x43, 0x02, 0x80, 0xF4,
    0x50, 0x22, 0x04, 0x80, 0xF4, 0x58, 0x14, 0x01, 0x80, 0xC5, 0x50, 0x06,
    0x80, 0xA3, 0x50, 0x10, 0x38, 0x0C, 0x55, 0x00, 0x68, 0x0A, 0x35, 0x03,
    0x04, 0x80, 0xC5, 0x50, 0x06, 0x80, 0xA3, 0x50, 0x48, 0x0C, 0x65, 0x00,
    0x68, 0x0F, 0x65, 0x00, 0x68, 0x0F, 0x65, 0x00, 0x68, 0x0F, 0x65, 0x00,
    0x68, 0x0A, 0x45, 0x04, 0x80, 0xC5, 0x50, 0x06, 0x80, 0xA3, 0x50, 0x40,
    0x38, 0x0C, 0x55, 0x00, 0x68, 0x0A, 0x35, 0x03, 0x01, 0x80, 0xC5, 0x50,
    0x06, 0x80, 0xA3, 0x58, 0x11, 0x04, 0x80, 0xC4, 0x50, 0x06, 0x80, 0xA2,
    0x50, 0x42, 0x02, 0x80, 0xC4, 0x50, 0x06, 0x80, 0xA2, 0x50, 0x23, 0x04,
    0x80, 0xC3, 0x50, 0x06, 0x80, 0xA1, 0x50, 0x44, 0x01, 0x80, 0xC3, 0x50,
    0x06, 0x80, 0xA1, 0x50, 0x15, 0x01, 0x80, 0xF0, 0x50, 0x17, 0x01, 0x80,
    0xE6, 0x50, 0x17, 0x20, 0x10, 0x48, 0x0E, 0x25, 0x04, 0x01, 0x75, 0x02,
    0x04, 0x80, 0xD6, 0x50, 0x40, 0x27, 0x72, 0x81, 0x13, 0x48, 0x0D, 0x05,
    0x81, 0x43, 0x17, 0x20,
};

const ::roo_display::Pictogram& slider_48() {
  static ::roo_display::Pictogram value(Box(0, 0, 67, 27), Box(0, 0, 67, 27),
                                        slider_48_data, Alpha4(color::Black));
  return value;
}

}  // namespace

}  // namespace roo_windows