
#include "containers/LedStripRGBW.h"

#include "effects/AlexaSwipe.h"
#include "effects/ReverseSwipe.h"
#include "helpers/ColorConversions.h"

#include <iostream>
#include <vector>
#include <fstream>

template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &vec)
{
  os << "[";
  for (const auto &e : vec)
  {
    if (std::is_same<uint8_t, T>::value)
      os << int(e) << ",";
    else
      os << e << ",";
  }
  os << "]";
  return os;
}

template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<std::vector<T>> &vec)
{
  os << "[";
  for (const auto &e : vec)
    os << e << ",";
  os << "]";
  return os;
}

template <typename TEffect, int NLeds>
void effectToFile(const std::string &filename, TEffect &effect, LedStripRGBW<NLeds> &strip, int calls = 100)
{
  std::vector<std::vector<uint8_t>> vr(calls);
  std::vector<std::vector<uint8_t>> vg(calls);
  std::vector<std::vector<uint8_t>> vb(calls);

  std::vector<std::vector<float>> vh(calls);
  std::vector<std::vector<float>> vs(calls);
  std::vector<std::vector<float>> vv(calls);

  for (int time = 0; time < calls; ++time)
  {
    effect();
    vr[time].resize(NLeds);
    vg[time].resize(NLeds);
    vb[time].resize(NLeds);

    vh[time].resize(NLeds);
    vs[time].resize(NLeds);
    vv[time].resize(NLeds);

    for (int i = 0; i < NLeds; ++i)
    {
      uint8_t r, g, b, w;
      strip.getRGBW(i, r, g, b, w);
      vr[time][i] = r;
      vg[time][i] = g;
      vb[time][i] = b;

      auto hsv = rgb2hsv(ColorRGBW{r, g, b, w});
      vh[time][i] = hsv.h;
      vs[time][i] = hsv.s;
      vv[time][i] = hsv.v;
    }
  }

  std::ofstream fs(filename.c_str());
  fs << "r = " << vr << "\n";
  fs << "g = " << vg << "\n";
  fs << "b = " << vb << "\n";
  fs << "h = " << vh << "\n";
  fs << "s = " << vs << "\n";
  fs << "v = " << vv << "\n";
}

int main(int argc, char **argv)
{
  {
    auto cfg = EffectAlexaSwipeConfig{20.f, 20.f, 90.f, 5.f, 180, true, ColorRGBW{255, 0, 0, 0}, ColorRGBW{255, 0, 0, 0}};
    LedStripRGBW<51> strip;

    EffectAlexaSwipe<decltype(strip)> effect(cfg, strip);
    effectToFile("swipe.py", effect, strip, 200);
  }

  {
    auto cfg = EffectReverseSwipeConfig{360.f, 5.f, 180};
    LedStripRGBW<51> strip;
    for (int i = 0; i < strip.numLeds(); ++i)
      setLedRGBW(strip, i, ColorRGBW{255, 255, 255, 0});

    EffectReverseSwipe<decltype(strip)> effect(cfg, strip);
    effectToFile("reverse_swipe.py", effect, strip, 200);
  }

  /*
  effect.currentPosition_ = 150;

  const auto numLeds = strip.numLeds() / 2;

  std::vector<float> brightness(numLeds, 0);
  std::vector<float> interpolation(numLeds, 0);

  for (int i = 0; i < numLeds; ++i)
    effect.getParams(float(i), interpolation[i], brightness[i]);

  printVec(brightness);
  printVec(interpolation);

  effect();
  */
  return 0;
}