#include "portcontroller.h"
#include "QDebug"

PortController::PortController(Decoder *d) {
#ifdef USE_LIB_USB
  // init libusb
  int result = libusb_init(nullptr);
  if (result != 0) {
    qDebug() << "LibUSB init error: " << result;
  } else {
    qDebug() << "LibUSB initiated";
  }
  LIBUSBPort *port = new LIBUSBPort();
#endif

#ifdef USE_SERIAL
  SerialPort *port = new SerialPort();
#endif
  // move port to thread
  port->moveToThread(&portThread);
  // connect port and decoder
  connect(port, SIGNAL(newData(const QByteArray &)), d,
          SLOT(processData(const QByteArray &)));
#ifdef USE_LIB_USB
  // connect port and controller
  connect(this, SIGNAL(open(libusb_device *)), port,
          SLOT(requestOpen(libusb_device *)));
#endif
#ifdef USE_SERIAL
  // connect port and controller
  connect(this, SIGNAL(open(QString)), port, SLOT(requestOpen(QString)));
#endif
  // connect port and controller
  connect(port, SIGNAL(openStatus(bool)), this, SLOT(opened(bool)));
  connect(this, SIGNAL(send(QByteArray)), port, SLOT(requestSend(QByteArray)));
  connect(this, SIGNAL(stop()), port, SLOT(requestToStop()));
  this->portOpened = false;
  // start thread
  portThread.start();
#ifdef USE_LIB_USB
  this->devs = nullptr;
#endif
}

PortController::~PortController() {
  // end port thread
  portThread.quit();
  portThread.wait();
#ifdef USE_LIB_USB
  // exit libusb
  libusb_exit(nullptr);
#endif
}

#ifdef USE_LIB_USB
QList<QString> PortController::getAvailablePorts() {
  this->devices.clear();
  if (this->devs != nullptr) {
    libusb_free_device_list(this->devs, 1);
  }
  QList<QString> list;
  libusb_get_device_list(nullptr, &this->devs);
  libusb_device *dev;
  int i = 0, j = 0;
  while ((dev = devs[i++]) != nullptr) {
    struct libusb_device_descriptor desc;
    libusb_get_device_descriptor(dev, &desc);
    // filter IDs
    if (desc.idProduct == 0x1 && desc.idVendor == 0x1) {
      list.append(QString("Cam" + QString::number(j)));
      j++;
      devices.append(dev);
    }
  }
  return list;
}
#endif

#ifdef USE_SERIAL
QList<QString> PortController::getAvailablePorts() {
  QList<QSerialPortInfo> list = QSerialPortInfo::availablePorts();
  QList<QString> strList;
  foreach (QSerialPortInfo p, list) {
    // filter IDs
    if (p.productIdentifier() == 0x1 &&
        p.vendorIdentifier() == 0x1) { // set correct IDs
      strList.append(p.portName());
    }
  }
  return strList;
}
#endif

void PortController::openPort(QString portName) {
  if (portName != "") {
#ifdef USE_LIB_USB
    int num = portName.remove(0, 3).toInt();
    emit open(this->devices.at(num));
#endif
#ifdef USE_SERIAL
    emit open(portName);
#endif
  } else {
    emit openStatus(false, false);
  }
}

void PortController::opened(bool o) {
  emit openStatus(o, this->portOpened);
  this->portOpened = o;
}

void PortController::sendData(QByteArray data) { emit send(data); }

void PortController::stopPort() { emit stop(); }
