#ifndef __MC_GPIOBUTTON_HPP
#define __MC_GPIOBUTTON_HPP

#include <stdint.h>
#include <vector>
#include <boost/signals2.hpp>
#include <gpiod.hpp>
#include "../thread/thread.hpp"

enum class GpioEdge
{
    None        = 0,
    Rising      = 1,
    Falling     = 2,
    Both        = 3
};

enum class GpioDirection
{
    Input       = 0,
    Output      = 1,
    PwmOutput   = 2,
};

enum class GpioPullup
{
    None        = 0,
    PullUp      = 1,
    PullDown    = 2,
};

enum class GpioOutput
{
    Both        = 0,
    OpenDrain   = 1,
    OpenSource  = 2,
};


enum class GpioPolarity
{
    ActiveHigh  = 0,
    ActiveLow   = 1,
};


class GpioBase : protected Thread
{
public:
    GpioBase();
    ~GpioBase();

    boost::signals2::signal<void (uint8_t gpio, GpioEdge edge, bool level)> onChange;

    void PinMode(GpioDirection dir, GpioOutput op, bool active_low = false);
    void PinMode(GpioDirection dir, GpioPullup pu, bool active_low = false);
    void PinMode(GpioDirection dir, bool active_low = false);

    void Listen(GpioEdge edge, bool active_low = false);

    virtual void Listen(GpioEdge edge, GpioPullup pu, bool active_low = false) = 0;

protected:
    virtual void PinMode(GpioDirection dir, GpioPullup pu = GpioPullup::None, GpioOutput op = GpioOutput::Both, bool active_low = false) = 0;
    gpiod::line_request init_linerq(GpioDirection dir, GpioEdge edge, GpioPullup pu, GpioOutput op, bool active_low);
    gpiod::chip gpioChip;
    
    GpioDirection dir;

};

class GpioPin : public GpioBase
{
public:
    GpioPin(uint8_t gpio);
    ~GpioPin();

    virtual void DigitalWrite(bool value);
    virtual bool DigitalRead(void);

    virtual void PwmWrite(uint32_t width);

    virtual void Listen(GpioEdge edge, GpioPullup pu, bool active_low = false);

    virtual bool IsAvailable();
protected:
    virtual void PinMode(GpioDirection dir, GpioPullup pu = GpioPullup::None, GpioOutput op = GpioOutput::Both,bool active_low = false);

	virtual void ThreadLoop();
    gpiod::line line;

};

class GpioPins : public GpioBase
{
public:
    GpioPins(std::vector<uint8_t> gpios);
    ~GpioPins();

    virtual void DigitalWrite(std::vector<bool> values);
    virtual std::vector<bool> DigitalRead(void);
    virtual void PwmWrite(std::vector<uint32_t> widths);


    virtual void Listen(GpioEdge edge, GpioPullup pu, bool active_low = false);

protected:
    virtual void PinMode(GpioDirection dir, GpioPullup pu = GpioPullup::None, GpioOutput op = GpioOutput::Both,bool active_low = false);

	virtual void ThreadLoop();
    gpiod::line_bulk lines;

};

class RgbLed : protected GpioPins
{
protected:
    uint32_t gamma(uint8_t value);
public:
    RgbLed(const uint8_t rPin, const uint8_t gPin, const uint8_t bPin);

    /*! 
        \param r The red component (0 to 255)
        \param g The green component (0 to 255)
        \param b The blue component (0 to 255)
    */
    void SetColor(const uint8_t r, const uint8_t g, const uint8_t b);


};






#endif//__MC_HID_SERVER_HPP