// bytran -|- spectral calculations for portable devices using the HITRAN database
//
// Developed by Dzianis Pliutau (Denis Plutov) and Kostya Roslyakov
// www.bytran.org | bytran@bytran.org
// Copyright (c) 2016 Dzianis Pliutau
// Distributed under the MIT license
//
// The MIT License (MIT)
// Copyright (c) 2016 Dzianis Pliutau
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.



// Object to carry out serial port communication with an external device
#include "serialport.h"
#include <QDebug>
#include <QList>

SerialPort::SerialPort(QObject *parent) : QObject(parent)
{    
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS

            // Creating the serial port object
            serial = new QSerialPort();

            // Getting the list of available ports
            QSerialPortInfo portInfo;
            ports = portInfo.availablePorts();
            // Need to scan for port change (when something is inserted or disconnected) and update the QML

            // Initializing the serial port with the default communication parameters (not sure how to deal with the port numbers)
            serial->setBaudRate(QSerialPort::Baud9600);
            serial->setDataBits(QSerialPort::Data8);
            serial->setStopBits(QSerialPort::OneStop);
            serial->setParity(QSerialPort::NoParity);
            serial->setFlowControl(QSerialPort::NoFlowControl);

            // Creating connections
            createConnections();

        #endif
    #endif
}

// Method to create connections for the serial port
void SerialPort::createConnections() {
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            connect(this->serial, &QSerialPort::readyRead, this, &SerialPort::readData);
        #endif
    #endif
}

// Methods to connect and disconnect the serial port
void SerialPort::connectSerialPort() {
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            serial->open(QIODevice::ReadWrite);
        #endif
    #endif
}
void SerialPort::disconnectSerialPort() {
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            serial->close();
        #endif
    #endif
}

// Method to indicate if a remote device is connected
bool SerialPort::getRemoteDeviceIsConnected() {
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            return serial->isOpen();
        #else
            return false;
        #endif
    #else
        return false;
    #endif
}

// Method is used to read data from the serial port
void SerialPort::readData() {
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            emit commandReceived(serial->readAll());
        #endif
    #endif
}

// Method to send a message to a remote device
void SerialPort::sendMessage(const QString &message) {
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            serial->write(message.toUtf8());
        #endif
    #endif
}
void SerialPort::sendMessage(const QByteArray &message) {
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            serial->write(message);
        #endif
    #endif
}

// Method to get a list of available port names
QStringList SerialPort::getPortNames()
{
    int i;  // Loop variable
    QStringList portNames;

    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            QSerialPortInfo portInfo;
            ports = portInfo.availablePorts();
            for (i = 0; i < ports.count(); i++) { portNames.append(ports.at(i).portName()); }
        #endif
    #endif

    return portNames;
}

// Methods to get and set the serial prot communication configuration
// http://doc.qt.io/qt-5/qserialport.html#setPortName
quint8 SerialPort::getPortIndex()
{
    quint8 i;  // Loop variable

    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            for (i = 0; i < ports.count(); i++) {
                if (serial->portName() == ports[i].portName()) { return i; }
            }
        #endif
    #endif
    return 0;
}
void SerialPort::setPortIndex(quint8 portIndex)
{
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            serial->close();
            serial->setPort(ports[portIndex]);
            serial->open(QIODevice::ReadWrite);
        #endif
    #endif
}

// http://doc.qt.io/qt-5/qserialport.html#BaudRate-enum
int SerialPort::getBaudRate()
{
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            if (serial->baudRate() == QSerialPort::Baud1200 )  { return 0; }
            if (serial->baudRate() == QSerialPort::Baud2400 )  { return 1; }
            if (serial->baudRate() == QSerialPort::Baud4800)   { return 2; }
            if (serial->baudRate() == QSerialPort::Baud9600)   { return 3; }
            if (serial->baudRate() == QSerialPort::Baud19200)  { return 4; }
            if (serial->baudRate() == QSerialPort::Baud38400)  { return 5; }
            if (serial->baudRate() == QSerialPort::Baud57600)  { return 6; }
            if (serial->baudRate() == QSerialPort::Baud115200) { return 7; }
        #endif
    #endif
    return 0;
}
void SerialPort::setBaudRate(int baudRate)
{
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            serial->close();
            if ( baudRate == 0 ) { serial->setBaudRate(QSerialPort::Baud1200);   }
            if ( baudRate == 1 ) { serial->setBaudRate(QSerialPort::Baud2400);   }
            if ( baudRate == 2 ) { serial->setBaudRate(QSerialPort::Baud4800);   }
            if ( baudRate == 3 ) { serial->setBaudRate(QSerialPort::Baud9600);   }
            if ( baudRate == 4 ) { serial->setBaudRate(QSerialPort::Baud19200);  }
            if ( baudRate == 5 ) { serial->setBaudRate(QSerialPort::Baud38400);  }
            if ( baudRate == 6 ) { serial->setBaudRate(QSerialPort::Baud57600);  }
            if ( baudRate == 7 ) { serial->setBaudRate(QSerialPort::Baud115200);  }
            serial->open(QIODevice::ReadWrite);
        #endif
    #endif
}

// http://doc.qt.io/qt-5/qserialport.html#Parity-enum
quint8 SerialPort::getParity()
{
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            if (serial->parity() == QSerialPort::NoParity)    { return 0; }
            if (serial->parity() == QSerialPort::OddParity)   { return 1; }
            if (serial->parity() == QSerialPort::EvenParity)  { return 2; }
            if (serial->parity() == QSerialPort::SpaceParity) { return 3; }
            if (serial->parity() == QSerialPort::MarkParity)  { return 4; }
        #endif
    #endif
    return 0;
}
void SerialPort::setParity(quint8 parity)
{
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            serial->close();
            if (parity == 0) { serial->setParity(QSerialPort::NoParity);    }
            if (parity == 1) { serial->setParity(QSerialPort::OddParity);   }
            if (parity == 2) { serial->setParity(QSerialPort::EvenParity);  }
            if (parity == 3) { serial->setParity(QSerialPort::SpaceParity); }
            if (parity == 4) { serial->setParity(QSerialPort::MarkParity);  }
            serial->open(QIODevice::ReadWrite);
        #endif
    #endif
}

// http://doc.qt.io/qt-5/qserialport.html#DataBits-enum
quint8 SerialPort::getDataBits()
{
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            if (serial->dataBits() == QSerialPort::Data5) { return 5; }
            if (serial->dataBits() == QSerialPort::Data6) { return 6; }
            if (serial->dataBits() == QSerialPort::Data7) { return 7; }
            if (serial->dataBits() == QSerialPort::Data8) { return 8; }
        #endif
    #endif
    return 0;
}
void SerialPort::setDataBits(quint8 dataBits)
{
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            serial->close();
            if (dataBits == 5) { serial->setDataBits(QSerialPort::Data5); }
            if (dataBits == 6) { serial->setDataBits(QSerialPort::Data6); }
            if (dataBits == 7) { serial->setDataBits(QSerialPort::Data7); }
            if (dataBits == 8) { serial->setDataBits(QSerialPort::Data8); }
            serial->open(QIODevice::ReadWrite);
        #endif
    #endif
}

// http://doc.qt.io/qt-5/qserialport.html#StopBits-enum
quint8 SerialPort::getStopBits()
{
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            // 1.5 bits was omitted but maybe will have to be re-introduced later for the Windows operating system
            if (serial->stopBits() == QSerialPort::OneStop) { return 1; }
            if (serial->stopBits() == QSerialPort::TwoStop) { return 2; }
        #endif
    #endif
    return 0;
}
void SerialPort::setStopBits(quint8 stopBits)
{
    #ifndef Q_OS_WINRT
        #ifndef Q_OS_IOS
            serial->close();
            // 1.5 bits was omitted but maybe will have to be re-introduced later for the Windows operating system
            if (stopBits == 1) {serial->setStopBits(QSerialPort::OneStop); }
            if (stopBits == 2) {serial->setStopBits(QSerialPort::TwoStop); }
            serial->open(QIODevice::ReadWrite);
        #endif
    #endif
}
