#include "serial.h"
#include <unistd.h>
#include "zigateplugin.h"
#include <QtCore>

//extern QApplication a;
extern ZigatePlugin zigatePlugin;
extern SerialManager serialManager;

using namespace std;

SerialManager::SerialManager()
{
}

SerialManager::~SerialManager()
{
    this->close();
}

void SerialManager::initSerial()
{

    this->setBaudRate(115200);
    this->setDataBits(QSerialPort::Data8);
    this->setStopBits(QSerialPort::OneStop);
    this->setParity(QSerialPort::NoParity);

    openSerialPort();
}

// open serial port and return true when it is available
bool SerialManager::openSerialPort()
{
    bool result;
    bool test = false;

    while (1)
   {
       result = this->findSerialDevice();
       this->setPortName(this->serialDevicePath);
       if (result)
       {
           cout << "Device found :" + this->serialDevicePath.toStdString() << endl;
           break;
       }else
       {
           cout << "Device not found, waiting 10 seconds before retrying" << endl;
           sleep(10);
       }
   }

    while(!test or !this->isOpen())
    {
        test = this->open(QIODevice::ReadWrite);
        if (!test)
        {
            cout << "opening device: " << this->errorString().toStdString() << "=>" << this->serialDevicePath.toStdString() << endl;
            sleep(5);
        }
    };
    return true;
}

// launch the thread which read datas on serial port
void ZigatePlugin::readDatas()
{

    serialManager.dataRead = serialManager.readAll();
    //cout << "reading datas" << serialManager.dataRead.toHex(' ').toStdString() << endl;
    zigatePlugin.interpretResult(serialManager.dataRead);
}

void SerialManager::write2serial(QByteArray msg)
{
    cout << "writing to serial" << endl;
    dataWriteSize = msg.count();
    cout << "size = " << dataWriteSize << endl;
    this->write((const QByteArray)msg);
    cout << msg.toHex().toStdString() << endl;
}

bool SerialManager::findSerialDevice()
{
    const auto serialPortInfos = QSerialPortInfo::availablePorts();
    for (const QSerialPortInfo &portInfo : serialPortInfos)
    {
        cout << portInfo.serialNumber().toStdString() << this->deviceName.toStdString() << endl;
        if (portInfo.serialNumber().contains(this->deviceName))
        {
            this->portName = portInfo.portName();
            this->serialDevicePath = portInfo.systemLocation();
            this->serialDeviceDescription = portInfo.description();
            this->serialDeviceManufacturer = portInfo.manufacturer();
            this->serialDeviceNumber = portInfo.serialNumber();
            this->serialDeviceVendor = portInfo.vendorIdentifier();
            this->serialDeviceProduct = portInfo.productIdentifier();
            return true;
        }
    }
    return false;
}

void SerialManager::serialError(QSerialPort::SerialPortError error)
{
    cout << "error code : " << error << this->errorString().toStdString() << "=>" << this->serialDevicePath.toStdString() << endl;

    switch (error)
    {
        case 0:
        case 3:
            return;
        break;
        case 1:
        case 9:
            cout << "error code : " << error << this->errorString().toStdString() << "=>" << this->serialDevicePath.toStdString() << endl;
            this->close();
            openSerialPort();
       break;
        default:
            cout << "error code : " << error << this->errorString().toStdString() << "=>" << this->serialDevicePath.toStdString() << endl;
        break;
    }
}
