/***************************************************************************
 *   Copyright (C) 2021 by Santiago González                               *
 *                                                                         *
 ***( see copyright.txt file at root folder )*******************************/

#include <QPainter>
#include <QtNetwork>
#include <QTcpSocket>
#include <QMenu>

#include "tcpmodule.h"
#include "simulator.h"
#include "iopin.h"


TcpModule::TcpModule( QString name )
         : eElement( name )
         , TransModule( name )
{
    m_debug = false;

    Simulator::self()->addToUpdateList( this );

}
TcpModule::~TcpModule()
{
    TcpModule::initialize();
}

void TcpModule::initialize()
{
    for( tcpConnection_t* conn : m_tcpConnections )
    {
        conn->socket->disconnectFromHost();
        conn->socket->waitForDisconnected( 1000 );
        conn->socket->deleteLater();
        delete conn;
    }
    m_tcpConnections.clear();
}

void TcpModule::updateStep()
{
    for( tcpConnection_t* conn : m_tcpConnections )
    {
        switch( conn->action ) {
            case tcpNone: break;
            case tcpConnect:
            {
                QTcpSocket* tcpSocket = conn->socket;
                if( tcpSocket->state() == QAbstractSocket::UnconnectedState )
                {
                    if( m_debug ) qDebug() << "TcpModule - Connecting Socket"<<conn->number<<"to"<<conn->host<< conn->port;
                    tcpSocket->connectToHost( conn->host, conn->port );
                }
                else if( m_debug ) qDebug() << "TcpModule - Error Connecting Socket"<<conn->number<<"to"<<conn->host<<conn->port
                                            <<"\n              State = "<<tcpSocket->state();
            }break;
            case tcpClose:
            {
                QTcpSocket* tcpSocket = conn->socket;
                if( !tcpSocket ) return;

                if( tcpSocket->state() == QAbstractSocket::ConnectedState )
                {
                    if( m_debug ) qDebug() << "TcpModule - Disconnecting Socket"<<conn->number<<"from"<<conn->host<< conn->port;
                    tcpSocket->disconnectFromHost();
                }
                else if( m_debug )
                    qDebug() << "TcpModule - Error Disconnecting Socket"<<conn->number<<"from"<<conn->host<< conn->port
                             <<"\n              State = "<<tcpSocket->state();
            }break;
        }
        conn->action = tcpNone;
    }
}

void TcpModule::closeSocket( int link )
{
    if( !m_tcpConnections.contains( link ) ) return;
    tcpConnection_t* conn = m_tcpConnections.value( link );
    conn->action = tcpClose;
}

void TcpModule::sendMsg( QString msg, int link )
{
    if( !m_tcpConnections.contains( link ) ) return;
    tcpConnection_t* conn = m_tcpConnections.value( link );
    QTcpSocket* tcpSocket = conn->socket;

    if( tcpSocket->state() == QAbstractSocket::ConnectedState )
    {
        QByteArray toSend = msg.toUtf8();
        if( m_debug ) qDebug() << "TcpModule - Sending data to Socket:"<<conn->number<<"\n"<<toSend;
        int bytes = tcpSocket->write( toSend+"\n\0" );
        if( m_debug ) qDebug() << "TcpModule -"<<bytes<<"Bytes Written to Socket"<<conn->number;
    }
    else if( m_debug ) qDebug() << "TcpModule - Error Sending data: Socket"<<conn->number<<"not connected\n";
}

void TcpModule::connectTo( int link, QString host, int port )
{
    if( m_tcpConnections.contains( link ) )
    {
        tcpConnection_t* conn = m_tcpConnections.value( link );
        conn->action = tcpConnect;
    }else{
        QTcpSocket* tcpSocket = new QTcpSocket();
        tcpConnection_t* conn = new tcpConnection_t;

        conn->socket = tcpSocket;
        conn->host   = host;
        conn->port   = port;
        conn->number = link;
        conn->action = tcpConnect;

        m_tcpConnections[link] = conn;

        QObject::connect( tcpSocket, &QTcpSocket::connected   , [=](){ tcpConnected(link); });
        QObject::connect( tcpSocket, &QTcpSocket::disconnected, [=](){ tcpDisconnected(link); });
        QObject::connect( tcpSocket, &QTcpSocket::readyRead   , [=](){ tcpReadyRead(link); });
    }
}

// Replies from TCP --------------------------------------------------------------------------

void TcpModule::tcpConnected( int link )
{
    if( !m_debug ) return;
    tcpConnection_t* conn = m_tcpConnections.value( link );
    qDebug() << "TcpModule - Socket"<<link<<"Connected to"<<conn->host<<conn->port;
}
void TcpModule::tcpDisconnected( int link )
{
    if( !m_debug ) return;
    tcpConnection_t* conn = m_tcpConnections.value( link );
    qDebug() << "TcpModule - Socket"<<link<<"Disconnected from"<<conn->host<<conn->port;
}

void TcpModule::tcpReadyRead( int link )
{
    tcpConnection_t* conn = m_tcpConnections.value( link );

    QString msg = conn->socket->readAll();
    received( msg, link ) ;

    if( !m_debug ) return;
    qDebug() << "TcpModule - Socket"<<link
             <<"Received from Host:" << conn->host <<"Port:"<< conn->port
             <<"\n"<< msg;
}

