/// a static array of red-green-blue-white values together with free functions to set them
#pragma once

#include "helpers/ColorRGBW.h"

#include <cstdint>

template <int TNumLeds>
class LedStripRGBW
{
public:
  static constexpr int NUM_LEDS = TNumLeds;

  static constexpr int normalizeIdx(int idx)
  {
    return (idx < 0) ? (idx + NUM_LEDS) : (idx >= NUM_LEDS ? idx - NUM_LEDS : idx);
  }

  void set(int idx, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
  {
    // green: 0
    // red: 8
    // blue: 16
    // white: 24
    idx = normalizeIdx(idx);
    data_[idx] = (g << 0) | (r << 8) | (b << 16) | (w << 24);
  }

  void getRGBW(int idx, uint8_t &r, uint8_t &g, uint8_t &b, uint8_t &w)
  {
    idx = normalizeIdx(idx);
    g = (data_[idx] >> 0) & 0xff;
    r = (data_[idx] >> 8) & 0xff;
    b = (data_[idx] >> 16) & 0xff;
    w = (data_[idx] >> 24) & 0xff;
  }

  const uint32_t *rawData() const { return data_; }
  constexpr static int numLeds() { return TNumLeds; }

private:
  uint32_t data_[TNumLeds];
};

template <typename TLedStrip>
constexpr int numLeds()
{
  return TLedStrip::NUM_LEDS;
}

template <int TNumLeds>
constexpr int numLeds(const LedStripRGBW<TNumLeds> &)
{
  return TNumLeds;
}

template <int TNumLeds>
void setLedRGB(LedStripRGBW<TNumLeds> &s, int beginIdx, int endIdx, uint8_t r, uint8_t g, uint8_t b)
{
  for (int i = beginIdx; i < endIdx; ++i)
    s.set(i, r, g, b, 0);
}

template <int TNumLeds>
void setLedRGB(LedStripRGBW<TNumLeds> &s, int idx, uint8_t r, uint8_t g, uint8_t b)
{
  s.set(idx, r, g, b, 0);
}

template <int TNumLeds>
void setLedRGBW(LedStripRGBW<TNumLeds> &s, int beginIdx, int endIdx, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{
  for (int i = beginIdx; i < endIdx; ++i)
    s.set(i, r, g, b, w);
}

template <int TNumLeds>
void setLedRGBW(LedStripRGBW<TNumLeds> &s, int idx, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{
  s.set(idx, r, g, b, w);
}

template <int TNumLeds>
void setLedRGBW(LedStripRGBW<TNumLeds> &s, int idx, const ColorRGBW &c)
{
  s.set(idx, c.r, c.g, c.b, c.w);
}

template <int TNumLeds>
void setLedRGBW(LedStripRGBW<TNumLeds> &s, int beginIdx, int endIdx, const ColorRGBW &c)
{
  for (int i = beginIdx; i < endIdx; ++i)
    s.set(i, c.r, c.g, c.b, c.w);
}

template <int TNumLeds>
void clear(LedStripRGBW<TNumLeds> &s)
{
  for (int i = 0; i < TNumLeds; ++i)
    s.set(i, 0, 0, 0, 0);
}

template <int TNumLeds>
ColorRGBW getLedRGBW(LedStripRGBW<TNumLeds> &s, int idx)
{
  ColorRGBW res;
  s.getRGBW(idx, res.r, res.g, res.b, res.w);
  return res;
}
