#include "SyncWorkThread.h"
#include "alg_jd.h"
#include "common.h"
#include "balluffcamera.h"
#include "baslercamera.h"
#include "threadSend.h"
#include <PLCDevice.h>
#include "exportData.h"
#include <QMap>

extern AlgJd alg_jd[NumberOfSupportedCameras];  //检测胶点的AI算法
extern ConfPath g_conf_path;
extern SysConf g_sys_conf;  //系统配置参数
extern DisplayLabelConf g_display_label_conf[NumberOfSupportedCameras];

extern int rotationAngle[NumberOfSupportedCameras];  //图片旋转角度
extern bool isNeedRotate[NumberOfSupportedCameras];
extern int work_camera_nums;
extern SingleCamInfoStruct SingleCamInfo[NumberOfSupportedCameras];

extern SyncQueue<std::pair<std::string, cv::Mat> >* g_save_queue;   //图片保存队列
extern SyncQueue<std::pair<int, cv::Mat>>* g_image_queue[NumberOfSupportedCameras]; //int表示一个目标拍了几张
#ifdef __UDPSend
extern SyncQueue<_UDPSendInfo>* UDP_Info_queue;
#endif
#ifdef __TCPSend
extern SyncQueue<_TCPSendInfo>* TCP_Info_queue;
extern threadSendTCP tcpSendThread;
#endif
#ifdef __ExportData
extern ExportDataThread exportDataThread;
#endif
extern PLCDevice* m_PLCDevice;
extern bool g_debug_mode;

bool IsALL = false;//是否是全存


SyncWorkThread::~SyncWorkThread()
{
    stop();
    std::vector<std::pair<int, cv::Mat>> queue;
    local_g_image_sync_queue->put(queue);
    quit();
    wait();
}

void SyncWorkThread::init(SyncQueue<std::vector<std::pair<int, cv::Mat>>>* image_ptr, ASyncQueue<bool>* result_ptr[], int MergeToCamId)
{
    local_g_image_sync_queue = image_ptr;
    local_g_result_queue = result_ptr;
    b_quit = false;
    MergeToCamId = MergeToCamId;
    for (int i = 0; i < NumberOfSupportedCameras; i++) {
        frame_total[i] = 0;
    }
}

void SyncWorkThread::start_work()
{
    start(HighestPriority);
}
void SyncWorkThread::stop()
{
    b_quit = true;
}

void SyncWorkThread::run()
{
    try {
        uint32_t result_index[NumberOfSupportedCameras] = { 0 };
        while (!b_quit)
        {
            QDateTime now_ts = QDateTime::currentDateTime();
#ifdef __TCPSend
            _TCPSendInfo TCPSendInfo;
            QString sendName = "416_BJ_01_" + now_ts.toString("yyyy-MM-dd_HH-mm-ss.zzz");
            TCPSendInfo.pics_name = sendName.toLocal8Bit().constData();
            TCP_Info_queue->put(TCPSendInfo);
            tcp_send_times++;
            cout << "TCP_data :" << sendName.toLocal8Bit().constData() << endl;
            cout << "TCP_send_times :" << tcp_send_times << endl;
#endif
            std::vector<std::pair<int, cv::Mat>> element_vec;
            local_g_image_sync_queue->take(element_vec);

#ifdef IS_CAM_NG_OK_DATA_MERGED
            bool IsNGForAll = false;
#endif

            int merge_index;
            cv::Mat merge_image = cv::Mat::zeros(image_h * g_sys_conf.shoot[0], image_w * work_camera_nums,  CV_8UC3);//640*work_camera_nums
            cv::Rect roi;
            int j = 0;	// 实际工作的相机标识，element_vec中可能有相机没在工作
            for (int i = 0; i < element_vec.size(); i++)//每个相机的图轮流遍历
            {

                if (!SingleCamInfo[i].Detect || !SingleCamInfo[i].IsOpen || SingleCamInfo[i].OffLine)
                    continue;
                local_camera_number = i;
                std::pair<int, cv::Mat> element;
                element = element_vec[i];
                int unit_count = element.first;
                cv::Mat image = element.second;
                {//不要删掉这个括号，用来定义锁的作用域
                    std::lock_guard<std::mutex> locker(g_sys_conf.lock);
                    local_SysConf.save = g_sys_conf.save;
                    local_SysConf.shoot[local_camera_number] = g_sys_conf.shoot[local_camera_number];
                    local_SysConf.MisMatchAct = g_sys_conf.MisMatchAct;
                    local_SysConf.ConfThreshold = g_sys_conf.ConfThreshold;//
                    for (int i = 0; i < 3; i++)local_SysConf.no[local_camera_number][i] = g_sys_conf.no[local_camera_number][i];

#ifdef DRAW_RECT
                    std::lock_guard<std::mutex> locker2(g_display_label_conf[local_camera_number].lock);
                    local_DisplayLabelConf.leftButtonDownFlag = g_display_label_conf[local_camera_number].leftButtonDownFlag;
                    local_DisplayLabelConf.Flag[0] = g_display_label_conf[local_camera_number].Flag[0];
                    local_DisplayLabelConf.Flag[1] = g_display_label_conf[local_camera_number].Flag[1];
                    local_DisplayLabelConf.originalPoint = g_display_label_conf[local_camera_number].originalPoint;
                    local_DisplayLabelConf.processPoint = g_display_label_conf[local_camera_number].processPoint;
                    local_DisplayLabelConf.RectVet[0] = g_display_label_conf[local_camera_number].RectVet[0];
                    local_DisplayLabelConf.RectVet[1] = g_display_label_conf[local_camera_number].RectVet[1];
#endif
                }

#ifdef __UDPSend
                _UDPSendInfo UDPSendInfo;
                UDPSendInfo.FrameID = info_frame;
                UDPSendInfo.index = local_camera_number;
#endif
//#ifdef __TCPSend
//                _TCPSendInfo TCPSendInfo;
//#endif
//#ifdef __TCPSend
//                QString sendName = "416_BJ_01_" + now_ts.toString("yyyy-MM-dd_HH-mm-ss.zzz");
//                TCPSendInfo.pics_name = sendName.toLocal8Bit().constData();
//                TCP_Info_queue->put(TCPSendInfo);
//#endif
                if (!image.data)
                {
                    continue;	//图像为空，跳过
                }
                if (image.channels() == 1)
                {
                    cv::cvtColor(image, image, CV_BGR2RGB);	//灰度图像转为彩色图像
                }
                cv::resize(image, image, cv::Size(image_w, image_h * unit_count));
                if (local_SysConf.shoot[local_camera_number] == unit_count)
                {
/*#ifdef __TCPSend
                    QString sendName = "416_BJ_01_" + now_ts.toString("yyyy-MM-dd_HH-mm-ss.zzz");
                    TCPSendInfo.pics_name = sendName.toLocal8Bit().constData();
                    TCP_Info_queue->put(TCPSendInfo);
                    tcp_send_times++;
                    cout << "TCP_data :" << sendName.toLocal8Bit().constData() << endl;
                    cout << "TCP_send_times :" << tcp_send_times << endl;
#endif */  
                    std::vector<cv::Mat> vec_in;
                    int w = image.cols ;
                    int h = image.rows / unit_count;
                    for (int index = 0; index < unit_count; index++) {
                        cv::Rect temp_Rect(0, h * index, w, h);
                        cv::Mat temp_image = image(temp_Rect).clone();
                        if (isNeedRotate[local_camera_number]) {
                            if (rotationAngle[local_camera_number] != (cv::ROTATE_90_COUNTERCLOCKWISE + 1))
                            {
                                cv::rotate(temp_image, temp_image, rotationAngle[local_camera_number]);
                            }
                        }
                        vec_in.push_back(temp_image.clone());
                    }
                    std::vector<cv::Mat> vec_out;
                    std::vector<std::vector<std::pair<int, cv::Rect>>> vec_results;
                    QDateTime ts_start = QDateTime::currentDateTime();
                    if (unit_count == 1) {
                        std::vector<std::pair<int, cv::Rect>> results;
                        cv::Mat imagein, imageout;
                        imagein = vec_in[0];
                        alg_jd[local_camera_number].detect(imagein, imageout, results);
                        vec_out.push_back(imageout.clone());
                        vec_results.push_back(results);
                    }
                    else 
                    {
                        alg_jd[local_camera_number].detect_batch(vec_in, vec_out, vec_results);                    
                    }
                    QDateTime ts_jd = QDateTime::currentDateTime();
                    int time_process = ts_start.msecsTo(ts_jd);
#ifdef SYNC_CAMERA
                    emit display_timecost(local_camera_number, time_process);
#endif
#ifdef __UDPSend
                    UDPSendInfo.timecost = QString::number(time_process);
#endif
                    cv::Mat image1;
                    cv::Mat image2;
                    QString jd_no;
                    for (int index = 0; index < unit_count; index++) {
                        jd_no += QString::number(vec_results[index].size()) + ",";
                    }
                    jd_no.chop(1);
#ifdef SYNC_CAMERA
                    emit display_jd_no(local_camera_number, jd_no);
#endif

#ifdef __UDPSend
                    UDPSendInfo.JD = jd_no;
#endif
                    IsALL = false;//4.10
                    bool IsNG = false;
                    int ngReason = 0;
                    QMap<int, QString> ng_reason_maps;
                    ng_reason_maps[0] = "1";//1=OK ; 0=NG
                    ng_reason_maps[1] = "0";
                    ng_reason_maps[2] = "0";
                    ng_reason_maps[3] = "0";
                    for (int index = 0; index < unit_count; index++) {
                        if (vec_results[index].size() < local_SysConf.no[local_camera_number][index])
                        {
                            IsNG |= true;
                            ngReason = 1;
                        }
                        //if (vec_results[index].size() != 1)IsNG |= true;//反向训练
                        if (local_SysConf.ConfThreshold == 0)
                        {
                            IsNG = false;
                            ngReason = 0;
                        }
                    }

                    if (unit_count >= 2) {
                        image1 = vec_out[(result_index[i]) % 2].clone();
#ifdef DRAW_RECT
                        IsNG |= CheckSelectRects(image1, vec_results, (result_index[i]) % 2, local_DisplayLabelConf, 0);
                        if (IsNG) {
                            ngReason = 2;
                        }
#endif
                    }
                    else {
                        image1 = vec_out[0].clone();
#ifdef DRAW_RECT
                        IsNG |= CheckSelectRects(image1, vec_results, 0, local_DisplayLabelConf, 0);
                        if (IsNG) {
                            ngReason = 2;
                        }
#endif
                    }
#ifdef DRAW_RECT
                    DrawSelectRects(image1, local_DisplayLabelConf, 0);
#endif

                    if (unit_count >= 3) {
                        image2 = vec_out[2].clone();
#ifdef DRAW_RECT
                        DrawSelectRects(image2, local_DisplayLabelConf, 1);
                        IsNG |= CheckSelectRects(image1, vec_results, 2, local_DisplayLabelConf, 1);
                        if (IsNG) {
                            ngReason = 3;
                        }
#endif
                    }
                    result_index[i]++;
                    if (!IsNG)
                    {
                        if (!g_debug_mode)
                        {
#ifdef SYNC_CAMERA
                            emit event_ok(local_camera_number);
#endif
#ifndef IS_CAM_NG_OK_DATA_MERGED
                           local_g_result_queue[local_camera_number]->put(true);
#endif
                        }
                    }
                    else
                    {
                        IsALL = false;
                        if (!g_debug_mode)
                        {
#ifdef SYNC_CAMERA
                            emit event_ng(local_camera_number);
#endif
#ifndef IS_CAM_NG_OK_DATA_MERGED
                            local_g_result_queue[local_camera_number]->put(false);
#else
                            IsNGForAll = TRUE;
#endif
                        }

                        if ((local_SysConf.save == 2) || (local_SysConf.save == 1))
                        {
                            
                            for (int index = 0; index < unit_count; index++)
                            {
                                if (vec_results[index].size() < local_SysConf.no[local_camera_number][index])
                                {
                                    cv::Mat m = vec_in[index].clone();
                                    QString file_name = g_conf_path.save_pics_path + "/ng/" +
                                        now_ts.toString("yyyy-MM-dd") + "/"
                                        + QString::number(local_camera_number + 1) + "/" + QString::number(index + 1) + "/" +
                                        now_ts.toString("yyyy-MM-dd_HH-mm-ss_zzz_") + QString::number(local_camera_number + 1) +
                                        "#" + "_" + QString::number(index + 1) + "_" + ng_reason_maps[ngReason] +
                                        ".jpg";
                                    
                                g_save_queue->put(std::make_pair(file_name.toLocal8Bit().constData(), m));

                                m = vec_out[index].clone();
                                file_name = g_conf_path.save_pics_path + "/ng_result/" +
                                    now_ts.toString("yyyy-MM-dd") + "/"
                                    + QString::number(local_camera_number + 1) + "/" + QString::number(index + 1) + "/" +
                                    now_ts.toString("yyyy-MM-dd_HH-mm-ss_zzz_") + QString::number(local_camera_number + 1) +
                                    "#" + "_" + QString::number(index + 1) + "_" + ng_reason_maps[ngReason] +
                                    ".jpg";
                                
                                g_save_queue->put(std::make_pair(file_name.toLocal8Bit().constData(), m));
                                }
                            }
                        }
                    }
#ifdef SYNC_CAMERA
                    if (!g_debug_mode)
                    {
                        emit display_check_total(local_camera_number, ++frame_total[local_camera_number]);
                        //exportDataInfo.cameraTotal = frame_total;
                        emit notify(local_camera_number, 0, image1);
                        if (unit_count >= 3)
                            emit notify(local_camera_number, 1, image2);
                    }
#endif
                    for (int index = 0; index < unit_count; index++)
                    {
                        if (local_SysConf.save == 2)//照片存储
                        {
                            /// 合成work_camera_nums * unit_count 宫格图像
                            cv::Mat m = vec_in[index].clone();
                            QString file_name;
                            merge_index = j * unit_count + index + 1;
                            roi = cv::Rect(j * m.cols, index * m.rows, m.cols, m.rows);
                            m.copyTo(merge_image(roi));
                            
                            if (merge_index == work_camera_nums * unit_count) 
                            {
                                //条盒TJ 小盒BJ
                                file_name = g_conf_path.save_pics_path + "/"
                                    + now_ts.toString("yyyy-MM-dd") + "/"+"416_BJ_01_"
                                    + now_ts.toString("yyyy-MM-dd_HH-mm-ss.zzz")+ ".jpg";
                                g_save_queue->put(std::make_pair(file_name.toLocal8Bit().constData(), merge_image));     
#ifdef SYNC_CAMERA
                                sendDataToCompress(file_name, IsNG);
#endif
/*#ifdef __TCPSend
                                QString sendName = "416_BJ_01_" + now_ts.toString("yyyy-MM-dd_HH-mm-ss.zzz");
                                TCPSendInfo.pics_name = sendName.toLocal8Bit().constData();
                                TCP_Info_queue->put(TCPSendInfo);
                                tcp_send_times++;
                                cout << "TCP_data :" << sendName.toLocal8Bit().constData() << endl;
                                cout << "TCP_send_times :" << tcp_send_times << endl;
#endif */                        
                            }
                        }
                    }
                }
                else
                {
#ifdef SYNC_CAMERA
                    //保证不错位
                    if (!g_debug_mode)
                    {
                        if (local_SysConf.MisMatchAct == 1)//as ng
                            emit event_ng(local_camera_number);
                        else if (local_SysConf.MisMatchAct == 0)//as ok
                            emit event_ok(local_camera_number);
                        emit display_check_total(local_camera_number, ++(frame_total[local_camera_number]));
                        qDebug() << local_camera_number << "#camera# " << now_ts.toString("yyyy-MM-dd_HH-mm-ss_zzz_") << "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  " << unit_count;
                    }
#endif
                }
#ifdef __UDPSend
                UDP_Info_queue->put(UDPSendInfo);
#endif
                j++;
            }
#ifdef IS_CAM_NG_OK_DATA_MERGED
            if (IsNGForAll)
            {
                local_g_result_queue[MergeToCamId]->put(false);
               
            }
            else
            {
                local_g_result_queue[MergeToCamId]->put(true);
               
            }
#endif
           // emit display_check_total(local_camera_number, ++(frame_total[local_camera_number]));

        }

    }
    catch (cv::Exception& e)
    {
        const char* err_msg = e.what();
        std::cout << "exception caught: " << err_msg << std::endl;
    }
}
