#ifndef SCREENMANAGER_H
#define SCREENMANAGER_H

#include <Adafruit_SSD1306.h>
#include "SDCardManager.h"
#include "CFGFileParser.h"
#include "CFGDictionary.h"


class ScreenManager
{
  friend class SAB;
  public:
    enum Error {OK, MALLOC_FAILED, VIEW_NOT_FOUND, VIEW_FUNC_UNDEFINED, VIEW_FAILED_TO_EXECUTE, CURRENT_VIEW_UNDEFINED};
    //Data structure for the view handling
    typedef struct viewLink
    {
        boolean (*viewLogicFunction)(Adafruit_SSD1306&, void*);
        void *pData;
        const int UID;
        struct viewLink *next, *previous;
    } ViewLink, *ViewLinkedList;

    ScreenManager(Adafruit_SSD1306 &display, SDCardManager *sdCardManager = NULL);
  
    boolean addView(boolean (*viewLogicFunction)(Adafruit_SSD1306&, void*), void *pData, const unsigned char UID);
    boolean removeView(const unsigned char UID);
    boolean displayView(const uint8_t UID);
    boolean displayNextView();
    boolean displayPreviousView();
    void forceRefresh();
    boolean applyCfgFromSD();
    void invertDisplayColor(const boolean inverted);
    void orientDisplay(const Orientation orientation);
    void dimDisplay(const boolean dimmed);
    void clearDisplay(const boolean bufferOnly = false);
    void clearViews();
    void sleep();
    void wakeUp();
    void setEnabled(boolean value);
    // Default value is 0 : this disables auto off
    void setAutoOFFDelay(const uint64_t delay = 0);
    boolean isEnabled() const;
    boolean isSleeping() const;
    boolean init();
    void run();
    
    Error getError() const;
    const char* getErrorMessage() const;
    boolean isDisplayColorInverted() const;
    Orientation getDisplayOrientation() const;
    boolean isDisplayDimmed() const;
    int getCurrentViewUID() const;
    uint64_t getAutoOFFDelay() const;
    unsigned char getViewCount();

    
    void iterateThroughList();
    
  protected:
  private:
    void *createEmptyList();
    boolean addNewLinkAtTheEnd(ViewLinkedList *viewLinkedList, ViewLink viewLink);
    boolean removeLinkByUID(ViewLinkedList *viewLinkedList, const unsigned char UID);
    ViewLink* getLinkByUID(ViewLinkedList viewLinkedList, const unsigned char UID);
    boolean isListEmpty(ViewLinkedList viewLinkedList);
    static boolean displayError(Adafruit_SSD1306 &display, void *pData);
    void setDefault();
    uint8_t orientationTranslator(uint16_t degres);
    
    Adafruit_SSD1306 &_displayRef;
    ViewLinkedList _viewLinkedList;
    Error _error = OK;
    boolean _displayColorInverted = false;
    boolean _displayDimmed = false;
    boolean _enabled = true;
    boolean _sleeping = false;
    uint8_t _refreshRateHz = 1;
    uint16_t _refreshInterval = 1000;
    uint64_t _timeRef = 0, _autoOFFDelayRef = 0, _autoOFFDelay = 0;
    boolean _forceRefresh = false;
    ViewLink *_currentView = NO_CURRENT_VIEW, *_tail = nullptr;
    ViewLink _viewNotFound, _viewFuncUndefined, _currentViewUndefined, _viewFunctionFailedToExecute;
    SDCardManager *_sdCardManager;
    
    //This structure contains the error message as well as the UID from the view that caused the error if available.
    typedef struct {const __FlashStringHelper* errorMessage; int viewUID;} ErrorInfo;
};

#endif //SCREENMANAGER_H
