#include "communications.h"
#include <QObject>
#include <QThread>
#include <QSerialPort>
#include <QTcpSocket>
#include <QUdpSocket>
#include <QHostAddress>
#include <QMutex>
#include <QDebug>

void CommunicationBase::run()
{
    while(1){
        processFrameData();

        forwardMutex.lock();
        int size =forwardByteArrayList.count();
        forwardMutex.unlock();

        if(size >0){
            forwardMutex.lock();
            QByteArray byteArray =forwardByteArrayList.at(0);
            forwardByteArrayList.removeAt(0);
            forwardMutex.unlock();

            forwardMsg(byteArray);
        }

        uploadMutex.lock();
        size =uploadByteArrayList.count();
        uploadMutex.unlock();

        if(size >0){
            uploadMutex.lock();
            QByteArray byteArray =uploadByteArrayList.at(0);
            uploadByteArrayList.removeAt(0);
            uploadMutex.unlock();

            uploadServerMsg(byteArray);
        }
    }
}

void CommunicationBase::forwardMsgSlot(const QByteArray& byteArray)
{
    forwardMutex.lock();
    forwardByteArrayList.append(byteArray);
    forwardMutex.unlock();
}

void CommunicationBase::uploadServerMsgSlot(const QByteArray& byteArray)
{
    uploadMutex.lock();
    uploadByteArrayList.append(byteArray);
    uploadMutex.unlock();
}

void CommunicationBase::restart()
{
    close();
    open();
}

CommunicationSerialPort::CommunicationSerialPort(const QString &name,
                                                 QSerialPort::BaudRate baud,
                                                 QObject *parent)
    : CommunicationBase(parent)
{
    portName =name;
    m_baud =baud;

    m_serialPort =NULL;
}

CommunicationSerialPort::~CommunicationSerialPort()
{
    close();
}

bool CommunicationSerialPort::open()
{
    bool result = true;

    m_serialPort = new QSerialPort(portName);
    m_serialPort->setBaudRate(m_baud);
    m_serialPort->setFlowControl(QSerialPort::NoFlowControl);//FLOW_OFF//
    m_serialPort->setParity(QSerialPort::EvenParity);
    m_serialPort->setDataBits(QSerialPort::Data8);
    m_serialPort->setStopBits(QSerialPort::OneStop);

    if(!m_serialPort->isOpen()){
        result = m_serialPort->open(QIODevice::ReadWrite);
        m_serialPort->setTextModeEnabled(false);
    }
    return result;
}

QSerialPort *CommunicationSerialPort::getSerialPort(){
    return m_serialPort;
}
void CommunicationSerialPort::close()
{
    if(m_serialPort !=NULL){
        if(m_serialPort->isOpen()){
            m_serialPort->close();
        }

        delete m_serialPort;
        m_serialPort =NULL;
    }
}

bool CommunicationSerialPort::send(const QByteArray& byteArray)
{
    m_serialPort->write(byteArray);
    return true;
}

QByteArray CommunicationSerialPort::readAll(){
   QByteArray data = m_serialPort->readAll();
   return data;
}
void CommunicationSerialPort::modify(const QString &name, QSerialPort::BaudRate baud)
{
    portName =name;
    m_baud =baud;
}


CommunicationTcpSocket::CommunicationTcpSocket(const QString &hostIpAddress,
                                 quint16 port,
                                 QObject *parent)
    : CommunicationBase(parent)
{
    m_tcpSocket = NULL;

    peekAddress =QHostAddress(hostIpAddress);
    peekPort =port;
}

CommunicationTcpSocket::~CommunicationTcpSocket()
{
    close();
}

bool CommunicationTcpSocket::open()
{
    QDEBUG(objectName());

    if(m_tcpSocket ==NULL){
        m_tcpSocket = new QTcpSocket();
        m_tcpSocket->bind(QHostAddress::Any);
    }
    m_tcpSocket->connectToHost(peekAddress, peekPort);
    m_tcpSocket->waitForConnected();

    connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(received()));
    connect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));

    m_tcpSocket->write(objectName().toLocal8Bit());
    m_tcpSocket->flush();

    return m_tcpSocket->isValid();
}

void CommunicationTcpSocket::close()
{
    if(m_tcpSocket !=NULL){
        disconnect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(received()));
        disconnect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
        m_tcpSocket->disconnectFromHost();

        delete m_tcpSocket;
        m_tcpSocket = NULL;
    }
}

bool CommunicationTcpSocket::send(const QByteArray& byteArray)
{
    m_tcpSocket->write(byteArray);
}

void CommunicationTcpSocket::modify(const QString &hostIpAddress, quint16 port)
{
    peekAddress =QHostAddress(hostIpAddress);
    peekPort =port;
}

void CommunicationTcpSocket::received()
{
    QByteArray byteArray =m_tcpSocket->readAll();
    QDEBUG(objectName() <<byteArray);

    rcvByteArray.append(byteArray);
}

void CommunicationTcpSocket::disconnected()
{
    restart();
}

CommunicationUdpSocket::CommunicationUdpSocket(const QString &hostIpAddress,
                                 quint16 port,
                                 QObject *parent)
    : CommunicationBase(parent)
{
    m_udpSocket = NULL;

    peekAddress =QHostAddress(hostIpAddress);
    peekPort =port;
}

CommunicationUdpSocket::~CommunicationUdpSocket()
{
    close();
}

bool CommunicationUdpSocket::open()
{
    if(m_udpSocket ==NULL){
        m_udpSocket = new QUdpSocket();
        m_udpSocket->bind(QHostAddress::Any);
    }
    return true;
}

void CommunicationUdpSocket::close()
{
    if(m_udpSocket !=NULL){
        delete m_udpSocket;
        m_udpSocket = NULL;
    }
}

bool CommunicationUdpSocket::send(const QByteArray&)
{

}

void CommunicationUdpSocket::modify(const QString &hostIpAddress, quint16 port)
{
    peekAddress =QHostAddress(hostIpAddress);
    peekPort =port;
}
