#ifndef CONTROLLERS_H
#define CONTROLLERS_H
#include <EncoderButton.h>
#include <Adafruit_MCP23X17.h>
#include "Arduino.h"
#include "MIDIUSB.h"

// Uncomment this line if you want pin and values printed on the serial, remember to open a console because it waits until a connection is established.
#define DEBUG

// Uncomment this line if you want to disable MIDI output, you have to comment the #include "MIDIUSB.h" as well
//#define DUMMY

// Analog controls (sliders and potentiometers), the deadzone is the smallest increment that the control must have to trigger the effect.
#define DEAD_ZONE 15

// Stickyness is a deazone that lies around extreme positions (0-1023) and the middle (511, but trimmable) of readings.
#define STICKYNESS 30

// Time, in ms, needed for a long press
#define LONG_INTERVAL 1000

void noteOn(byte channel, byte pitch, byte velocity);
void noteOff(byte channel, byte pitch, byte velocity);
void controlChange(byte channel, byte control, byte value);
void eb_Encoder(EncoderButton& eb);


class AnalogControl {
  private:
    int pin;
    byte effect;
    int middle;
    int value;
    int prev_value;
  public:
    AnalogControl(int pin, byte effect, int middle);
    void init();
    void checkStatus();
};

class DigitalButton {
  private:
    int pin;
    bool pressed;
    long debounce;
    byte effect;
    byte effect_toggle;
    bool toggled;
    byte effect_long;
    byte effect_long_toggle;
    bool long_toggled;
    bool long_pressed;
  public:
    DigitalButton(int pin, byte effect, byte effect_toggle, byte effect_long, byte effect_long_toggle);
    void init();
    void checkStatus();
};

class MCP23017_Expander {
  private:
  	Adafruit_MCP23X17 mcp;
    int address;
    bool pressed[16];
    byte effects[16];
    byte effects_toggle[16];
    bool toggled[16];
    byte effects_long[16];
    byte effects_long_toggle[16];
    bool long_toggled[16];
    bool long_pressed[16];
    long debounce[16];
  public:
	MCP23017_Expander(int address, int effects[16], int effects_toggle[16], int effects_long[16], int effects_long_toggle[16]);
    void init();
    void checkStatus();
};


struct RotaryEncoderControl {
  EncoderButton rotary_encoder;
  byte effect;
};

class Mux {
  private:
    int pinSIG;
    int value[16];
    int prev_value[16];
    int mid_deadzone[16];
  public:
    int effects[16];
    static int pinS0;
    static int pinS1;
    static int pinS2;
    static int pinS3;
    Mux(int pinSIG, int effects[16], int mid_deadzone[16]);
    void init();
    void checkStatus(byte selector);
};

#endif
