#ifndef LED_DISPLAY_CONTROLLER
#define LED_DISPLAY_CONTROLLER

#define LDR_PIN 36

#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
#include <EepromManager.h>
#include "esp_task_wdt.h"
#include <NeoPixelBrightnessBusGfx.h>
#include <NeoPixelBrightnessBus.h>

// function for updater task on core 0
void updateDisplayGlobal(void* object);

class LedDisplayController
{
public:
    template<typename T_COLOR_FEATURE, typename T_METHOD>
    explicit LedDisplayController(NeoPixelBrightnessBusGfx<T_COLOR_FEATURE, T_METHOD> *matrix )
    {
        this->eepromUnit = nullptr;
        this->loadTextSets();

        this->RFade = (StepsFade*log10(2))/log10(255);

        this->matrix = matrix;
        this->matrix->Begin();
        this->matrix->setTextWrap(false);
            
        text_curr_nr = 0;
        text_set_starttime = 0;
        text_pass = 0;
        textpixel = 0;
        disp_show = false;

        setsModiefiedLastTime_ms = 0;
        setModifyingActive = false; 

        this->brightness_init();
        this->disp_init();

        // create updater task
        xTaskCreatePinnedToCore(updateDisplayGlobal, "DisplayUpdateTask", 10000, this, 1, &displayUpdateTask, 0);
    } ; 
    ~LedDisplayController();

    //typedef uint16_t (*remapfn)(uint16_t, uint16_t); 

    enum text_align_t
    {
        AlignLeft,
        AlignCenter,
        AlignRight
    };

    enum DisplayTextSetParameter
    {
        TextParameter = 0,
        ActiveParameter,
        RuntimeParameter,
        ColorParameter,
        AlignmentParameter,
        ScrollParameter,
        ScrollDirectionParameter,
        ScrollSpeedParameter,
        ScrollCountParameter,
        IndexParameter,
        DisplayTextSetParameterCount    /*!< Just for helping purposes */
    };

    enum GetSetTextSetParameterExitCode
    {
        Success,
        InvalidParameterError,
        ParameterNotWritableError,
        ValueOutOfRangeError,
        IndexOutOfRangeError,
        ValueIsNullptrError,
        InternalError
    };

    static const uint16_t maximumTextSets = 6;
    static const uint16_t maximumTextLength = 256;

    void loop();

    // modifiers for the internal text sets
    bool registerEepromUnit(EepromManager* eepromManager);
    String getTextSetParameter(int index, DisplayTextSetParameter parameter);
    GetSetTextSetParameterExitCode setTextSetParameter(int index, DisplayTextSetParameter parameter, String value);

    // brightness control
    int getBrightness();
    bool setBrightness(int brightness);
    bool getAutomaticBrightnessAdjustment();
    void setAutomaticBrightnessAdjustment(bool automaticBrightnessAdjustment);

private:

    // modified status
    const unsigned long msToWaitBeforeModifyGetsInactive = 2000; //milliseconds
    unsigned long setsModiefiedLastTime_ms;
    bool setModifyingActive;    

    // matrix objects
    TaskHandle_t displayUpdateTask;
    NeoPixelBrightnessBusGfx<NeoGrbFeature, Neo800KbpsMethod> *matrix;
    
    // brigthness meassurement collection set
    static const uint8_t meas_slots = 5;
    uint8_t current_meas_slot;
    uint16_t brightness_levels[meas_slots];
    float brightness_adjust;
    long last_brightness_meas;

    // matrix variables
    uint16_t text_curr_nr;
    uint32_t text_set_starttime;
    bool text_no_activ_legal_sets; 

    int text_pos;
    unsigned int text_pass;
    unsigned int textpixel;
    bool disp_show;
    long last_display_show_ms;
    uint8_t default_display_show_wait_ms;
    uint8_t display_show_wait_ms;

    static const uint8_t StepsFade  = 50;
    float RFade;

    // matrix control
    //uint16_t remap(uint16_t x, uint16_t y);
    void disp_init();
    void brightness_init();
    void disp_start_set();
    void disp_scroll_text();
    void show_matrix(const char *text, int pos, const char *color);
    void measureBrightnessEnv( void );
    uint8_t adjustBrightnessToEnv( void );
    uint16_t colorFromHex(String hex);

    // storage structs
    typedef struct text_set_t
    {
        char text[maximumTextLength];
        bool active;
        uint16_t runtime;
        char color[7];
        text_align_t alignment;
        bool scroll;
        int scrollDirection;
        int scrollSpeed;                /*!< Between 0 and 10 */
        uint16_t scrollCount;
    } text_set_t;

    typedef struct sets_t
    {
        text_set_t sets[maximumTextSets];
        int disp_brightness;
        bool disp_automatic_brightness_adjustment;
        char valid[3];
    } sets_t;

    // storage variables
    const text_set_t defaultTextSet {"", false, 1, "ffffff", AlignCenter, false, 0, 0, 0};
    sets_t text_sets;
    //FIXME: Add a second set of data here - one is the active one that gets read and the other is the inaktive one that is written ...
    // after a write occurs and after a second on no more write action the sets are switched ... this is to avoid races ... 
    // In case there was an deletion of a set ... the index has to be take into account ... it shell never point to an illegal aarea afterwards or
    // or to another than before ... in case the delted set was the current active one ... 

    // storage control
    EepromUnit* eepromUnit;
    GetSetTextSetParameterExitCode getSetTextSetParameter(int index, DisplayTextSetParameter parameter, String *value, bool set = false);
    bool storeTextSets();
    bool loadTextSets();
    bool storeDataToEEPROM();
};



#endif // LED_DISPLAY_CONTROLLER