#include "sendsystem.h"

SendSystem::SendSystem(QObject *parent) : QObject(parent)
{
    isSendStopped = false; 
}

void SendSystem::initialize(DataParser *dataParser,QMutex *globalMutex)
{
    this->dataParser = dataParser;
    connect(this,&SendSystem::sigSendXMLmessage,dataParser->ClientAnswer(),&ClientAnswerParser::message,Qt::AutoConnection);
    connect(this,&SendSystem::sigSendNotify,dataParser->ClientAnswer(),&ClientAnswerParser::notify,Qt::DirectConnection); //потому что возвращает значение
    connect(this,&SendSystem::sigSendVersion,dataParser->ClientAnswer(),&ClientAnswerParser::currentVersion,Qt::AutoConnection);

    qDebug() << "SendSystem thread: " << QThread::currentThreadId();
    mutex = globalMutex;
}

void SendSystem::setClient(Client *client,QTcpSocket *socket)
{
    this->socket = socket;
    this->type = client->getClientType();
    this->client = client;
    isSendStopped = false;
}

void SendSystem::sendNotify(QString notify)
{
    qDebug() << "SendNotify thread: " << QThread::currentThreadId();
    auto answer = emit sigSendNotify(notify);
    sendXmlAnswer(answer);
}

void SendSystem::sendFileBlock(QString path)
{
    QFile file(path);
    QFileInfo fileInfo(file);

    if(isSendStopped)
    {   //Поведение на случай отключения клиента
        file.close();
        Logger::instance().log("UNLOCK STOP MUTEX : " + client->getLogin(),LogLevel::ERROR);
        return;
    }

    QDataStream stream(socket);
    stream.setVersion(QDataStream::Qt_DefaultCompiledVersion);

    fileSize = file.size();

    if (fileSize == 0)
    {
        Logger::instance().log("Client: " + client->getLogin() +  " WARNING! Zero size " + fileInfo.fileName(),LogLevel::ERROR);
        Logger::instance().log(path,LogLevel::ERROR);
        return;
    }

    stream << PacketType::TYPE_FILE; //Отправляем тип блока
    stream << path << fileSize;

    if(file.open(QFile::ReadOnly))
    {
        while(!file.atEnd())
        {
            QByteArray data = file.read(sendFileBlockSize);
            stream << data;
            //socket->waitForBytesWritten(10);

            if(socket->state() == QAbstractSocket::UnconnectedState) break;
            countSend++;
        }

        //emit sigSendToLogger(Tools::getTime() + " send file " + fileInfo.fileName());
    }

    file.close();
    countSend = 0;
}

void SendSystem::sendFileBlockByteArray(QByteArray array, PacketType packetType)
{
    if(client->getClientType() == TypeClientAutorization::TYPE_QT_CLIENT ||
           client->getClientType() == TypeClientAutorization::TYPE_GUI)
    {
        QDataStream stream(socket);
        stream.setVersion(QDataStream::Qt_DefaultCompiledVersion);

        quint64 size = array.size();
        qint64 bytesSended = 0;

        if (size == 0)
        {
           Logger::instance().log(" WARNING! Zero size ",LogLevel::ERROR);
                    return;
         }

         stream << packetType; //Отправляем тип блока
         stream << size;

         while (size > 0)
         {
             QByteArray chunk = array.mid(bytesSended,sendFileBlockSize);
             stream << chunk;

             bytesSended += chunk.length();
             size -= bytesSended;
         }
    }
    else
    {
         sendPacketType(packetType);
         quint64 size = array.size();
         qint64 bytesSended = 0;

         if (size == 0)
         {
            Logger::instance().log(" WARNING! Zero size ",LogLevel::ERROR);
                     return;
         }

         QByteArray message;
         message.append(reinterpret_cast<char*>(&size), sizeof(int));
         socket->write(message);

         while (size > 0)
         {
             QByteArray chunk = array.mid(bytesSended,sendFileBlockSize);
             quint64 bytesSended = socket->write(chunk);

             size -= bytesSended;
         }

    }
}

void SendSystem::sendVersion()
{
    QByteArray data = dataParser->ClientAnswer()->currentVersion();
    sendXmlAnswer(data);
}

void SendSystem::sendFileBlockWithRename(QString path, QString newName)
{
    qDebug() << "sendFileBlockWithRename thread: " << QThread::currentThreadId();

    QDataStream stream(socket);
    stream.setVersion(QDataStream::Qt_DefaultCompiledVersion);

    QFile file(Tools::createRootPath(path));
    QFileInfo fileInfo(file);
    fileSize = fileInfo.size();

    if(fileSize == 0){
        Logger::instance().log("Client: " + client->getLogin() + " WARNING! Zero size " + fileInfo.fileName(),LogLevel::ERROR);
        return;
    }

    QString pathForSend = Tools::createFolderPath(path) + "/" + staticDataFolderName + newName;

    stream << PacketType::TYPE_FILE; //Отправляем тип блока

    stream << pathForSend << fileSize;

    if(isSendStopped) {             //Поведение на случай отключения клиента

        file.close();
        return;
    }


    socket->waitForBytesWritten();

    if(file.open(QFile::ReadOnly)){
        while(!file.atEnd()){
            QByteArray data = file.read(sendFileBlockSize);
            stream << data;
            socket->waitForBytesWritten();
            countSend++;
        }

        Logger::instance().log("Send file " + fileInfo.fileName());
    }

    file.close();
    countSend = 0;
    socket->waitForBytesWritten();
    socket->waitForReadyRead(100);

    sendNotify(commandHashCompleteClient);
}

void SendSystem::sendFolderBlock(QString path)
{
    QDataStream stream(socket);
    stream.setVersion(QDataStream::Qt_DefaultCompiledVersion);

    stream << PacketType::TYPE_FOLDER;
    stream << path;
}

void SendSystem::sendDeleteBlock(QString path)
{
    QDataStream stream(socket);
    stream.setVersion(QDataStream::Qt_DefaultCompiledVersion);

    stream << PacketType::TYPE_DELETE;
    stream << path;
    qDebug() << "DELETE: " + path;
    socket->waitForReadyRead(10);
}

void SendSystem::sendPacketType(PacketType packetType)
{
    Logger::instance().log(" SEND TO: " + client->getLogin() + " " + enumToString(packetType), LogLevel::DEBUG);
    if (client->getClientType() == TypeClientAutorization::TYPE_QT_CLIENT ||
        client->getClientType() == TypeClientAutorization::TYPE_GUI)
    {

        QDataStream stream(socket);
        stream.setVersion(QDataStream::Qt_DefaultCompiledVersion);
        stream << packetType;
        socket->waitForReadyRead(100);
    }
    else
    {
        QByteArray message;
        int type = (int)packetType;
        message.append(reinterpret_cast<char*>(&type), sizeof(int));
        socket->write(message);
    }

}

void SendSystem::sendHello()
{
    socket->write(SERVER_HELLO);
}

void SendSystem::sendXmlAnswer(QByteArray array, PacketType packetType)
{
    qDebug() << "SendSystemThread: " << QThread::currentThreadId();
    Logger::instance().log("SEND TO: "+ client->getLogin() + " " + enumToString(packetType) + "\n Text: " +
                           QString(array),LogLevel::DEBUG);

    if (client->getClientType() == TypeClientAutorization::TYPE_QT_CLIENT ||
        client->getClientType() == TypeClientAutorization::TYPE_GUI)
    {
        QDataStream stream(socket);
        stream.setVersion(QDataStream::Qt_DefaultCompiledVersion);

        stream << packetType;
        stream << array;
        socket->waitForBytesWritten();
    }
    else
    {
        sendPacketType(packetType);
        QByteArray message;
        int size = array.length();
        message.append(reinterpret_cast<char*>(&size), sizeof(int));
        socket->write(message);
        socket->write(array);
    }
}

void SendSystem::sendNeedUpdate(bool flag,quint64 size,quint64 fileCount,quint64 deleteCount)
{
    QDataStream stream(socket);
    stream.setVersion(QDataStream::Qt_DefaultCompiledVersion);
    stream << PacketType::TYPE_NEEDUPDATE;
    stream << flag;
    stream << size;
    stream << fileCount;
    stream << deleteCount;
}

void SendSystem::updateFiles(QList<FileData> fileSendList, QList<FileData> deleteList){

    QMutexLocker locker(mutex);
    QListIterator<FileData> clientIterator(deleteList);

    while(clientIterator.hasNext())
    {
        FileData data = clientIterator.next();

        sendDeleteBlock(data.path);
        if(getIsSendStopped())
        {
            return;
        }
    }

    QListIterator<FileData> serverIterator(fileSendList);

    while(serverIterator.hasNext())
    {
        FileData data = serverIterator.next();

        if (data.hash == "FOLDER")
        {
            sendFolderBlock(data.path);
            socket->waitForBytesWritten();
        }
        else
        {
            sendFileBlock(data.path);
            socket->waitForBytesWritten();
        }

        if(isSendStopped)
        {
            return;
        }
    }
    sendPacketType(PacketType::UPDATE_FILES_COMPLETE);
}


void SendSystem::socketClose()
{
    socket->close();
}

bool SendSystem::socketFlush()      //TODO: проверить использование
{
    return socket->flush();
}

void SendSystem::sendStop()
{
    isSendStopped = true;
}

void SendSystem::sendDocs(QString docsPath)
{
    sendFileBlock(docsPath);
}

bool SendSystem::getIsSendStopped() const
{
    return isSendStopped;
}

SendSystem::~SendSystem()
{

}
