#include "exportData.h"
#include "QtCore\qfile.h"
#include "QtCore\qtextstream.h"
#include <QTimer>
#include <QFileInfoList>
#include <QDir>
#include <QFileInfo>
#include <QIODevice>
#include <QTextStream>
#include <QProcess>
#include <string>
//#include <ftpManager.h>
#include <wininet.h>
#include <Windows.h>
#include <sys/stat.h>
#include <io.h>
#pragma comment(lib, "Wininet.lib")

Cigarette* cg;
extern SyncQueue<_XMLExportDataInfo>* export_XMLData_Info_queue;
extern ConfPath g_conf_path;
extern bool flag;
extern SysConf g_sys_conf;  //系统配置参数

ExportDataThread::ExportDataThread(QObject* parent) : QThread(parent)
{
    /* Move to init()
    //第一步执行
    cg->read_conf(g_conf_path);
    for (int index = 0; index < NumberOfSupportedCameras; index++)
    {
        XMLError error;
        pDocument[index] = new tinyxml2::XMLDocument();
        QString xmlPath = QString(EXPORTDATA_FILE).arg(index);
        QString filePath = g_conf_path.config_path + "/" + xmlPath;

        error = pDocument[index]->LoadFile(filePath.toLocal8Bit().constData());
        if (error != XML_SUCCESS) {
            XMLDeclaration* declaration = pDocument[index]->NewDeclaration();
            pDocument[index]->InsertFirstChild(declaration);
        }
    }
    init(ip,port,username,userpwd);
    cout << "11111111111111";
    hint = InternetOpen(0, INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
    if (hint == NULL) {
        return;
    }
    if (!ConnectFtp(&ip, &port, &username, &userpwd))
        qDebug() << "First connect FTP failed because " << GetLastError();
    */
    readyToSendZip = false;
    listToZip.clear();
    tmpListToZip.clear();
    lastTimeStamp.clear();
    zipTimeStamp.clear();
    hftp = NULL;
    hint = NULL;
    
}

void ExportDataThread::init(string ip_, int port_, string username_, string userpwd_)
{
    //初始化FTP连接信息
    ip = ip_;
    port = port_;
    username = username_;
    userpwd = userpwd_;
    cout << "ftp ip =" << ip << "| prot =" << port << endl;
    cout << "username =" << username << "| pwd =" << userpwd << endl;
    b_quit = false;
    flag = false;

    timer = new QTimer(this);
    timer->setTimerType(Qt::PreciseTimer);
    timer->setSingleShot(true);

    //第一步执行
    cg->read_conf(g_conf_path);
    for (int index = 0; index < NumberOfSupportedCameras; index++)
    {
        XMLError error;
        pDocument[index] = new tinyxml2::XMLDocument();
        QString xmlPath = QString(EXPORTDATA_FILE).arg(index);
        QString filePath = g_conf_path.config_path + "/" + xmlPath;

        error = pDocument[index]->LoadFile(filePath.toLocal8Bit().constData());
        if (error != XML_SUCCESS) {
            XMLDeclaration* declaration = pDocument[index]->NewDeclaration();
            pDocument[index]->InsertFirstChild(declaration);
        }
    }
    
    //init(ip, port, username, userpwd);
    hint = InternetOpen(0, INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
    if (hint == NULL) {
        return;
    }
    if (!ConnectFtp(&ip, &port, &username, &userpwd))
        qDebug() << "First connect FTP failed because " << GetLastError();
    
}

void ExportDataThread::start_work()
{
    //start(HighestPriority);///优先级
    //start(HighPriority);
    start();
}

void ExportDataThread::stop()
{
    b_quit = true;
    _XMLExportDataInfo data;
    export_XMLData_Info_queue->put(data);
    //InternetCloseHandle(hftp);
    //InternetCloseHandle(hint);
}

bool ExportDataThread::FtpConnectionTest () {
    int retryCount = 3;
    if ((hftp == NULL) || (!FtpSetCurrentDirectoryA(hftp, "/"))) {
        while (!ConnectFtp(&ip, &port, &username, &userpwd)) {
            if (retryCount-- == 0) {
                break;
            }
            QTime delayTime = QTime::currentTime().addMSecs(100); //100ms
            while (QTime::currentTime() < delayTime) {
                QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
            }
        }
    }

    return (retryCount > 0);
}

bool ExportDataThread::ConnectFtp(string *ip_, int *port_, string *username_, string *userpwd_) {
    
    //// FTP地址
    //string ftpServer = "192.168.1.180";
    ///* 端口号，一般为21 */
    //int port = 666;
    ///* 用户名 */
    //string userName = "FTP2";
    ///* 密码 */
    //string pwd = "123";

    if (hftp != NULL) {
        InternetCloseHandle(hftp);
        hftp = NULL;
    }

    // 创建ftp连接
    // hftp = InternetConnectA(hint, ftpServer.c_str(), port, userName.c_str(), pwd.c_str(), INTERNET_SERVICE_FTP, 0, 0);  
    hftp = InternetConnectA(hint, ip_->c_str(), *port_, username_->c_str(), userpwd_->c_str(), INTERNET_SERVICE_FTP, 0, 0);
    if (hftp == NULL) {
        qDebug() << "ftp connect failed because " << GetLastError();
        return false;
    }
    //else
    //    qDebug() << "ftp reconnect success";
    return true;

}

//bool _ExportDataInfo::getAverageData(map<string, float>& averageData, int index)
//{
//    tinyxml2::XMLDocument doc;
//    //char xmlPath[256];
//    XMLError error;
//    map<string, float> data;
//    //memset(xmlPath, 0, 256);
//    QString xmlPath = QString(EXPORTDATA_FILE).arg(index);
//    //sprintf(xmlPath, EXPORTDATA_FILE, index);
//    QString filePath = g_conf_path.config_path + "/" + xmlPath;
//    error = doc.LoadFile(filePath.toLocal8Bit().constData());
//    if (error != XML_SUCCESS)
//        if (doc.LoadFile(filePath.toLocal8Bit().constData()) != 0)
//        {
//            cout << "load xml file failed" << endl;
//            return false;
//        }
//    XMLElement* root = doc.RootElement();
//    XMLElement* userNode = root->FirstChildElement("Camera");
//    data["CameraId"] = index;
//    data["IsNG"] = 0;
//    data["IsJdExist"] = 0;
//    data["Total"] = 0;
//    while (userNode != NULL)
//    {
//        if (atoi(userNode->Attribute("Id")) == index) {
//            data["IsNG"]++;
//            data["IsJdExist"]++;
//            data["Total"]++;
//            XMLElement* IsNgNode = userNode->FirstChildElement("IsNG");
//            data["IsNg"] = strcmp(IsNgNode->GetText(), "TRUE");
//            XMLElement* IsJdExistNode = userNode->FirstChildElement("IsJdExist");
//            if (strcmp(IsJdExistNode->GetText(), "TRUE") == 0)
//                data["IsJdExist"]++;
//            XMLElement* TimeCostNode = userNode->FirstChildElement("TimeCost");
//            data["TimeCost"] += stof(TimeCostNode->GetText());
//        }
//        userNode = userNode->NextSiblingElement();//下一个兄弟节点
//    }
//    if (data["Total"] == 0)
//        return false;
//    data["TimeCost"] = data["TimeCost"] / data["Total"];
//
//    averageData = data;
//
//    return true;
//}
//XML文件
//写数据到XML文件
int ExportDataThread::insertXMLNode(const char* xmlPath, _XMLExportDataInfo& data)
{
    XMLElement* root = pDocument[data.cameraId]->RootElement();

    if (root == NULL) {
        root = pDocument[data.cameraId]->NewElement("Root");
        pDocument[data.cameraId]->InsertEndChild(root);
        pDocument[data.cameraId]->SaveFile(xmlPath);
        //return 0;
    }

    /// 总统计数据
    // 总检测数量
    XMLElement* Total = pDocument[data.cameraId]->NewElement("TotalDatas");

    XMLElement* time = pDocument[data.cameraId]->NewElement("CurrentTime");
    QString currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    time->InsertEndChild(pDocument[data.cameraId]->NewText(currentTime.toStdString().c_str()));
    Total->InsertEndChild(time);

    XMLElement* TotalCheckNum = pDocument[data.cameraId]->NewElement("TotalCheckNum");
    char s[20];
    TotalCheckNum->InsertEndChild(pDocument[data.cameraId]->NewText(itoa(data.TotalCheckNum, s, 10)));
    Total->InsertEndChild(TotalCheckNum);

    // 总剔除数量
    XMLElement* TotalKickNum = pDocument[data.cameraId]->NewElement("TotalKickNum");
    TotalKickNum->InsertEndChild(pDocument[data.cameraId]->NewText(itoa(data.TotalKickNum, s, 10)));
    Total->InsertEndChild(TotalKickNum);

    root->InsertEndChild(Total);

    /// 各相机数据
    // 相机id & 总数
    XMLElement* CameraNode = pDocument[data.cameraId]->NewElement("Camera");
    CameraNode->SetAttribute("Count ", data.cameraTotal);
    CameraNode->SetAttribute("Id", data.cameraId);

    XMLElement* JudgeNum = pDocument[data.cameraId]->NewElement("JudgeNum");
    // 各相机检测数量
    XMLElement* checkNum = pDocument[data.cameraId]->NewElement("CheckNum");
    checkNum->InsertEndChild(pDocument[data.cameraId]->NewText(itoa(data.checkNum, s, 10)));
    JudgeNum->InsertEndChild(checkNum);
    // 各相机ok数量
    XMLElement* okNum = pDocument[data.cameraId]->NewElement("OkNum");
    okNum->InsertEndChild(pDocument[data.cameraId]->NewText(itoa(data.okNum, s, 10)));
    JudgeNum->InsertEndChild(okNum);
    // 各相机ng数量
    XMLElement* ngNum = pDocument[data.cameraId]->NewElement("NgNum");
    ngNum->InsertEndChild(pDocument[data.cameraId]->NewText(itoa(data.ngNum, s, 10)));
    JudgeNum->InsertEndChild(ngNum);
    // 各相机实际剔除数量（单通道剔除时为总剔除数量）
    XMLElement* kickNum = pDocument[data.cameraId]->NewElement("KickNum");
    kickNum->InsertEndChild(pDocument[data.cameraId]->NewText(itoa(data.kickNum, s, 10)));
    JudgeNum->InsertEndChild(kickNum);

    // 合格率
    XMLElement* PassRate = pDocument[data.cameraId]->NewElement("PassRate");
    std::string temp_str = std::to_string(data.PassRate * 100) + "%";
    const char* temp_char = temp_str.c_str();
    PassRate->InsertEndChild(pDocument[data.cameraId]->NewText(temp_char));
    JudgeNum->InsertEndChild(PassRate);

    // 剔除率
    XMLElement* KickRate = pDocument[data.cameraId]->NewElement("KickRate");
    temp_str = std::to_string(data.KickRate * 100) + "%";
    temp_char = temp_str.c_str();
    KickRate->InsertEndChild(pDocument[data.cameraId]->NewText(temp_char));
    JudgeNum->InsertEndChild(KickRate);

    // 各相机胶点识别个数
    XMLElement* JdNum = pDocument[data.cameraId]->NewElement("JdNum");
    JdNum->InsertEndChild(pDocument[data.cameraId]->NewText(data.jdNum.toStdString().c_str()));
    JudgeNum->InsertEndChild(JdNum);

    XMLElement* shotCounts = pDocument[data.cameraId]->NewElement("ShotCounts");
    shotCounts->InsertEndChild(pDocument[data.cameraId]->NewText(itoa(data.shotCounts, s, 10)));
    JudgeNum->InsertEndChild(shotCounts);

    CameraNode->InsertEndChild(JudgeNum);

    // 各相机采集速度
    XMLElement* speed = pDocument[data.cameraId]->NewElement("Speed");

    XMLElement* AcquisitionSpeed = pDocument[data.cameraId]->NewElement("AcquisitionSpeed");
    AcquisitionSpeed->InsertEndChild(pDocument[data.cameraId]->NewText(data.AcquisitionSpeed.toStdString().c_str()));
    speed->InsertEndChild(AcquisitionSpeed);
    // 各相机检测速度
    XMLElement* DetectSpeed = pDocument[data.cameraId]->NewElement("DetectSpeed");
    DetectSpeed->InsertEndChild(pDocument[data.cameraId]->NewText(data.DetectSpeed.toStdString().c_str()));
    speed->InsertEndChild(DetectSpeed);
    CameraNode->InsertEndChild(speed);

    root->InsertEndChild(CameraNode);

    return pDocument[data.cameraId]->SaveFile(xmlPath);
}

void ExportDataThread::run()
{
    while (!b_quit || (b_quit && (!export_XMLData_Info_queue->isEmpty() || readyToSendZip || !tmpListToZip.isEmpty()))) {
        _XMLExportDataInfo element;
        if (!export_XMLData_Info_queue->isEmpty()) {
            export_XMLData_Info_queue->take(element);

            if (element.cameraId != -1 && flag) {
                char buf[256];
                memset(buf, 0, 256);
                QString xmlPath = QString(EXPORTDATA_FILE).arg(element.cameraId);
                QString filePath = g_conf_path.config_path + "/" + xmlPath;
                sprintf(buf, filePath.toLocal8Bit().constData(), element.cameraId);
                insertXMLNode(buf, element);
                QString remotePath = "/tmp/" + xmlPath;
                ConnectServer(filePath, remotePath);
            }
        }

        if ((b_quit || (!timer->isActive() && !readyToSendZip)) && (!tmpListToZip.isEmpty())) {
            listToZip.unite(tmpListToZip);
            tmpListToZip.clear();
            zipTimeStamp.append(lastTimeStamp[0]);
            lastTimeStamp.clear();
            readyToSendZip = true;
        }

        if (readyToSendZip && !listToZip.isEmpty()) {
            QString remotePath;
            QStringList zipFilePaths;
            QStringList fileList;
            QString okStr = "1";
            QProcess process(0);
            //QDateTime now_ts = QDateTime::currentDateTime();
            QStringList argsNg;
            QStringList argsOk;

            //条盒TJ 小盒BJ
            zipFilePaths.append("416_BJ_" + zipTimeStamp[0] + "-00_" + zipTimeStamp[0] + "-59_0.zip");
            zipFilePaths.append("416_BJ_" + zipTimeStamp[0] + "-00_" + zipTimeStamp[0] + "-59_1.zip");
            fileList.append(zipTimeStamp[0] + "ng.txt");
            fileList.append(zipTimeStamp[0] + "ok.txt");

            zipTimeStamp.clear();

            QFile* file[2] = { NULL };

            file[0] = new QFile(fileList[0]);
            file[1] = new QFile(fileList[1]);

            //QFile fileNg(fileList[0]);
           // QFile fileOk(fileList[1]);

            file[0]->open(QIODevice::WriteOnly);
            file[1]->open(QIODevice::WriteOnly);

            QTextStream ngStream(file[0]);
            QTextStream okStream(file[1]);

            argsNg.append("a");
            argsNg.append(zipFilePaths[0]);

            argsOk.append("a");
            argsOk.append(zipFilePaths[1]);

            // create zip file
            QMapIterator<QString, bool> iterator(listToZip);
            while (iterator.hasNext()) {
                iterator.next();
                if (iterator.value()) {
                    ngStream << iterator.key() << endl;
                }
                else {
                    okStream << iterator.key() << endl;
                }
            }
            argsNg.append("-i@" + fileList[0]);
            argsNg.append("-mx=3");

            argsOk.append("-i@" + fileList[1]);
            argsOk.append("-mx=3");

            file[0]->close();
            file[1]->close();

            for (int i = 0; i < zipFilePaths.size(); i++) {
                if (file[i]->size() == 0) {
                    continue;
                }
                process.start(QApplication::applicationDirPath() + "/7z.exe", i == 0 ? argsNg : argsOk);
                process.waitForStarted();
                process.waitForFinished();
                //QString out = QString::fromLocal8Bit(process.readAllStandardOutput());
                //qDebug() << out;
                remotePath = zipFilePaths[i].mid(zipFilePaths[i].indexOf("image") - 1);
                qDebug() << remotePath;
                ConnectServer(zipFilePaths[i], remotePath);
                QFile file(zipFilePaths[i]);
                file.remove();
            }
            file[0]->remove();
            file[1]->remove();
            listToZip.clear();
            readyToSendZip = false;
            delete file[0];
            delete file[1];
        }
    }
    flag = false;

    for (int index = 0; index < NumberOfSupportedCameras; index++) {
        pDocument[index]->~XMLDocument();
    }

    if (hftp != NULL) {
        InternetCloseHandle(hftp);
        hftp = NULL;
    }
    if (hftp != NULL) {
        InternetCloseHandle(hint);
        hint = NULL;
    }
}

//*****************************************已经调试好，没有理清逻辑前不要动**********************
void ExportDataThread::check_save_dir(std::string dir_path)
{
    // 如果目的路径不存在，一级一级创建
    // 目的路径格式为:"./dir/dir1/.../"

    if (FALSE == FtpSetCurrentDirectoryA(hftp, dir_path.c_str())) {
        FtpSetCurrentDirectoryA(hftp, "/");
        int pos = 1;
        while (pos > 0) {
            // 从第二个“/”开始依次找到目的路径中的“/”位置
            pos = dir_path.find_first_of('/', pos + 1);
            if (pos == -1)
                break;
            string tempPath = dir_path.substr(0, pos + 1);
            FtpCreateDirectoryA(hftp, tempPath.c_str());
        }
        //FtpSetCurrentDirectoryA(hftp, dir_path.c_str());
    }
}

void ExportDataThread::EDrecMsgFromCigarette() {
    flag = true;
}
//发送数据给服务器
void ExportDataThread::ConnectServer(QString srcPath, QString destPath) {
    string filePath = srcPath.toLocal8Bit().constData();
    string remotePath = destPath.toLocal8Bit().constData();

    std::vector<string> files;
    // 判断上传的是文件还是文件夹标识
    int size = 0;
    struct stat st;
    stat(filePath.c_str(), &st);
    if (st.st_mode & S_IFDIR) {
        //qDebug() << "filePath is Directory";
        // 获取文件夹下所有文件名
        GetFiles(filePath, files);
        size = files.size();
    }

    if (!FtpConnectionTest()) {
        qDebug() << "Failed to connect FTP server";
        return;
    }

    // 上传文件源为一个文件
    if (size == 0) {
        int pos = remotePath.find_last_of('/');
        string destFileName = remotePath.substr(pos + 1);
        string tempPath = remotePath.substr(0, pos + 1);

        if (!InternetGetConnectedState(NULL, 0)) {
            qDebug() << "计算机未连接到互联网";
        }
        else {
            check_save_dir(tempPath);
            while (!FtpPutFileA(hftp, filePath.c_str(), remotePath.c_str(), FTP_TRANSFER_TYPE_BINARY, 0)) {
                qDebug() << "ftp put file " << filePath.c_str() << "failed because" << GetLastError();
                if (!ConnectFtp(&ip, &port, &username, &userpwd))
                    qDebug() << "connect FTP failed because " << GetLastError();
            }
        }
    }
    // 上传源为一个文件夹
    else {
        for (int i = 0; i < size; i++) {
            string tempFilePath = (string(files[i]).erase(0, filePath.length() + 1)).c_str();
            // 获取上传路径中的文件名
            int pos = tempFilePath.find_last_of('/');
            string destFileName = tempFilePath.substr(pos + 1);
            check_save_dir(remotePath + tempFilePath.substr(0, pos + 1));
            //发送函数
            if (!FtpPutFileA(hftp, files[i].c_str(), destFileName.c_str(), FTP_TRANSFER_TYPE_BINARY, 0))
                qDebug() << "ftp put files failed because " << GetLastError();
        }
    }
}

void ExportDataThread::GetDataFromSaveThread(QString filePath, bool Ng) {
    QString remotePath;
    QStringList currentTimeStamp;
    QRegExp rx("((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))_([0-1]?[0-9]|2[0-3])-([0-5][0-9])");
    

    
    if (filePath.indexOf("ng") == -1) {

        if (rx.indexIn(filePath) != -1) {
            currentTimeStamp = rx.capturedTexts();
        }
        else {
            QDateTime now_ts = QDateTime::currentDateTime();
            currentTimeStamp.append(now_ts.toString("yyyy-MM-dd_HH-mm"));
        }

        if (lastTimeStamp.isEmpty() || (currentTimeStamp[0] != lastTimeStamp[0])) {
            if (!tmpListToZip.isEmpty()) {
                listToZip.unite(tmpListToZip);
                tmpListToZip.clear();
            }
            if (!listToZip.isEmpty()) {
                zipTimeStamp.append(lastTimeStamp[0]);
                readyToSendZip = true;
            }
            lastTimeStamp.clear();
            lastTimeStamp.append(currentTimeStamp[0]);
            timer->stop();
            timer->start(1000 * (60 * 1 + 10));
        }
        tmpListToZip.insert(filePath, Ng);
    }

}

//*****************************************已经调试好，没有理清逻辑前不要动**********************
void ExportDataThread::GetFiles(string path, std::vector<string>& files) {
    //文件句柄  
    intptr_t hFile = 0;
    //文件信息的结构体
    struct _finddata_t fileinfo;
    string p;
    if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
    {
        // "\\*"是指读取文件夹下的所有类型的文件
        do
        {
            //如果是目录,迭代之  
            //如果不是,加入列表  
            if ((fileinfo.attrib & _A_SUBDIR))
            {
                if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
                    GetFiles(p.assign(path).append("/").append(fileinfo.name), files);
            }
            else
            {
                files.push_back(p.assign(path).append("/").append(fileinfo.name));
            }
        } while (_findnext(hFile, &fileinfo) == 0);
        _findclose(hFile);
    }
}
