#ifndef _LED_ANIMATION_H
#define _LED_ANIMATION_H

#include "common/LEDStrip.h"
#include "led_strip.h"
#include "my_board.h"
#include <functional>
#include "common/HSVTable.h"

#define HUE_MAX 767

enum EXIT_TYPE { EXIT_NORMAL, EXIT_FROM_NOTIFY, EXIT_FINISHED, EXIT_TIMEOUT };


#define HUE_CALC_METHOD 0
// TODO Fix hue range... 0-359 or 0-360;
#if HUE_CALC_METHOD == 0
  #define HUEtoRGB(x) trueHSV(x)
#elif HUE_CALC_METHOD == 1
  #define HUEtoRGB(x) sineHSV(x)
#elif HUE_CALC_METHOD == 2
  #define HUEtoRGB(x) pwrHSV(x)
#endif

#define RGBtoHUE(x) RGBToHSV(x)

#define INFINITE_LOOP 0


enum DIR_TYPE { DT_REV, DT_FWD, DT_BOTH };

typedef struct {
  int RampUpTime;
  int msRampDownTime;
  int msHoldTime;
  int msFreq;
  float minDuty;
  float maxDuty;
  int interval;
  uint8_t pwr;
}params_whiteFill;

typedef struct {
  int hue;
  int cooling;
  int sparking;
  int interval;
  uint8_t pwr;
}params_fire_hue;

typedef struct {
  rgbpixel_t col1;
  rgbpixel_t col2;
  uint8_t range; /* hue range 0-127*/
  int density; 
  uint8_t step; /* range step inteval*/
  int interval;
  uint8_t pwr;
}params_rain;

#define ANIMTESTMODE_TIMEOUT (20 * 1000) // 20 secs

typedef struct {
  int EventTestCountdown = 0;
  int EventsIndex; // upto 8 events based on anim-events.json
  int EventsCount; // upto 8 events based on anim-events.json
  int PopupAnimIndex;
  bool busy;
  bool repeat;
  int countStatus;
}ANIM_STATUS;

typedef struct {
  bool busy;
  int dslrCountStatus;
}WHITE_FILL_STATUS;

extern ANIM_STATUS animStatus;
extern WHITE_FILL_STATUS whiteStatus;

float calculateSteps(int msFreq, float LEDCount, int msFillTime);
void GetOptimizedStepInterval(float &steps, int &interval, int LEDCount, int msFillTime, int startInterval, float tolerance);

float GetNextPalletHue(void);
void Init_Hue_Range_Pallet(float hue1, float hue2, int colSteps);

float GetHueRange(float hue1, float hue2);
float GetHueRangeWeb(float hue1, float hue2);

int CalcEventInterval(float speed, int min, int max);

/********************************  ANIMATION LOOP HELPER  *********************************
 * All Animations should use this lopp helper.
 * Logic for monitoring exit notifications
 * Timeout in mSec can be set to exit
**************************************************************************************/
EXIT_TYPE Animation_Loop(ANIM_STATUS &stateMon, int msFreq, TickType_t duration, std::function<int()> callback=NULL);

// min:0-100, max:0-100
//int Const_White_Fill(WHITE_FILL_STATUS &status, int msRampUpTime, int msHoldTime, int msRampDownTime, int msFreq, float minDuty, float maxDuty);
int Const_White_Fill(WHITE_FILL_STATUS &status,  FRONT_LIGHT light , float delayFactor, int countDown, int msFreq);
//int Const_White_Fill_HelioType(ANIM_STATUS &stateMon, float startPoint,  int msRampUpTime,  int msRampDownTime, int msHoldTime, int msFreq, float minDuty, float maxDuty);

EXIT_TYPE Animation_White_Fill_Mirrored(LEDSTRIP& strip, ANIMATION_EVENT& event);

EXIT_TYPE Animation_Linear_Brighten(LEDSTRIP& strip, ANIMATION_EVENT& event);
EXIT_TYPE Animation_Tick_Fill(LEDSTRIP& strip, ANIMATION_EVENT& event);


/********************************  COLORED  SNAKES  *********************************
 * cycles=0=infinite
 * (check1) "mix"=false, all appearing sectors will be the same color until the next iteration
 *          "mix"=true, each meteor color will be different
 * (check2) "roate", add rotation to animation
 * (hue range) hue range (0-360)
 * (param1) sectors
 * (param2) colorCount, number of color divisions
**************************************************************************************/
EXIT_TYPE Animation_Snakes(LEDSTRIP& strip, ANIMATION_EVENT& event, DIR_TYPE dir=DT_BOTH, int cycles=0);
void drawSnakeMix(LEDSTRIP& strip, int sectors, float hue1, float hue2, int colorCount);


/********************************  COLORED  COMETS *********************************
 *(check1) "mix"=false, all appearing comets will be the same color until the next iteration
 * (check2) "mix"=true, each comets color will be different
 * (param1) hue range (0-360)
 * (param2) colorCount, number of color divisions
**************************************************************************************/
EXIT_TYPE Animation_Comets(LEDSTRIP& strip, ANIMATION_EVENT& event, DIR_TYPE dir=DT_BOTH, int cycles=0);

void fadeToBlackBy(rgbpixel_t& pixel, uint8_t fadeAmount);
inline uint8_t nscale8(uint8_t i, uint8_t scale);

/********************************  COLORED  SECTORS  *********************************
 * (check1) "mix"=false, all appearing sectors will be the same color until the next iteration
 * (check2) "mix"=true, each meteor color will be different
 * (param1) hue range (0-360)
 * (param2) colorCount, number of color divisions
**************************************************************************************/
EXIT_TYPE Animation_Sectors(LEDSTRIP& strip, ANIMATION_EVENT& event, DIR_TYPE dir=DT_BOTH, int cycles=0);


/********************************  COLORED  DASHES  *********************************
 * (check1) "mix"=false, all appearing dashes will be the same color until the next iteration
 * (check2) "mix"=true, each dash color will be different
 * (param1) hue range (0-360)
 * (param2) colorCount, number of color divisions
**************************************************************************************/
EXIT_TYPE Animation_Dashes(LEDSTRIP& strip, ANIMATION_EVENT& event, DIR_TYPE dirType=DT_BOTH, int cycles=0);


/********************************  HUE SPECTRUM  *********************************
 * (check1) "mix"=false, all appearing dashes will be the same color until the next iteration
 * (check2) "mix"=true, each dash color will be different
 * (param1) hue range (0-360)
 * (param2) colorCount, number of color divisions
**************************************************************************************/
EXIT_TYPE Animation_Hue_Spectrum(LEDSTRIP& strip, ANIMATION_EVENT& event, TickType_t duration);
EXIT_TYPE Animation_Hue_Spectrum_Mirrored(LEDSTRIP& strip, ANIMATION_EVENT& event, TickType_t duration);
void Fill_Hue_Spectrum(LEDSTRIP& strip, float hue1, float hue2);
void Fill_Hue_Spectrum_Mirrored(LEDSTRIP& strip, float hue1, float hue2);


/************************  RAINBOW  *********************/
EXIT_TYPE Animation_Rainbow(LEDSTRIP& strip, ANIMATION_EVENT& event, TickType_t duration);

/************************  PULSE COLOR  *********************/
EXIT_TYPE Animation_Pulse_Color_Cycling(LEDSTRIP& strip, ANIMATION_EVENT& event);


/****************  FIRE  ****************/
enum FIRE_COLOR { RED_FIRE, GREEN_FIRE, BLUE_FIRE};
//void Animation_Fire(LEDSTRIP& strip, ANIMATION_EVENT& event, FIRE_COLOR fire, TickType_t duration);
EXIT_TYPE Animation_Fire(LEDSTRIP& strip, ANIMATION_EVENT& event);
void LEDStrip_FireInit(LEDSTRIP& strip);
void Fire_Update( LEDSTRIP& strip, FIRE_COLOR fire, int Cooling, int Sparking);
rgbpixel_t GetPixelHeatColor ( FIRE_COLOR fire, uint8_t temperature);




/************************    *********************/
void Animation_Splash(LEDSTRIP& strip);
void Animation_SparkleColor(LEDSTRIP& strip, int msFreq);
void Animation_SparkleHue(LEDSTRIP& strip, ANIMATION_EVENT& event);

EXIT_TYPE Animation_Serial_Test2(LEDSTRIP& strip, int msFreq, const char* s1, const char* s2);
// msTransTime(Duration), msFreq(update interval)
void Animation_TransTo_Color(LEDSTRIP& strip, ANIM_STATUS &stateMon, int msTransTime, int msFreq, rgbpixel_t col);


void drawSectorsHueSingle(LEDSTRIP& strip, rgbpixel_t col, float hue1, float hue2, int sectors) ;
void drawSectorsHueMix(LEDSTRIP& strip, float hue1, float hue2, int sectors, int colorCount);



/************************  TEST ANIMATIONS  *********************/
EXIT_TYPE Animation_SetPixel(LEDSTRIP& strip, ANIMATION_EVENT& event);
EXIT_TYPE Animation_Clear(LEDSTRIP& strip, ANIMATION_EVENT& event);


rgbpixel_t GetColorFromHue(int hue);


#endif