// NOTE: SD Card DOES NOT WORK OFFLINE, 
#include "Buttons.h"
#include "Display.h"
#include "InfraRed.h"
#include "MultiMediaSwitch.h"
#include "NewSerial.h"
#include "SDCardStorage.h"
#include "AppVersion.h"
#include "esp32.h"
#include <Arduino.h>
#include <SD.h>
#include <functional>
#include <vector>
InfraRedReceive irReceiver(39, false, false);
InfraRedSend irSender(4, false, false);
NewSerial newSerial(LogLevel::debug);
SPI1pins spi1(true);
SDCardStorage sdCard(spi1, 25, "LCD-sdcard");
SPI0pins spi0;
DisplayOptions displayOptions;
Display display(spi0, displayOptions);
ButtonOptions buttonOptions;
Buttons buttons(buttonOptions);
DeviceManager deviceManager;
MultiMediaSwitch mediaSwitch(sdCard, display, deviceManager);
void setup() {
  // To-do: store/load in system memory
  int activeInputA = 1;
  int activeInputB = 1;
  bool outputAisActive = false;
  bool outputBisActive = false;
  sdCard.enableMock();
  NewSerial::info(__PRETTY_FUNCTION__, "start");
  NewSerial::info(__PRETTY_FUNCTION__, "AppVersion: %s", AppVersionInfo::FULL_VERSION);
  // Work-arround SD bug, when running SD.begin from within annother class the SD class will not read/write to any
  // file.
  auto sdInit = SD.begin(spi1.cs, spi1.spiClass);
  display.setup();
  sdCard.setup(true, sdInit);
  try {
    mediaSwitch.loadConfiguration(activeInputA, activeInputB, outputAisActive, outputBisActive);
  } catch (const LocalStorageException &e) {
    const int level = static_cast<int>(e.severityLevel) + 1;
    NewSerial::printException(level, e);
  }
  ButtonSetupOptions buttonSetupOptions;
  buttonSetupOptions.rotary1EncoderCallback = [&](bool clockwise) { mediaSwitch.updateInput(1, clockwise); };
  buttonSetupOptions.rotary1ButtonCallback = [&](bool longPress) { mediaSwitch.powerOffOutput(1); };
  buttonSetupOptions.rotary2EncoderCallback = [&](bool clockwise) { mediaSwitch.updateInput(2, clockwise); };
  buttonSetupOptions.rotary2ButtonCallback = [&](bool longPress) { mediaSwitch.powerOffOutput(2); };
  buttons.setup(buttonSetupOptions);
  NewSerial::info(__PRETTY_FUNCTION__, "finished");
  // Serial.begin(115200);
  irReceiver.setup();
  irSender.setup();
  Serial.println("IR Receiver and Sender are ready");
}
void loop() {
  display.loop();
  // IRData IRreceiveData = infraRedReceive.loop();
  // infraRedSend.loop(IRreceiveData);
  delay(10); // this speeds up the simulation
  if (irReceiver.loop()) {
    Serial.println(resultToHumanReadableBasic(&irReceiver.results));
  }
}