#ifndef _OLEDUIPLUS_H_
#define _OLEDUIPLUS_H_
#include <Arduino.h>
#include <OLEDDisplayUi.h>
#include <interval.h>

// Kody stisknutych klaves
#define KEY_NONE 0
#define KEY_UP 1
#define KEY_DOWN 2
#define KEY_ENTER 4
#define KEY_EXIT 3

// Pocet radku menu na OLED displeji
#define MENU_ROWS_ON_OLED 3

// Maximalni pocet stavovych ikon na displeji
#define MAX_STATUS_ICONS 8

#define ELEMENTS_COUNT(a) (sizeof(a) / sizeof(a[0]))

typedef int (*kbdRead)(void);
typedef void (*de)(OLEDDisplay *display, int16_t x, int16_t y, void *ptr); // draw entry
typedef int (*ee)(void *ptr);
typedef void (*ce)(void);
typedef bool (*ve)(void *ptr);
typedef void (*oledon)(void); // informace o tom, ze je treba zapnout OLED displej
typedef void (*oledoff)(void); // informace o tom, ze zhasiname OLED displej

typedef struct {
    const char *entryText; // staticky text, vypisovany v polozce menu
    de drawEntry; // dynamicky text (napr. hodnota), vypisovany v polozce menu
    ee enterEntry; // funkce, volana pri stisku klavesy enter na polozce
    ce checkEntry; // funkce, volana pri kazdem zobrazeni pouze pro aktivni polozku v menu
    ve validEntry; // funkce, ktera vrati, jestli je polozka menu platna/viditelna/aktivni, nebo ne
    void *usrData; // ukazatel na uzivatelska data
} menuEntry_t;

typedef struct {
    const char *title;
    uint8_t entriesCount;
    const menuEntry_t *entries;
} menu_t;

void onOffOverlay(OLEDDisplay *display, OLEDDisplayUiState *state);

class OLEDUIPlus : public OLEDDisplayUi {
public:
    void goToMainFrame(void);
    void goToFrame(uint8_t frame);
    void goToPrevFrame(void);
    void begin(OLEDDisplay *display, kbdRead rKbd, uint32_t timeout, FrameCallback frames[], size_t framesCount, OverlayCallback overlays[], size_t overlaysCount);
    void startAnim(int open);
//    void onOffOverlay(OLEDDisplay *display, OLEDDisplayUiState *state);
    bool loop(void);
    void drawMenu(OLEDDisplay *display, const menu_t *menu, int *top, int *selected, int16_t x, int16_t y);
    int handleKbd(void);
    int extendOn(void);
    void setTimeout(uint32_t ms);
    bool blinkIsVisible(void);
    bool menuExpired(void);
    uint8_t getFrameIndex(FrameCallback cb);
    void setMainFrame(FrameCallback cb);
    bool isVisible(void);
    void setOffCb(oledoff oloff);
    void setOnCb(oledon olon);
    bool isMainFrame(uint8_t idx);

#if defined(USE_OTA)
    void OTAStart(void);
    void OTAProgress(unsigned int progress, unsigned int total);
    void OTAEnd(void);
#endif

private:
    Interval _timing; // casovac rychlosti periodicke obsluhy (rizeny dle casu, ktery vrati OLEDDisplayUi objekt)
    uint8_t _frameseq[8]; // historie prechodu jednotlivych obrazovek
    uint32_t _frameptr = 0; // index ve _frameseq
    OLEDDisplay* _oled = nullptr; // ukazatel na displej
    uint8_t _oledBrightness = 100; // jas OLED displeje
    uint32_t _oledtimeout = 0; // zhasinani OLED
    Interval _oledTiming; // casovac pro zhasinani OLED
    kbdRead _kbd; // klavesnice
    Interval _inMenu; // casovac pro opusteni menu pri necinnosti uzivatele (hlidani si osetruje kazdy menu modul sam!)
    Interval _blink; // casovac pro blikani
    bool _visible = false; // stav blikani (viditelny/neviditelny)
    FrameCallback* _frames;
    size_t _framesCount = 0;
    uint8_t _mainFrame = 0xff;
    bool _haveOnOffOverlay = false; // priznak, ze mame startovaci a ukoncovaci animaci
};

extern OLEDUIPlus ui;

#endif
