#include "threadsendpro.h"
#include "QFileInfo"
#include <QHostAddress>
#include <QIODevice>
#include <QDir>
#include <QJsonArray>
#include <QDirIterator>
#include <QMessageBox>
#include <LoUIClass/x_uimsgboxok.h>
#include <QCoreApplication>
ThreadSendPro::ThreadSendPro(QString strProPathAndName,QString strIp,int iPort)
{
    m_strProName=strProPathAndName;
    m_strIp=strIp;
    m_iPort=iPort;


}
ThreadSendPro::~ThreadSendPro()
{

}
void ThreadSendPro::run()
{
    // 避免界面冻结
    QCoreApplication::processEvents();
    //如果关闭窗口，线程退出
    if(bSendCloseFlag==true)
        bSendCloseFlag=false;
    else {
        return;
    }
    sentAllBytes =  0;
    loadBytes = LOADBYTES;
    file = Q_NULLPTR;
    send = new QTcpSocket();

    connect(send, SIGNAL(connected()), this, SLOT(connect_sucessful()));
    /* socket出错 -> 错误处理 */
    connect(send, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(show_error(QAbstractSocket::SocketError)));
    //发起连接设备
    send->connectToHost(QHostAddress(m_strIp),m_iPort);
//    emit sigSetLableText("connectToHost");
    if(bSendCloseFlag)
        return;
    if(!send->waitForConnected(10000))              //等待连接返回
    {
        emit sigSetLableText("connect timeout");
        //emit sigSetLableText("5");
        return ;
    }
    sentAllBytes = 0;
    //1.获取需要发送的文件列表,并获取到总的大小
    m_NeedSendFileList=GetNeedFileList();
    //2.等待应答
    if(bSendCloseFlag)
        return;
    if(send->waitForReadyRead(5000))
    {
        if(bSendCloseFlag)
            return;
        QByteArray readBuf=send->read(send->bytesAvailable());
        QJsonParseError parseJsonErr;
        QJsonDocument document = QJsonDocument::fromJson(readBuf,&parseJsonErr);
        if(!(parseJsonErr.error == QJsonParseError::NoError))
        {
            //qDebug()<<tr("解析json文件错误！");
            //return;
        }

        QJsonObject jsonObject = document.object();
        QString strType=jsonObject["_type"].toString();
        if(strType=="consult")
        {

            m_NeedSendFileList.clear();
            QJsonArray bb=jsonObject["idList"].toArray();
            for(int i=0;i<bb.count();i++)
            {
                m_NeedSendFileList.append(bb.at(i).toString());
            }
            m_bGetConsultAckFlag=true;
        }
     }
    else {

    }

    qint64 iAllSize=GetNeedFileAllSize(strCurSendDir,m_NeedSendFileList);
    //3.发送项目文件开始命令
    QString m_strfileName=FindLocalFileFromPath(strCurSendDir,"program");
    QFileInfo info(m_strfileName);
    iAllSize+=info.size();
    if(bSendCloseFlag)
        return;
    sendProJsonStart(iAllSize);
    //QStringList strFileList;
    //start_transfer_(strCurSendDir,&strFileList);
    QString strtempAbsolutePath=info.absolutePath();
    QString strTempRelativePath=strtempAbsolutePath.right(strtempAbsolutePath.length()-strCurSendDir.length());
    if(bSendCloseFlag)
        return;
    SendFileHead(m_strfileName,strTempRelativePath);
    if(bSendCloseFlag)
        return;
    SendFileData(m_strfileName);
    if(bSendCloseFlag)
        return;
    SendFileEnd(m_strfileName);

    //4.发送协商列表应答里的文件
    if(bSendCloseFlag)
        return;
    start_transfer_byAckConsult(strCurSendDir,m_NeedSendFileList);
    //5.发送结束
    if(bSendCloseFlag)
        return;
    sendProJsonFinished();
    if(bSendCloseFlag)
        return;
    if(send->waitForReadyRead(5000))
    {
        QByteArray readBuf=send->read(send->bytesAvailable());
        QJsonParseError parseJsonErr;
        QJsonDocument document = QJsonDocument::fromJson(readBuf,&parseJsonErr);
        QJsonObject jsonObject = document.object();
        QString strType=jsonObject["_type"].toString();
        if(strType=="AckSuccess")
        {
            //readAckSempahore.release();
        }
    }
    else {

    }

    if(send!=nullptr)
    {

        send->close();
        bSendCloseFlag=true;
        delete send;
    }
//    emit sigSetLableText("send finished");
    qDebug()<<tr("get readAckSempahore");
}


int ThreadSendPro::connect_sucessful(){
   // emit sigSetLableText(QString("Connection Established!"));
    return 0;

}

QStringList ThreadSendPro::GetNeedFileList()
{
    emit sigSetProgressValue(0); // 进度条归零
    QFileInfo fileInfo(m_strProName);
    QStringList strFileList;
    strCurSendDir=fileInfo.absolutePath();
    dirFileSize(strCurSendDir,&strFileList);
    //发送节目列表协商
    QJsonObject jsonXieShangObj;
    QJsonArray aa;
    for(int i=0;i<strFileList.count();i++)
    {
        QString strtemp=strFileList.at(i);
        int iOffset=strtemp.indexOf(".");
        strtemp=strtemp.left(iOffset);
        aa.append(strtemp);
    }
    //aa.fromStringList(strFileList);
    jsonXieShangObj.insert("_type", "consult");
    jsonXieShangObj.insert("proName", fileInfo.fileName());
    jsonXieShangObj.insert("idList",aa);
    jsonXieShangObj.insert("zVer","xixun1");
    QJsonDocument doc1;
    doc1.setObject(jsonXieShangObj);
    QByteArray sendArray1 = doc1.toJson(QJsonDocument::Compact);
    send->write(sendArray1);
    SynchronousSocketWrite();
    return strFileList;


}
qint64 ThreadSendPro::GetNeedFileAllSize(const QString &path,QStringList list)
{
    QDir dir(path);
    qint64 size = 0;
    //dir.entryInfoList(QDir::Files)返回文件信息
    for (int m=0;m<list.count();m++)
    {
        QString strtempFileName=list.at(m);
        if(strtempFileName!="program")
        {
            QString strFileAllPathName=FindLocalFileFromPath(path,strtempFileName);
            QFileInfo fileInfo(strFileAllPathName);
            size += fileInfo.size();

        }
    }

    return size;
}



void ThreadSendPro::sendProJsonStart(qint64 iAllSize)
{
    QJsonObject jsonPro;
    jsonPro.insert("_type", "proStart");
    QFileInfo fileInfo(m_strProName);
    jsonPro.insert("proName", fileInfo.fileName());
    emit sigSetProgressMax(iAllSize);

    jsonPro.insert("proSize", iAllSize);
    jsonPro.insert("zVer","xixun1");
    QJsonDocument doc;
    doc.setObject(jsonPro);
    QByteArray sendArray = doc.toJson(QJsonDocument::Compact);
    send->write(sendArray);
    SynchronousSocketWrite();

}

void ThreadSendPro::sendProJsonFinished()
{
    QJsonObject jsonPro;
    jsonPro.insert("_type", "proEnd");
    QFileInfo fileInfo(m_strProName);
    jsonPro.insert("proName", fileInfo.fileName());
    jsonPro.insert("zVer","xixun1");
    QJsonDocument doc;
    doc.setObject(jsonPro);
    QByteArray sendArray = doc.toJson(QJsonDocument::Compact);
    send->write(sendArray);
 //   send->flush();
    SynchronousSocketWrite();

}
qint64 ThreadSendPro::dirFileSize(const QString &path,QStringList *list)
{
    QDir dir(path);
    qint64 size = 0;
    //dir.entryInfoList(QDir::Files)返回文件信息
    foreach(QFileInfo fileInfo, dir.entryInfoList(QDir::Files))
    {
        QString strOnlyFileName=fileInfo.fileName();
        int iAlreadExistFlag=0;
        for(int i=0;i<list->count();i++)
        {
            if(list->at(i)==strOnlyFileName)
            {
                iAlreadExistFlag=1;
            }
        }
        if(iAlreadExistFlag==0)//不重复的文件才计入发送的总大小
        {
            list->append(strOnlyFileName);
            //计算文件大小
            size += fileInfo.size();
        }
    }
    //dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot)返回所有子目录，并进行过滤
    foreach(QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
    {
        //若存在子目录，则递归调用dirFileSize()函数
        size += dirFileSize(path + QDir::separator() + subDir,list);
    }
    return size;
}
void ThreadSendPro::start_transfer_byAckConsult(const QString &path,QStringList list)
{
    QDir dir(path);
    //dir.entryInfoList(QDir::Files)返回文件信息
    for (int m=0;m<list.count();m++)
    {
        if(bSendCloseFlag)
            return;
        QString strtempFileName=list.at(m);
        if(strtempFileName!="program")
        {

            QString m_strfileName=FindLocalFileFromPath(path,strtempFileName);

            QFileInfo info(m_strfileName);
            if(info.exists())
            {
                QString strtempAbsolutePath=info.absolutePath();
                QString strTempRelativePath=strtempAbsolutePath.right(strtempAbsolutePath.length()-strCurSendDir.length());
                if(SendFileHead(m_strfileName,strTempRelativePath)==false)
                    return;
                if(SendFileData(m_strfileName)==false)
                    return;
                if(SendFileEnd(m_strfileName)==false)
                    return;;
            }

        }


    }
}

QString ThreadSendPro::FindLocalFileFromPath(const QString &strFilePath, const QString filename)
{
    QStringList m_Filelist;//找到的文件存入此队列
    if (strFilePath.isEmpty() || filename.isEmpty())
    {
        return "";
    }

    QDir dir;
    QStringList filters;

    filters << filename;//过滤条件，可以添加多个选项，可以匹配文件后缀等。我这里只是找指定文件
    dir.setPath(strFilePath);
    dir.setNameFilters(filters);//添加过滤器
    //QDirIterator 此类可以很容易的返回指定目录的所有文件及文件夹，可以再递归遍历，也可以自动查找指定的文件
    QDirIterator iter(dir,QDirIterator::Subdirectories);

    while (iter.hasNext())
    {
        iter.next();
        QFileInfo info=iter.fileInfo();
        if (info.isFile())
        {
            return info.absoluteFilePath();
        }
    }
    return "";

}

bool ThreadSendPro::SendFileHead(QString fileName,QString strRelativePath)
{
    QFileInfo fileinfo;
    fileinfo = QFileInfo(fileName);
   // name:"xxxx",size:23434545,path:"/"
    QJsonObject jsonFileInfo;
    jsonFileInfo.insert("_type", "fileStart");
    QString strOnlyFileName=fileinfo.fileName();
    QString strExcName=fileinfo.suffix();
    if(strExcName.isEmpty())
        jsonFileInfo.insert("id", strOnlyFileName.left(strOnlyFileName.length()-strExcName.length()));
    else
        jsonFileInfo.insert("id", strOnlyFileName.left(strOnlyFileName.length()-strExcName.length()-1));
    jsonFileInfo.insert("size", fileinfo.size());
    //jsonFileInfo.insert("relative_path", strRelativePath);
    jsonFileInfo.insert("relative_path", "");
     jsonFileInfo.insert("zVer","xixun1");
    QJsonDocument doc;
    doc.setObject(jsonFileInfo);
    QByteArray sendArray = doc.toJson(QJsonDocument::Compact);


    QJsonObject jsonFileInfo1;
    jsonFileInfo1.insert("_type", "jsonlen");
    jsonFileInfo1.insert("jsonlen", sendArray.length());
    QJsonDocument doc1;
    doc1.setObject(jsonFileInfo1);
    QByteArray sendArray1 = doc1.toJson(QJsonDocument::Compact);
    if(bSendCloseFlag)
        return false;
    send->write(sendArray);
    SynchronousSocketWrite();
    return true;

}
bool ThreadSendPro::SendFileEnd(QString fileName)
{
    QFileInfo fileinfo;
    fileinfo = QFileInfo(fileName);
   // name:"xxxx",size:23434545,path:"/"
    QJsonObject jsonFileInfo;
    jsonFileInfo.insert("_type", "fileEnd");
    QString strOnlyFileName=fileinfo.fileName();
    QString strExcName=fileinfo.suffix();
    if(strExcName.isEmpty())
        jsonFileInfo.insert("id", strOnlyFileName.left(strOnlyFileName.length()-strExcName.length()));
    else {
        jsonFileInfo.insert("id", strOnlyFileName.left(strOnlyFileName.length()-strExcName.length()-1));

    }
    jsonFileInfo.insert("zVer","xixun1");
    QJsonDocument doc;
    doc.setObject(jsonFileInfo);
    QByteArray sendArray = doc.toJson(QJsonDocument::Compact);
    if(bSendCloseFlag)
        return false;
    send->write(sendArray);
    SynchronousSocketWrite();
    return true;

}
bool ThreadSendPro::SendFileData(QString fileName)
{
    qint64 llSendBytes=0;

    file = new QFile(fileName);
//    QFileInfo ff(fileName);
//    QString sss=ff.fileName().left(ff.fileName().length()-ff.suffix().length()-1);
//    QFile *fileNew = new QFile(ff.absolutePath()+"/"+sss+"copy."+ff.suffix());
//    if(!fileNew->open(QFile::WriteOnly)) // 打开失败
//    {


//    }
    if(!file->open(QFile::ReadOnly))
    {
        emit sigSetLableText(tr("open file failed"));
        //emit sigSetLableText(fileName);
        //qDebug() << "*** start_transfer(): File-Open-Error";
        return false;
    }
    qint64 llfileSize = file->size();
    qint64 llrestBytes=llfileSize;
    while (llSendBytes<llfileSize) {

        QByteArray buf = file->read(qMin(loadBytes, llrestBytes));
        //QJsonValue JsonData=QJsonDocument::fromJson(buf).toVariant().toJsonValue();
        //QJsonObject json_object2 = QJsonDocument::fromJson(buf).object();
        /* 发送 */
//        QString strData;
//        strData.prepend(buf);
//        QFileInfo fileinfo;
//        fileinfo = QFileInfo(fileName);
//        QJsonObject jsonFileInfo;
//        jsonFileInfo.insert("_type", "fileData");
//        jsonFileInfo.insert("name", fileinfo.fileName());
//        jsonFileInfo.insert("data", buf);
//        jsonFileInfo.insert("zVer","xixun1");
//         QJsonDocument doc;
//        doc.setObject(jsonFileInfo);
//        QByteArray sendArray = doc.toJson(QJsonDocument::Compact);

        if(bSendCloseFlag)
        {
            file->close();
            return false;
        }
        qint64 iSendResultLength=send->write(buf);
 //       send->waitForBytesWritten();
//        fileNew->write(buf);
        llSendBytes+=iSendResultLength ;

        llrestBytes=llfileSize-llSendBytes;
        sentAllBytes += iSendResultLength;
        if(sentAllBytes!=0)
             emit sigSetProgressValue(sentAllBytes);
        SynchronousSocketWrite();
     }
    file->close();
//    fileNew->close();
    return true;
}


/*--- 出错处理 ---*/
void ThreadSendPro::show_error(QAbstractSocket::SocketError error)
{

    //qDebug() << "*** Socket Error";
    QString strTip=QString::number(error);
    if(error!=6)
    {
        //send->close();
        bSendCloseFlag=true;
       // emit sigSetLableText(tr("send failed")+strTip);
        emit sigSetLableText(strTip);
         //emit sigSetProgressValue(0); // 进度条归零
         m_reSendCount=0;
    }

//    emit sigSetLableText("连接失败");
}


bool ThreadSendPro::SynchronousSocketWrite()
{
    if(bSendCloseFlag)
        return false;
    if(!send->waitForBytesWritten(3000))
    {
        qDebug()<<"socket write timeout!";
        return false;
    }
    //readAckSempahore.acquire();
    return true;
}
void ThreadSendPro::recevie_file()
{
    //QDataStream in(receive);
    //in.setVersion(DATA_STREAM_VERSION);
    //QFile *tempFile=nullptr;
    //receive->bytesAvailable();
   // if(send->waitForReadyRead())
    {
        //QByteArray readBuf=send->readAll();
        QByteArray readBuf=send->read(send->bytesAvailable());
        QJsonParseError parseJsonErr;
        QJsonDocument document = QJsonDocument::fromJson(readBuf,&parseJsonErr);
        if(!(parseJsonErr.error == QJsonParseError::NoError))
        {
            //qDebug()<<tr("解析json文件错误！");
            //return;
        }
        QJsonObject jsonObject = document.object();
        QString strType=jsonObject["_type"].toString();
        if(strType=="AckSuccess")
        {
            //释放信号
            readAckSempahore.release();

        }
        else if(strType=="consult"){
            m_NeedSendFileList.clear();

            QJsonArray bb=jsonObject["idList"].toArray();
            for(int i=0;i<bb.count();i++)
                m_NeedSendFileList.append(bb.at(i).toString());
            m_bGetConsultAckFlag=true;
            readAckSempahore.release();
        }
    }
}
