template <uint8_t _muxCount, uint8_t _muxChannels, uint8_t _muxPins>
class Rox74HC40XX {
  public:
    Rox74HC40XX(){}

 //****************START VOID begin********************************************
   
    void begin(uint8_t ch1, uint8_t ch2, uint8_t ch3, int8_t ch4=-1){
      if(_muxChannels<3 || _muxChannels>4){
        delay(1000);
        Serial.println("channel must be 3 or 4");
        while(1);
      }
      if(_muxChannels==3 && _muxPins!=8){
        delay(1000);
        Serial.println("_muxPins must be 8");
        while(1);
      } else if(_muxChannels==4 && _muxPins!=16){
        delay(1000);
        Serial.println("_muxPins must be 16");
        while(1);
      }
      channels[0] = ch1;
      channels[1] = ch2;
      channels[2] = ch3;
      if(ch4!=-1 && _muxChannels==4){
        channels[3] = ch4;
      }
      for(uint8_t i = 0 ; i < _muxChannels ; i++){
        pinMode(channels[i], OUTPUT);
      }
      delay(10);
      timeout = millis();
    }

//****************END VOID begin********************************************

    uint16_t getLength(){
      return _muxCount*_muxPins;
    }

 //****************START void setSignalPin********************************************
   
    // @n: the index of the mux
    // @pin: the pin on the teensy connected to that mux' signal pin
    // this method must be called for each mux
    void setSignalPin(uint8_t n, uint8_t pin){
      if(n < _muxCount){
        signalPin[n] = pin;
        pinMode(pin, INPUT);
      }
    }
//****************END void setSignalPin********************************************
   

    // these analog multiplexers require a small delay between pin read
    // so that their capacitor for each pin is charged/discharged
    // since we don't want to use an actual delay() we use an elapsedMillis
    // you can pass a value to this function in your sketch to change the
    // number of milliseconds between each pin read.
    bool update(uint8_t readInterval=1){
      if(millis()-timeout >= readInterval){
        readMux();
        timeout = millis();
        // return true when the mux has been read
        // used for testing and to know when the mux has been read
        return true;
      }
      return false;
    }
    uint16_t read(uint16_t n){
      if(n < (_muxCount * totalPins)){
        return values[n];
      }
      return 0;
    }
    uint16_t* getValues() {
      return values;
    }
private:
    uint8_t currentChannel = 0;
    uint8_t channels[_muxChannels];
    uint8_t signalPin[_muxCount];
    uint16_t values[_muxCount*_muxPins];
    unsigned long timeout;
    const uint16_t totalPins = (_muxCount*_muxPins);

//****************START void readMux********************************************
   
    void readMux(){
      for(uint8_t i = 0 ; i < _muxCount ; i++){
        uint8_t index = (i*_muxPins) + currentChannel;
        if(index < totalPins){
          values[index] = analogRead(signalPin[i]);
        }
      }
      // go to the next channel
      currentChannel++;
      if(currentChannel >= _muxPins){
        currentChannel = 0;
      }
      // set the channel pins
      for(uint8_t i=0 ; i < _muxChannels ; i++){
        digitalWrite(channels[i], bitRead(currentChannel, i));
      }
    }
//****************END void readMux********************************************
   

};

template <uint8_t _muxCount>
class Rox74HC4067 : public Rox74HC40XX <_muxCount, 4, 16> {};

template <uint8_t _muxCount>
class Rox74HC4051 : public Rox74HC40XX <_muxCount, 3, 8> {};

template <uint8_t _muxCount>
class RoxANAMUX : public Rox74HC40XX <(_muxCount*2), 4, 16> {};

// MUX_TOTAL is the number of 74HC4067s that you have chained together
// if you have more than 1 then change it to that number.
#define MUX_TOTAL 1
Rox74HC4067 <MUX_TOTAL> mux;


#define PIN_S0  8
#define PIN_S1  9
#define PIN_S2  10
#define PIN_S3  11
#define PIN_SIG0  A0

// this is the pin of the 74HC4067 that we will read
#define PIN_TO_READ 0

// keep track of the previous value, while the library handles 10-bit values
// for this example we'll lower the resolution to 8-bits
// this is to avoid some of the noise since there's no smoothing in the library.
//uint8_t prev[16];
uint8_t prev = 0;

void setup(){
  delay(100);
  Serial.begin(9600);
    Serial.println("Serial.begin");
  // being the mux
  mux.begin(PIN_S0, PIN_S1, PIN_S2, PIN_S3);
     Serial.println("mux.begin");
  // set what pin is the signal pin for the first mux
  // the first argument is the index of the mux, second is the pin number
  mux.setSignalPin(0, PIN_SIG0);
}

void loop(){
  // read the mux
  // this method should always be in your loop() function
  // the update method has an option parameter which is the number of millis
  // between each pin read, if you don't pass an argument it will read them
  // every 1 millisecond
  //mux.update();
  // read each pin
  // for(uint8_t i=0,n=mux.getLength();i<n;i++){
  //   // since the Rox74HC4067 doesn't smooth the values it just reads them raw
  //   // we'll only read one pin on this example
  //   if(i==PIN_TO_READ){
  //     uint8_t data = mux.read(i)>>2;
  //     if(data!=prev){
  //       prev = data;
  //       Serial.print("Mux pin ");
  //       Serial.print(i);
  //       Serial.print(" = ");
  //       Serial.print(data);
  //     }
  //   }
  // // }
  // bool upd = mux.update();
  // Serial.print(upd);
  // if (upd) {
  //   Serial.print(mux.read(0));
  // }

  mux.update();
  for (byte i = 0; i < MUX_TOTAL; i++) {
    // if (pots[i].update(muxes.read(i))) {
    //   MIDI.sendControlChange(i, pots[i].read(), MIDI_CHANNEL);
    // }
    Serial.print(mux.read(i));
  }



  // for (int i=0; i<5; i++) {
  //   int data = mux.read(i);
  //   prev[i] = data;
  // }

  // for (const int &n : prev) {
  //   Serial.print(n);
  //   Serial.println();
  // }


  // for(uint8_t i=0,n=mux.getLength();i<n;i++){
    // since the Rox74HC4067 doesn't smooth the values it just reads them raw
    // we'll only read one pin on this example
    // if(i==PIN_TO_READ){
    //uint8_t data = mux.read(i)>>2;
    // if(data!=prev){
      // prev = data;
  //     Serial.print("Mux pin ");
  //     Serial.print(i);
  //     Serial.print(" = ");
  //     Serial.println(data);
  // }

  // }

  
  
  // for (int i=0; i<3; i++) {
  //   uint8_t data = mux.read(i);
  //   if (data!=prev[i]) {
  //     Serial.print("Ch");
  //     Serial.print(i);
  //     Serial.print(":");
  //     Serial.print(data);
  //     Serial.print( "prev:");
  //     Serial.print(prev[i]);
  //     Serial.println();
  //     prev[i] = data;
  //   }
    //int valList[] = _values;
    //Serial.print(valList[]);
    // for (int i=0; i<3; i++) {
    //   Serial.print("Ch");
    //   Serial.print(i);
    //   Serial.print(":");

    //   Serial.print(mux.read(i));
    //   Serial.print(" ");
    // }
    // uint16_t* valList = mux.getValues();
    // for (int i=0; i<16; i++) {
    //   mux.update();
    //   Serial.print(valList[i]);
    //   Serial.print(" ");
    // }
    
    //delay(50);
  // }



  // for (int i=0; i<3; i++) {
  //   mux.update();
  //   int data = mux.read(i);
  //   Serial.println(data);
  //   //if (data!=prev) {
  //   // prev = data;
  //   // Serial.print(i);
  //   // Serial.print(":");
  //   // Serial.print(data);
  //   // Serial.print(" ");
  //   //}
//  Serial.println();
  delay(50);
  // }
}