#pragma once

#include <Adafruit_NeoPixel.h>

#ifndef LEDRING_START_NUM
#define LEDRING_START_NUM 58 //LED Position
#endif

#ifndef LEDRING_START_DELAY_MS
#define LEDRING_START_DELAY_MS 100ul
#endif

#ifndef LEDRING_ANIMATION_DELAY_MS
#define LEDRING_ANIMATION_DELAY_MS 250ul
#endif

#ifndef LEDRING_SPEED_FACTOR
#define LEDRING_SPEED_FACTOR 0.9f
#endif


enum class ERingAnimation {
  CIRCULATE,
  HIT_HALF,
  HIT_FULL,
  MISS,
  GAME_OVER,
  RESET,
};

class LedRing {
  private:
    Adafruit_NeoPixel m_strip;
    unsigned long m_lastUpdateMs;
    ERingAnimation m_currentRingAnimation;
    const int m_ledCount;
    int m_currentLed;
    int m_stepCounter;
    unsigned long m_speedDelay;
    void (*m_pCallbackProc) (ERingAnimation, void*);
    void *m_pCallbackParam;

    void callAnimationCallback();
    void circulateRoutine(void);
    bool hitRoutine(bool);
    bool missRoutine(void);
    bool gameOverResetRoutine(bool);

  public:
    LedRing(const int, const int, const int, const int);
    void init(void);
    void reset(void);
    void update(void);
    bool isHalfHit() { return ((m_currentLed == (LEDRING_START_NUM - 1)) || (m_currentLed == (LEDRING_START_NUM + 1))); }
    bool isFullHit() { return (m_currentLed == LEDRING_START_NUM); }
    bool isBusy(void) { return (m_currentRingAnimation != ERingAnimation::CIRCULATE); }
    void setBrightness(int brightness) { m_strip.setBrightness(brightness); }
    void setAnimationCallback(void (*pCallback) (ERingAnimation, void*), void*);
    int getBrightness(void) { m_strip.getBrightness(); }
    void playAnimation(ERingAnimation);
};