#define LED_RED 11
#define LED_GREEN 10
#define LED_BLUE 9

#define BUTTON_RED_DOWN 7
#define BUTTON_GREEN_DOWN 6
#define BUTTON_BLUE_DOWN 5
#define BUTTON_RED_UP 4
#define BUTTON_GREEN_UP 3
#define BUTTON_BLUE_UP 2

class RgbLed
{
public:
  RgbLed(int r, int g, int b, int pinR, int pinG, int pinB)
  {
    step = 50;
    pinRed = pinR;
    pinGreen = pinG;
    pinBlue = pinB;

    red = r;
    green = g;
    blue = b;

    digitalWrite(pinRed, r);
    digitalWrite(pinGreen, g);
    digitalWrite(pinBlue, b);
  }
  ~RgbLed() = default;

  void redUp()
  {
      red -= step;
      if(red <= 5) {red = 0;} 
      analogWrite(pinRed, red);
  }

  void redDown()
  {
      red += step;
      if(red >= 250) {red = 255;} 
      analogWrite(pinRed, red);
  }

  void greenUp()
  {
      green -= step;
      if(green <= 5) {green = 0;}
      analogWrite(pinGreen, green);
  }

  void greenDown()
  {
      green += step;
      if(green >= 250) {green = 255;}
      analogWrite(pinGreen, green);
  }

  void blueUp()
  {
      blue -= step;
      if(blue <= 5) {blue = 0;}
      analogWrite(pinBlue, blue);
  }

  void blueDown()
  {
      blue += step;
      if(blue >= 250) {blue = 255;}
      analogWrite(pinBlue, blue);
  }

private:
  int step;

  int red;
  int green;
  int blue;
  
  int pinRed;
  int pinGreen;
  int pinBlue;
};

class Button
{
public:
  Button(RgbLed* _led, void (RgbLed::*_action)(void), int pinB)
  {
    led = _led;
    action =_action;
    lastButton = LOW;
    curButton = LOW;
    pinButton = pinB;
  }

  ~Button() = default;

  void processButton()
  {
    curButton = debounce(lastButton, pinButton);
    if (lastButton == HIGH && curButton == LOW)
    {
      (led->*action)();
    }
    lastButton = curButton;
  }

private:
  RgbLed* led;
  void (RgbLed::*action)(void);
  int lastButton;
  int curButton;
  int pinButton;

  int debounce (int last, int button)
  {
    int current = digitalRead(button);
    if(last != current)
    {
      delay(5);
      current = digitalRead(button);
    }
    return current;
  }
};

RgbLed led(255, 255, 255, LED_RED, LED_GREEN, LED_BLUE);

Button redUpButton(&led, &RgbLed::redUp, BUTTON_RED_UP);
Button redDownButton(&led, &RgbLed::redDown, BUTTON_RED_DOWN);

Button greenUpButton(&led, &RgbLed::greenUp, BUTTON_GREEN_UP);
Button greenDownButton(&led, &RgbLed::greenDown, BUTTON_GREEN_DOWN);

Button blueUpButton(&led, &RgbLed::blueUp, BUTTON_BLUE_UP);
Button blueDownButton(&led, &RgbLed::blueDown, BUTTON_BLUE_DOWN);

void setup() 
{
  pinMode(LED_RED, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_BLUE, OUTPUT);

  pinMode(BUTTON_RED_UP, INPUT_PULLUP);
  pinMode(BUTTON_GREEN_UP, INPUT_PULLUP);
  pinMode(BUTTON_BLUE_UP, INPUT_PULLUP);
  pinMode(BUTTON_RED_DOWN, INPUT_PULLUP);
  pinMode(BUTTON_GREEN_DOWN, INPUT_PULLUP);
  pinMode(BUTTON_BLUE_DOWN, INPUT_PULLUP);
}

void loop() 
{
  redUpButton.processButton();
  redDownButton.processButton();

  greenUpButton.processButton();
  greenDownButton.processButton();

  blueUpButton.processButton();
  blueDownButton.processButton();
}