/*---------------------------------------------------------*\
| RGBControllerInterface.h                                  |
|                                                           |
|   OpenRGB's RGB controller hardware abstration layer,     |
|   provides a generic representation of an RGB device      |
|                                                           |
|   Adam Honse (CalcProgrammer1)                02 Jun 2019 |
|                                                           |
|   This file is part of the OpenRGB project                |
|   SPDX-License-Identifier: GPL-2.0-or-later               |
\*---------------------------------------------------------*/

#pragma once

#include <cstring>
#include <string>
#include <vector>
#include <nlohmann/json.hpp>

/*---------------------------------------------------------*\
| RGB Color Type and Conversion Macros                      |
\*---------------------------------------------------------*/
typedef unsigned int RGBColor;

#define RGBGetRValue(rgb)   (rgb & 0x000000FF)
#define RGBGetGValue(rgb)   ((rgb >> 8) & 0x000000FF)
#define RGBGetBValue(rgb)   ((rgb >> 16) & 0x000000FF)

#define ToRGBColor(r, g, b) ((RGBColor)((b << 16) | (g << 8) | (r)))

#define RGBToBGRColor(rgb) ((rgb & 0xFF) << 16 | (rgb & 0xFF00) | (rgb & 0xFF0000) >> 16)

/*---------------------------------------------------------*\
| RGBController Callback Types                              |
\*---------------------------------------------------------*/
typedef void (*RGBControllerCallback)(void *, unsigned int, void *);

/*---------------------------------------------------------*\
| Update Reason Codes                                       |
\*---------------------------------------------------------*/
enum
{
    RGBCONTROLLER_UPDATE_REASON_UPDATELEDS,         /* UpdateLEDs() called              */
    RGBCONTROLLER_UPDATE_REASON_UPDATEMODE,         /* UpdateMode() called              */
    RGBCONTROLLER_UPDATE_REASON_SAVEMODE,           /* SaveMode() called                */
    RGBCONTROLLER_UPDATE_REASON_CONFIGUREZONE,      /* ConfigureZone() called           */
    RGBCONTROLLER_UPDATE_REASON_CLEARSEGMENTS,      /* ClearSegments() called           */
    RGBCONTROLLER_UPDATE_REASON_ADDSEGMENT,         /* AddSegment() called              */
    RGBCONTROLLER_UPDATE_REASON_HIDDEN,             /* Hidden flag set                  */
    RGBCONTROLLER_UPDATE_REASON_UNHIDDEN,           /* Hidden flag cleared              */
    RGBCONTROLLER_UPDATE_REASON_SETDEVICESPECIFICCONFIGURATION,
                                                    /* SetDeviceSpecificConfiguration() called      */
    RGBCONTROLLER_UPDATE_REASON_SETDEVICESPECIFICZONECONFIGURATION,
                                                    /* SetDeviceSpecificZoneConfiguration() called  */
    RGBCONTROLLER_UPDATE_REASON_CONFIGUREDEVICE,    /* ConfigureDevice() called         */
    RGBCONTROLLER_UPDATE_REASON_DEVICE_CHANGED,     /* Device description replaced      */
};

/*---------------------------------------------------------*\
| Mode Flags                                                |
\*---------------------------------------------------------*/
enum
{
    MODE_FLAG_HAS_SPEED                 = (1 << 0), /* Mode has speed parameter         */
    MODE_FLAG_HAS_DIRECTION_LR          = (1 << 1), /* Mode has left/right parameter    */
    MODE_FLAG_HAS_DIRECTION_UD          = (1 << 2), /* Mode has up/down parameter       */
    MODE_FLAG_HAS_DIRECTION_HV          = (1 << 3), /* Mode has horiz/vert parameter    */
    MODE_FLAG_HAS_BRIGHTNESS            = (1 << 4), /* Mode has brightness parameter    */
    MODE_FLAG_HAS_PER_LED_COLOR         = (1 << 5), /* Mode has per-LED colors          */
    MODE_FLAG_HAS_MODE_SPECIFIC_COLOR   = (1 << 6), /* Mode has mode specific colors    */
    MODE_FLAG_HAS_RANDOM_COLOR          = (1 << 7), /* Mode has random color option     */
    MODE_FLAG_MANUAL_SAVE               = (1 << 8), /* Mode can manually be saved       */
    MODE_FLAG_AUTOMATIC_SAVE            = (1 << 9), /* Mode automatically saves         */
    MODE_FLAG_REQUIRES_ENTIRE_DEVICE    = (1 << 10),/* Mode always applies to entire    */
                                                    /* device, overrides per-zone modes */
    MODE_FLAG_HAS_DIRECTION_DIAG        = (1 << 11),/* Mode has diagonal direction      */
};

/*---------------------------------------------------------*\
| Mode Directions                                           |
\*---------------------------------------------------------*/
enum
{
    MODE_DIRECTION_LEFT         = 0,        /* Mode direction left              */
    MODE_DIRECTION_RIGHT        = 1,        /* Mode direction right             */
    MODE_DIRECTION_UP           = 2,        /* Mode direction up                */
    MODE_DIRECTION_DOWN         = 3,        /* Mode direction down              */
    MODE_DIRECTION_HORIZONTAL   = 4,        /* Mode direction horizontal        */
    MODE_DIRECTION_VERTICAL     = 5,        /* Mode direction vertical          */
    MODE_DIRECTION_UP_LEFT      = 6,        /* Mode direction up-left           */
    MODE_DIRECTION_UP_RIGHT     = 7,        /* Mode direction up-right          */
    MODE_DIRECTION_DOWN_LEFT    = 8,        /* Mode direction down-left         */
    MODE_DIRECTION_DOWN_RIGHT   = 9,        /* Mode direction down-right        */
};

/*---------------------------------------------------------*\
| Mode Color Types                                          |
\*---------------------------------------------------------*/
enum
{
    MODE_COLORS_NONE            = 0,        /* Mode has no colors               */
    MODE_COLORS_PER_LED         = 1,        /* Mode has per LED colors selected */
    MODE_COLORS_MODE_SPECIFIC   = 2,        /* Mode specific colors selected    */
    MODE_COLORS_RANDOM          = 3,        /* Mode has random colors selected  */
};

/*---------------------------------------------------------*\
| Zone Flags                                                |
\*---------------------------------------------------------*/
typedef unsigned int zone_flags;

#define ZONE_FLAGS_MANUALLY_CONFIGURABLE               (ZONE_FLAG_MANUALLY_CONFIGURABLE_SIZE_EFFECTS_ONLY   |       \
                                                        ZONE_FLAG_MANUALLY_CONFIGURABLE_SIZE                |       \
                                                        ZONE_FLAG_MANUALLY_CONFIGURABLE_NAME                |       \
                                                        ZONE_FLAG_MANUALLY_CONFIGURABLE_TYPE                |       \
                                                        ZONE_FLAG_MANUALLY_CONFIGURABLE_MATRIX_MAP          |       \
                                                        ZONE_FLAG_MANUALLY_CONFIGURABLE_SEGMENTS            |       \
                                                        ZONE_FLAG_MANUALLY_CONFIGURABLE_DEVICE_SPECIFIC)

#define ZONE_FLAGS_MANUALLY_CONFIGURED                 (ZONE_FLAG_MANUALLY_CONFIGURED_SIZE                  |       \
                                                        ZONE_FLAG_MANUALLY_CONFIGURED_NAME                  |       \
                                                        ZONE_FLAG_MANUALLY_CONFIGURED_TYPE                  |       \
                                                        ZONE_FLAG_MANUALLY_CONFIGURED_MATRIX_MAP            |       \
                                                        ZONE_FLAG_MANUALLY_CONFIGURED_SEGMENTS              |       \
                                                        ZONE_FLAG_MANUALLY_CONFIGURED_DEVICE_SPECIFIC)
enum
{
    ZONE_FLAG_MANUALLY_CONFIGURABLE_SIZE_EFFECTS_ONLY   = (1 << 0), /* Zone size is manually configurable, but only */
                                                                    /* for hardware effects, treated as single LED  */
                                                                    /* for per-LED modes                            */
    ZONE_FLAG_MANUALLY_CONFIGURABLE_SIZE                = (1 << 1), /* Zone size is manually configurable           */
    ZONE_FLAG_MANUALLY_CONFIGURABLE_NAME                = (1 << 2), /* Zone name is manually configurable           */
    ZONE_FLAG_MANUALLY_CONFIGURABLE_TYPE                = (1 << 3), /* Zone type is manually configurable           */
    ZONE_FLAG_MANUALLY_CONFIGURABLE_MATRIX_MAP          = (1 << 4), /* Zone matrix map is manually configurable     */
    ZONE_FLAG_MANUALLY_CONFIGURABLE_SEGMENTS            = (1 << 5), /* Zone segments are manually configurable      */
    ZONE_FLAG_MANUALLY_CONFIGURABLE_DEVICE_SPECIFIC     = (1 << 6), /* Zone dev-specific cfg manually configurable  */
    ZONE_FLAG_MANUALLY_CONFIGURED_SIZE                  = (1 << 12),/* Zone size has been manually configured       */
    ZONE_FLAG_MANUALLY_CONFIGURED_NAME                  = (1 << 13),/* Zone name has been manually configured       */
    ZONE_FLAG_MANUALLY_CONFIGURED_TYPE                  = (1 << 14),/* Zone type has been manually configured       */
    ZONE_FLAG_MANUALLY_CONFIGURED_MATRIX_MAP            = (1 << 15),/* Zone matrix map has been manually configured */
    ZONE_FLAG_MANUALLY_CONFIGURED_SEGMENTS              = (1 << 16),/* Zone segments have been manually configured  */
    ZONE_FLAG_MANUALLY_CONFIGURED_DEVICE_SPECIFIC       = (1 << 17),/* Zone device-specific cfg manually configured */
    ZONE_FLAG_ZONE_GEOMETRY_MAY_CHANGE                  = (1 << 24),/* Zone geometry may change                     */
};

/*---------------------------------------------------------*\
| Zone Types                                                |
\*---------------------------------------------------------*/
typedef unsigned int zone_type;

enum
{
    ZONE_TYPE_SINGLE,
    ZONE_TYPE_LINEAR,
    ZONE_TYPE_MATRIX,
    ZONE_TYPE_LINEAR_LOOP,
    ZONE_TYPE_MATRIX_LOOP_X,
    ZONE_TYPE_MATRIX_LOOP_Y,
    ZONE_TYPE_SEGMENTED
};

/*---------------------------------------------------------*\
| Segment Flags                                             |
\*---------------------------------------------------------*/
typedef unsigned int segment_flags;

enum
{
    SEGMENT_FLAG_GROUP_START    = (1 << 0), /* Start of segment group   */
    SEGMENT_FLAG_GROUP_MEMBER   = (1 << 1), /* Segment is in group      */
};

/*---------------------------------------------------------*\
| Device Types                                              |
|   The enum order should be maintained as is for the API   |
|   however DEVICE_TYPE_UNKNOWN needs to remain last. Any   |
|   new device types need to be inserted at the end of the  |
|   list but before unknown.                                |
\*---------------------------------------------------------*/
typedef int device_type;

enum
{
    DEVICE_TYPE_MOTHERBOARD,
    DEVICE_TYPE_DRAM,
    DEVICE_TYPE_GPU,
    DEVICE_TYPE_COOLER,
    DEVICE_TYPE_LEDSTRIP,
    DEVICE_TYPE_KEYBOARD,
    DEVICE_TYPE_MOUSE,
    DEVICE_TYPE_MOUSEMAT,
    DEVICE_TYPE_HEADSET,
    DEVICE_TYPE_HEADSET_STAND,
    DEVICE_TYPE_GAMEPAD,
    DEVICE_TYPE_LIGHT,
    DEVICE_TYPE_SPEAKER,
    DEVICE_TYPE_VIRTUAL,
    DEVICE_TYPE_STORAGE,
    DEVICE_TYPE_CASE,
    DEVICE_TYPE_MICROPHONE,
    DEVICE_TYPE_ACCESSORY,
    DEVICE_TYPE_KEYPAD,
    DEVICE_TYPE_LAPTOP,
    DEVICE_TYPE_MONITOR,
    DEVICE_TYPE_UNKNOWN,
};

/*---------------------------------------------------------*\
| Controller Flags                                          |
\*---------------------------------------------------------*/
typedef unsigned int controller_flags;

#define CONTROLLER_FLAGS_MANUALLY_CONFIGURABLE         (CONTROLLER_FLAG_MANUALLY_CONFIGURABLE_NAME              |   \
                                                        CONTROLLER_FLAG_MANUALLY_CONFIGURABLE_DEVICE_SPECIFIC)

#define CONTROLLER_FLAGS_MANUALLY_CONFIGURED           (CONTROLLER_FLAG_MANUALLY_CONFIGURED_NAME                |   \
                                                        CONTROLLER_FLAG_MANUALLY_CONFIGURED_DEVICE_SPECIFIC)

enum
{
    CONTROLLER_FLAG_LOCAL                                   = (1 << 0), /* Device is local to this instance                 */
    CONTROLLER_FLAG_REMOTE                                  = (1 << 1), /* Device is on a remote instance                   */
    CONTROLLER_FLAG_VIRTUAL                                 = (1 << 2), /* Device is a virtual device                       */
    CONTROLLER_FLAG_HIDDEN                                  = (1 << 3), /* Device is hidden                                 */

    CONTROLLER_FLAG_RESET_BEFORE_UPDATE                     = (1 << 8), /* Device resets update flag before                 */
                                                                        /* calling update function                          */

    CONTROLLER_FLAG_MANUALLY_CONFIGURABLE_NAME              = (1 << 16),/* Device name is manually configurable             */
    CONTROLLER_FLAG_MANUALLY_CONFIGURABLE_DEVICE_SPECIFIC   = (1 << 17),/* Device dev-specific cfg manually configurable    */

    CONTROLLER_FLAG_MANUALLY_CONFIGURED_NAME                = (1 << 24),/* Device name is manually configured               */
    CONTROLLER_FLAG_MANUALLY_CONFIGURED_DEVICE_SPECIFIC     = (1 << 25),/* Device dev-specific cfg is manually configured   */
};

/*---------------------------------------------------------*\
| Matrix Map                                                |
\*---------------------------------------------------------*/
class matrix_map_type
{
public:
    unsigned int                height;
    unsigned int                width;
    std::vector<unsigned int>   map;

    /*-----------------------------------------------------*\
    | Functionality defined inline so that it can be used   |
    | in consuming plugins                                  |
    \*-----------------------------------------------------*/
    matrix_map_type()
    {
        Reset();
    }

    matrix_map_type(unsigned int height, unsigned int width, unsigned int * map)
    {
        Set(height, width, map);
    }

    ~matrix_map_type()
    {

    }

    void Reset()
    {
        Set(0, 0, NULL);
    }

    void Set(unsigned int height, unsigned int width, unsigned int * map)
    {
        this->height        = height;
        this->width         = width;
        this->map.resize(height * width);

        if(map != NULL)
        {
            memcpy(this->map.data(), map, (height * width * sizeof(unsigned int)));
        }
        else
        {
            memset(this->map.data(), 0, (height * width * sizeof(unsigned int)));
        }
    }
};

/*---------------------------------------------------------*\
| Mode Class                                                |
\*---------------------------------------------------------*/
class mode
{
public:
    /*-----------------------------------------------------*\
    | Mode Information                                      |
    \*-----------------------------------------------------*/
    std::string             name;           /* Mode name                    */
    int                     value;          /* Device-specific mode value   */
    unsigned int            flags;          /* Mode flags bitfield          */
    unsigned int            speed_min;      /* speed minimum value          */
    unsigned int            speed_max;      /* speed maximum value          */
    unsigned int            brightness_min; /* brightness min value         */
    unsigned int            brightness_max; /* brightness max value         */
    unsigned int            colors_min;     /* minimum number of mode colors*/
    unsigned int            colors_max;     /* maximum numver of mode colors*/

    /*-----------------------------------------------------*\
    | Mode Settings                                         |
    \*-----------------------------------------------------*/
    unsigned int            speed;          /* Mode speed parameter value   */
    unsigned int            brightness;     /* Mode brightness value        */
    unsigned int            direction;      /* Mode direction value         */
    unsigned int            color_mode;     /* Mode color selection         */
    std::vector<RGBColor>
                            colors;         /* mode-specific colors         */

    /*-----------------------------------------------------*\
    | Functionality defined inline so that it can be used   |
    | in consuming plugins                                  |
    \*-----------------------------------------------------*/
    mode()
    {
        /*-------------------------------------------------*\
        | Initialize mode variables                         |
        \*-------------------------------------------------*/
        name           = "";
        value          = 0;
        flags          = 0;
        speed_min      = 0;
        speed_max      = 0;
        brightness_min = 0;
        brightness_max = 0;
        colors_min     = 0;
        colors_max     = 0;
        speed          = 0;
        brightness     = 0;
        direction      = 0;
        color_mode     = 0;
    }

    ~mode()
    {
        colors.clear();
    }
};

/*---------------------------------------------------------*\
| LED Class                                                 |
\*---------------------------------------------------------*/
class led
{
public:
    /*-----------------------------------------------------*\
    | LED Information                                       |
    \*-----------------------------------------------------*/
    std::string             name;           /* LED name                     */
    unsigned int            value;          /* Device-specific LED value    */

    /*-----------------------------------------------------*\
    | Functionality defined inline so that it can be used   |
    | in consuming plugins                                  |
    \*-----------------------------------------------------*/
    led()
    {
        /*-------------------------------------------------*\
        | Initialize LED variables                          |
        \*-------------------------------------------------*/
        name        = "";
        value       = 0;
    }

    ~led()
    {

    }
};

/*---------------------------------------------------------*\
| Segment Class                                             |
\*---------------------------------------------------------*/
class segment
{
public:
    std::string             name;           /* Segment name                 */
    zone_type               type;           /* Segment type                 */
    unsigned int            start_idx;      /* Start index within zone      */
    unsigned int            leds_count;     /* Number of LEDs in segment    */
    matrix_map_type         matrix_map;     /* Matrix map                   */
    segment_flags           flags;          /* Segment flags                */

    /*-----------------------------------------------------*\
    | Functionality defined inline so that it can be used   |
    | in consuming plugins                                  |
    \*-----------------------------------------------------*/
    segment()
    {
        /*-------------------------------------------------*\
        | Initialize segment variables                      |
        \*-------------------------------------------------*/
        name        = "";
        type        = 0;
        start_idx   = 0;
        leds_count  = 0;
        flags       = 0;
    }

    ~segment()
    {

    }
};

/*---------------------------------------------------------*\
| Zone Class                                                |
\*---------------------------------------------------------*/
class zone
{
public:
    std::string             name;           /* Zone name                    */
    std::string             display_name;   /* Display name                 */
    zone_type               type;           /* Zone type                    */
    led *                   leds;           /* List of LEDs in zone         */
    RGBColor *              colors;         /* Colors of LEDs in zone       */
    unsigned int            start_idx;      /* Start index of led/color     */
    unsigned int            leds_count;     /* Number of LEDs in zone       */
    unsigned int            leds_min;       /* Minimum number of LEDs       */
    unsigned int            leds_max;       /* Maximum number of LEDs       */
    matrix_map_type         matrix_map;     /* Matrix map                   */
    std::vector<segment>    segments;       /* Segments in zone             */
    zone_flags              flags;          /* Zone flags bitfield          */
    std::vector<mode>       modes;          /* Zone-specific modes          */
    int                     active_mode;    /* Active zone-specific mode    */

    /*-----------------------------------------------------*\
    | Functionality defined inline so that it can be used   |
    | in consuming plugins                                  |
    \*-----------------------------------------------------*/
    zone()
    {
        /*-------------------------------------------------*\
        | Initialize zone variables                         |
        \*-------------------------------------------------*/
        name        = "";
        type        = 0;
        leds        = NULL;
        colors      = NULL;
        start_idx   = 0;
        leds_count  = 0;
        leds_min    = 0;
        leds_max    = 0;
        flags       = 0;
        active_mode = -1;
    }

    ~zone()
    {

    }
};

typedef struct
{
    /*-----------------------------------------------------*\
    | Controller information strings                        |
    \*-----------------------------------------------------*/
    std::string             description;    /* controller description   */
    std::string             location;       /* controller location      */
    std::string             name;           /* controller name          */
    std::string             serial;         /* controller serial number */
    std::string             vendor;         /* controller vendor        */
    std::string             version;        /* controller version       */
    std::string             configuration;  /* controller device-       */
                                            /* specific config JSON     */

    /*-----------------------------------------------------*\
    | Controller variables                                  |
    \*-----------------------------------------------------*/
    int                     active_mode;    /* active mode              */
    controller_flags        flags;          /* controller flags         */
    device_type             type;           /* device type              */

    /*-----------------------------------------------------*\
    | Controller member vectors                             |
    \*-----------------------------------------------------*/
    std::vector<mode>       modes;          /* Modes                    */
    std::vector<zone>       zones;          /* Zones                    */
    std::vector<led>        leds;           /* LEDs                     */

    /*-----------------------------------------------------*\
    | Pointer to user object                                |
    \*-----------------------------------------------------*/
    void*                   object_ptr;

    /*-----------------------------------------------------*\
    | Function pointers                                     |
    \*-----------------------------------------------------*/
    void                    (*DeviceConfigureZone)(void*, int);

    void                    (*DeviceUpdateLEDs)(void*);
    void                    (*DeviceUpdateZoneLEDs)(void*, int);
    void                    (*DeviceUpdateSingleLED)(void*, int);

    void                    (*DeviceUpdateMode)(void*);
    void                    (*DeviceSaveMode)(void*);
    void                    (*DeviceUpdateZoneMode)(void*, int);

    void                    (*DeviceUpdateDeviceSpecificConfiguration)(void*);
    void                    (*DeviceUpdateDeviceSpecificZoneConfiguration)(void*, int);
} RGBController_Setup;

class RGBControllerInterface
{
public:
    /*-----------------------------------------------------*\
    | Controller Information                                |
    \*-----------------------------------------------------*/
    virtual std::string             GetName()                                                                                                           = 0;
    virtual std::string             GetVendor()                                                                                                         = 0;
    virtual std::string             GetDescription()                                                                                                    = 0;
    virtual std::string             GetVersion()                                                                                                        = 0;
    virtual std::string             GetSerial()                                                                                                         = 0;
    virtual std::string             GetLocation()                                                                                                       = 0;
    virtual std::string             GetDisplayName()                                                                                                    = 0;

    virtual device_type             GetDeviceType()                                                                                                     = 0;
    virtual controller_flags        GetFlags()                                                                                                          = 0;

    /*-----------------------------------------------------*\
    | Hidden Flag Functions                                 |
    \*-----------------------------------------------------*/
    virtual bool                    GetHidden()                                                                                                         = 0;
    virtual void                    SetHidden(bool hidden)                                                                                              = 0;

    /*-----------------------------------------------------*\
    | Zone Functions                                        |
    \*-----------------------------------------------------*/
    virtual zone                    GetZone(unsigned int zone_idx)                                                                                      = 0;
    virtual int                     GetZoneActiveMode(unsigned int zone)                                                                                = 0;
    virtual RGBColor                GetZoneColor(unsigned int zone, unsigned int color_index)                                                           = 0;
    virtual RGBColor*               GetZoneColorsPointer(unsigned int zone)                                                                             = 0;
    virtual unsigned int            GetZoneCount()                                                                                                      = 0;
    virtual std::string             GetZoneDisplayName(unsigned int zone)                                                                               = 0;
    virtual zone_flags              GetZoneFlags(unsigned int zone)                                                                                     = 0;
    virtual unsigned int            GetZoneLEDsCount(unsigned int zone)                                                                                 = 0;
    virtual unsigned int            GetZoneLEDsMax(unsigned int zone)                                                                                   = 0;
    virtual unsigned int            GetZoneLEDsMin(unsigned int zone)                                                                                   = 0;
    virtual matrix_map_type         GetZoneMatrixMap(unsigned int zone)                                                                                 = 0;
    virtual const unsigned int*     GetZoneMatrixMapData(unsigned int zone)                                                                             = 0;
    virtual unsigned int            GetZoneMatrixMapHeight(unsigned int zone)                                                                           = 0;
    virtual unsigned int            GetZoneMatrixMapWidth(unsigned int zone)                                                                            = 0;
    virtual unsigned int            GetZoneModeCount(unsigned int zone)                                                                                 = 0;
    virtual unsigned int            GetZoneModeBrightness(unsigned int zone, unsigned int mode)                                                         = 0;
    virtual unsigned int            GetZoneModeBrightnessMax(unsigned int zone, unsigned int mode)                                                      = 0;
    virtual unsigned int            GetZoneModeBrightnessMin(unsigned int zone, unsigned int mode)                                                      = 0;
    virtual RGBColor                GetZoneModeColor(unsigned int zone, unsigned int mode, unsigned int color_index)                                    = 0;
    virtual unsigned int            GetZoneModeColorMode(unsigned int zone, unsigned int mode)                                                          = 0;
    virtual unsigned int            GetZoneModeColorsCount(unsigned int zone, unsigned int mode)                                                        = 0;
    virtual unsigned int            GetZoneModeColorsMax(unsigned int zone, unsigned int mode)                                                          = 0;
    virtual unsigned int            GetZoneModeColorsMin(unsigned int zone, unsigned int mode)                                                          = 0;
    virtual unsigned int            GetZoneModeDirection(unsigned int zone, unsigned int mode)                                                          = 0;
    virtual unsigned int            GetZoneModeFlags(unsigned int zone, unsigned int mode)                                                              = 0;
    virtual std::string             GetZoneModeName(unsigned int zone, unsigned int mode)                                                               = 0;
    virtual unsigned int            GetZoneModeSpeed(unsigned int zone, unsigned int mode)                                                              = 0;
    virtual unsigned int            GetZoneModeSpeedMax(unsigned int zone, unsigned int mode)                                                           = 0;
    virtual unsigned int            GetZoneModeSpeedMin(unsigned int zone, unsigned int mode)                                                           = 0;
    virtual std::string             GetZoneName(unsigned int zone)                                                                                      = 0;
    virtual unsigned int            GetZoneSegmentCount(unsigned int zone)                                                                              = 0;
    virtual segment_flags           GetZoneSegmentFlags(unsigned int zone, unsigned int segment)                                                        = 0;
    virtual unsigned int            GetZoneSegmentLEDsCount(unsigned int zone, unsigned int segment)                                                    = 0;
    virtual matrix_map_type         GetZoneSegmentMatrixMap(unsigned int zone, unsigned int segment)                                                    = 0;
    virtual const unsigned int *    GetZoneSegmentMatrixMapData(unsigned int zone, unsigned int segment)                                                = 0;
    virtual unsigned int            GetZoneSegmentMatrixMapHeight(unsigned int zone, unsigned int segment)                                              = 0;
    virtual unsigned int            GetZoneSegmentMatrixMapWidth(unsigned int zone, unsigned int segment)                                               = 0;
    virtual std::string             GetZoneSegmentName(unsigned int zone, unsigned int segment)                                                         = 0;
    virtual unsigned int            GetZoneSegmentStartIndex(unsigned int zone, unsigned int segment)                                                   = 0;
    virtual unsigned int            GetZoneSegmentType(unsigned int zone, unsigned int segment)                                                         = 0;
    virtual unsigned int            GetZoneStartIndex(unsigned int zone)                                                                                = 0;
    virtual zone_type               GetZoneType(unsigned int zone)                                                                                      = 0;

    virtual unsigned int            GetLEDsInZone(unsigned int zone)                                                                                    = 0;

    virtual void                    SetZoneActiveMode(unsigned int zone, int mode)                                                                      = 0;
    virtual void                    SetZoneColor(unsigned int zone, unsigned int color_index, RGBColor color)                                           = 0;
    virtual void                    SetZoneModeBrightness(unsigned int zone, unsigned int mode, unsigned int brightness)                                = 0;
    virtual void                    SetZoneModeColor(unsigned int zone, unsigned int mode, unsigned int color_index, RGBColor color)                    = 0;
    virtual void                    SetZoneModeColorMode(unsigned int zone, unsigned int mode, unsigned int color_mode)                                 = 0;
    virtual void                    SetZoneModeColorsCount(unsigned int zone, unsigned int mode, unsigned int count)                                    = 0;
    virtual void                    SetZoneModeDirection(unsigned int zone, unsigned int mode, unsigned int direction)                                  = 0;
    virtual void                    SetZoneModeSpeed(unsigned int zone, unsigned int mode, unsigned int speed)                                          = 0;

    virtual bool                    SupportsPerZoneModes()                                                                                              = 0;

    /*-----------------------------------------------------*\
    | Mode Functions                                        |
    \*-----------------------------------------------------*/
    virtual unsigned int            GetModeCount()                                                                                                      = 0;
    virtual unsigned int            GetModeBrightness(unsigned int mode)                                                                                = 0;
    virtual unsigned int            GetModeBrightnessMax(unsigned int mode)                                                                             = 0;
    virtual unsigned int            GetModeBrightnessMin(unsigned int mode)                                                                             = 0;
    virtual RGBColor                GetModeColor(unsigned int mode, unsigned int color_index)                                                           = 0;
    virtual unsigned int            GetModeColorMode(unsigned int mode)                                                                                 = 0;
    virtual unsigned int            GetModeColorsCount(unsigned int mode)                                                                               = 0;
    virtual unsigned int            GetModeColorsMax(unsigned int mode)                                                                                 = 0;
    virtual unsigned int            GetModeColorsMin(unsigned int mode)                                                                                 = 0;
    virtual unsigned int            GetModeDirection(unsigned int mode)                                                                                 = 0;
    virtual unsigned int            GetModeFlags(unsigned int mode)                                                                                     = 0;
    virtual std::string             GetModeName(unsigned int mode)                                                                                      = 0;
    virtual unsigned int            GetModeSpeed(unsigned int mode)                                                                                     = 0;
    virtual unsigned int            GetModeSpeedMax(unsigned int mode)                                                                                  = 0;
    virtual unsigned int            GetModeSpeedMin(unsigned int mode)                                                                                  = 0;

    virtual void                    SetModeBrightness(unsigned int mode, unsigned int brightness)                                                       = 0;
    virtual void                    SetModeColor(unsigned int mode, unsigned int color_index, RGBColor color)                                           = 0;
    virtual void                    SetModeColorMode(unsigned int mode, unsigned int color_mode)                                                        = 0;
    virtual void                    SetModeColorsCount(unsigned int mode, unsigned int count)                                                           = 0;
    virtual void                    SetModeDirection(unsigned int mode, unsigned int direction)                                                         = 0;
    virtual void                    SetModeSpeed(unsigned int mode, unsigned int speed)                                                                 = 0;

    virtual int                     GetActiveMode()                                                                                                     = 0;
    virtual void                    SetActiveMode(int mode)                                                                                             = 0;
    virtual void                    SetCustomMode()                                                                                                     = 0;

    /*-----------------------------------------------------*\
    | LED Functions                                         |
    \*-----------------------------------------------------*/
    virtual unsigned int            GetLEDCount()                                                                                                       = 0;
    virtual std::string             GetLEDName(unsigned int led)                                                                                        = 0;
    virtual std::string             GetLEDDisplayName(unsigned int led)                                                                                 = 0;

    /*-----------------------------------------------------*\
    | Color Functions                                       |
    \*-----------------------------------------------------*/
    virtual RGBColor                GetColor(unsigned int led)                                                                                          = 0;
    virtual RGBColor*               GetColorsPointer()                                                                                                  = 0;
    virtual void                    SetColor(unsigned int led, RGBColor color)                                                                          = 0;

    virtual void                    SetAllColors(RGBColor color)                                                                                        = 0;
    virtual void                    SetAllZoneColors(int zone, RGBColor color)                                                                          = 0;

    /*-----------------------------------------------------*\
    | Device-Specific Configuration Functions               |
    \*-----------------------------------------------------*/
    virtual nlohmann::json          GetDeviceSpecificConfigurationSchema()                                                                              = 0;
    virtual nlohmann::json          GetDeviceSpecificConfiguration()                                                                                    = 0;
    virtual void                    SetDeviceSpecificConfiguration(nlohmann::json configuration_json)                                                   = 0;

    virtual nlohmann::json          GetDeviceSpecificZoneConfigurationSchema(int zone)                                                                  = 0;
    virtual nlohmann::json          GetDeviceSpecificZoneConfiguration(int zone)                                                                        = 0;
    virtual void                    SetDeviceSpecificZoneConfiguration(int zone, nlohmann::json configuration_json)                                     = 0;

    /*-----------------------------------------------------*\
    | Update Callback Functions                             |
    \*-----------------------------------------------------*/
    virtual void                    RegisterUpdateCallback(RGBControllerCallback new_callback, void * new_callback_arg)                                 = 0;
    virtual void                    UnregisterUpdateCallback(void * callback_arg)                                                                       = 0;
    virtual void                    ClearCallbacks()                                                                                                    = 0;
    virtual void                    SignalUpdate(unsigned int update_reason)                                                                            = 0;

    /*-----------------------------------------------------*\
    | Device Update Functions                               |
    \*-----------------------------------------------------*/
    virtual void                    UpdateLEDs()                                                                                                        = 0;
    virtual void                    UpdateZoneLEDs(int zone)                                                                                            = 0;
    virtual void                    UpdateSingleLED(int led)                                                                                            = 0;

    virtual void                    UpdateMode()                                                                                                        = 0;
    virtual void                    UpdateZoneMode(int zone)                                                                                            = 0;
    virtual void                    SaveMode()                                                                                                          = 0;

    virtual void                    ClearSegments(int zone)                                                                                             = 0;
    virtual void                    AddSegment(int zone, segment new_segment)                                                                           = 0;

    virtual void                    ConfigureZone(int zone_idx, zone new_zone)                                                                          = 0;
    virtual void                    ResizeZone(int zone, int new_size)                                                                                  = 0;

    virtual void                    ConfigureDevice(controller_flags new_flags, std::string new_name)                                                   = 0;
};
