#define JOY_HORZ A0
#define JOY_VERT A1
#define JOY_SEL 2
#define LED0 11
#define LED1 10
#define LED2 9
#define LED3 6
#define LED4 5
#define LED5 3

class Led
{
public:
  Led(int brightness, int pin)
  {
    _step = 10;
    _pin = pin;       
    _brightness = brightness;
    pinMode(pin, OUTPUT);
    analogWrite(pin, brightness);    
  }
  ~Led() = default;

  void brightnessUp()
  {
      _brightness += _step;
      if(_brightness >= 250) {_brightness = 255;} 
      analogWrite(_pin, _brightness);
  }
  void brightnessDown()
  {
      _brightness -= _step;
      if(_brightness <= 5) {_brightness = 0;} 
      analogWrite(_pin, _brightness);
  }

  void ledOff()
  {
    _brightness = 0;
    analogWrite(_pin, 0);
  }

  void ledSet(int brightness)
  {
    _brightness = brightness;
    analogWrite(_pin, brightness);
  }

  int getBrightness()
  {
    return _brightness;
  }

  private:
  int _step;
  int _brightness;    
  int _pin;  
};

template<int _maxLeds>
class Joystick
{
  public:
  Joystick(int pinHorz, int pinVert, int pinSel)
  {
    _pinSel = pinSel;
    _pinVert = pinVert;
    _pinHorz = pinHorz;
    _ledIndex = 0;
    _deadZone = 100;
    _selState = 0;
    pinMode(_pinSel, INPUT);
    pinMode(_pinVert, INPUT);
    pinMode(_pinHorz, INPUT);
  }
  ~Joystick() = default;

  void addLed(Led* led)
  {
    if(_countLeds + 1 <= _maxLeds)
    {
      _leds[_countLeds++] = led;    
    }    
  }

  void process()
  {
    int y = analogRead(_pinVert);
    int x = analogRead(_pinHorz);
    int push = debounce();
    
    if(x > 512 + _deadZone)
    {
      _ledIndex -= 1;
      if(_ledIndex < 0) 
      {
        _ledIndex = 0;      
      }
      else
      {
        int b = _leds[_ledIndex + 1]->getBrightness();
        _leds[_ledIndex + 1]->ledOff();      
        _leds[_ledIndex]->ledSet(b);
      }
      
    }
    else if(x < 512 - _deadZone)
    {
      _ledIndex += 1;
      if(_ledIndex >= _countLeds)
      {
        _ledIndex = _countLeds - 1;        
      }
      else
      {
        int b = _leds[_ledIndex - 1]->getBrightness();
        _leds[_ledIndex - 1]->ledOff();
        _leds[_ledIndex]->ledSet(b);
      }
      
    }

    if(y > 512 + _deadZone)
    {
      _leds[_ledIndex]->brightnessUp();
    }
    else if(y < 512 - _deadZone)
    {
      _leds[_ledIndex]->brightnessDown();
    }

    if(push != _selState)
    {
      int b = _leds[_ledIndex]->getBrightness();
      _leds[_ledIndex]->ledOff();
      _ledIndex = 0;
      _leds[_ledIndex]->ledSet(b);
      _selState = push;
    } 
  }

  private:
  int _pinSel;  
  int _pinHorz;
  int _pinVert;
  int _ledIndex;
  int _countLeds;
  int _selState;
  Led* _leds[_maxLeds];
  int _deadZone;

  int debounce ()
  {
    int current = digitalRead(_pinSel);
    if(_selState != current)
    {
      delay(5);
      current = digitalRead(_pinSel);
    }
    return current;
  }
};


Led led0(255, LED0);
Led led1(0, LED1);
Led led2(0, LED2);
Led led3(0, LED3);
Led led4(0, LED4);
Led led5(0, LED5);

Joystick<6> joystick(JOY_HORZ, JOY_VERT, JOY_SEL);


void setup() 
{  
  analogReference(DEFAULT);
  joystick.addLed(&led0);
  joystick.addLed(&led1);
  joystick.addLed(&led2);
  joystick.addLed(&led3);
  joystick.addLed(&led4);
  joystick.addLed(&led5);  
}

void loop() 
{
  joystick.process();
  
  delay(100);
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
joystick1:VCC
joystick1:VERT
joystick1:HORZ
joystick1:SEL
joystick1:GND
r6:1
r6:2
r1:1
r1:2
r2:1
r2:2
r3:1
r3:2
r4:1
r4:2
r5:1
r5:2
led1:A
led1:C
led2:A
led2:C
led4:A
led4:C
led5:A
led5:C
led6:A
led6:C
led7:A
led7:C