#include <Arduino.h>
#include <MIDI_Controller.h>

#define s * 1000

/* Pins */
/* GPIO (I2C) */
const uint8_t gpio_int{0};
const uint8_t sda{2};
const uint8_t scl{3};
/* Multiplexer */
#define MUX_ADDRSIZE 5
const uint8_t mux_sig{A10};
const uint8_t mux_addr[MUX_ADDRSIZE]{15, 21, 20, 19, 18};
/* ShiftRegister (OUT) */
#define SHIFT_OUTPUTSIZE 4
const uint8_t shift_data{14};
const uint8_t shift_latch{16};
const uint8_t shift_clock{1};
/* keyboard (IN) */
#define KEYBOARD_INSIZE 6
const uint8_t keyboard_in[KEYBOARD_INSIZE]{4, 5, 6, 7, 8, 9};

/* Components */
/* GPIO (I2C) */
/* Multiplexer */
// AnalogMultiplex multiplexer(mux_sig, mux_addr);
/* ShiftRegister (OUT) */
// ShiftRegisterOut shiftRegister(shift_data, shift_clock, shift_latch, MSBFIRST, SHIFT_OUTPUTSIZE);
/* keyboard (IN) */

/* Midi links */
//USBDebugMIDI_Interface midiInterface(115200);

// Analog potentiometers[] = {
// 	{multiplexer.pin(4), MIDI_CC::Channel_Volume, 5},
// 	{multiplexer.pin(5), MIDI_CC::Channel_Volume, 6},
// 	{multiplexer.pin(6), MIDI_CC::Channel_Volume, 7},
// 	{multiplexer.pin(7), MIDI_CC::Channel_Volume, 8}
// };

bool ref[6*16];

//
// using namespace ExtIO;

void setup() {
	Serial.begin(115200);
	while (Serial.available() == 0){
		delay(.5 s);
	}

	ExtIO::pinMode(shift_clock, OUTPUT);
	ExtIO::pinMode(shift_data, OUTPUT);
	ExtIO::pinMode(shift_latch, OUTPUT);
	ExtIO::pinMode(2, OUTPUT);

	for (size_t i = 0; i < KEYBOARD_INSIZE; ++i) {
		ExtIO::pinMode(keyboard_in[i], INPUT);
	}

	for (size_t i = 0; i < 6*8; ++i) {
		ref[i] = false;
	}
}

void scanLineOut(int colNum);


void loop() {
	// long start = millis();
	// for (size_t i = 0; i < 4; ++i) {
	// 	val[i] = multiplexer.analogRead(i);
	// 	if (val[i] != ref[i]) {
	// 			Serial.print("p[");
	// 			Serial.print(i, DEC);
	// 			Serial.print("] = ");
	// 			Serial.println(val[i], DEC);
	// 		ref[i] = val[i];
	//
	// 	}
	// }
	// val[8] = readCapacitivePin(2);
	// if (abs(val[8] - ref[8]) >= 2) {
	// 	if (val[8] > ref[8]) {
	// 		// Serial.print("loop() time : ");
	// 		// Serial.println(lastLoop, DEC);
	// 		// Serial.print("average : ");
	// 		// Serial.println(loopAverage, DEC);
	// 		Serial.println(val[8], DEC);
	// 	}
	// 	ref[8] = val[8];
	// }


	// if (val[0] >= 500) {
	// 	digitalWrite(0, HIGH);
	// } else {
	// 	digitalWrite(0, LOW);
	// }

	for (size_t i = 0; i < 16; ++i) {
		scanLineOut(i);
		uint8_t rowValue[KEYBOARD_INSIZE];
		bool pressed = false;
		for (size_t j = 0; j < 6; ++j) {
			if ((rowValue[i] = ExtIO::digitalRead(keyboard_in[j])) == HIGH) {
				if (!ref[j * 16 + i]) {
					Serial.print("key ");
					Serial.print(j * 16 + i);
					Serial.print(" pressed (received on pin ");
					Serial.print(keyboard_in[j], DEC);
					Serial.print(" & emmited on pin ");
					Serial.print(i);
					Serial.println(")");
					ref[j * 16 + i] = true;
				}
			} else {
				ref[j * 16 + i] = false;
			}
			pressed |= rowValue[i];
		}
		if (pressed) {
			digitalWrite(2, HIGH);
		} else {
			digitalWrite(2, LOW);
		}
	}


	// for (uint8_t i = 0; i < 8; ++i) {
	// 	byte bitsToSend = 0b00000001 << i;
	// 	digitalWrite(shift_latch, LOW);
	// 	shiftOut(shift_data, shift_clock, MSBFIRST, bitsToSend);
	// 	digitalWrite(shift_latch, HIGH);
	// 	Serial.print(" ");
	// 	Serial.print(bitsToSend, BIN);
	// 	Serial.println(" HIGH");
	// 	delay(1 s);
	// 	//bitWrite(bitsToSend, i, LOW);
	// 	digitalWrite(shift_latch, LOW);
	// 	shiftOut(shift_data, shift_clock, MSBFIRST, 0b00000000);
	// 	digitalWrite(shift_latch, HIGH);
	// 	Serial.print(i);
	// 	Serial.println(" LOW");
	// 	delay(1 s);
	// }

	// analogWrite(9, val[0] * 256 / 1024);



	// MIDI_Controller.refresh();
	// lastLoop = millis() - start;
	// loopAverage = (loopAverage + lastLoop) / 2;
	//delay(.5 s);
}
byte bits[] = {
	0b00000001,
	0b00000010,
	0b00000100,
	0b00001000,
	0b00010000,
	0b00100000,
	0b01000000,
	0b10000000
};

void scanLineOut(int colNum) {
	ExtIO::digitalWrite(shift_latch, LOW);

	if(0 <= colNum && colNum <= 7) {
		ExtIO::shiftOut(shift_data, shift_clock, MSBFIRST, 0b00000000); //right sr
		ExtIO::shiftOut(shift_data, shift_clock, MSBFIRST, bits[colNum]); //left sr
	} else {
		ExtIO::shiftOut(shift_data, shift_clock, MSBFIRST, bits[colNum - 8]); //right sr
		ExtIO::shiftOut(shift_data, shift_clock, MSBFIRST, 0b00000000); //left sr
	}

	ExtIO::digitalWrite(shift_latch, HIGH);
}
