#include "faceCompare.h"
#include "ui_faceCompare.h"

#include "CAppInfo.h"

#include <QDesktopWidget>
#include <QFile>
#include <QFileInfo>

#include "awMsgBox.h"
#include "logproc.h"
#include "CCommonTools.h"
#include "CFaceRecProc.h"


faceCompare::faceCompare(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::faceCompare)
{
    ui->setupUi(this);

    setStyleSheet(g_appInfoPtr->m_sQssStr);

    initUI();
    m_bStartCompare = false;

    qRegisterMetaType<CBaseResponsePackage>("CBaseResponsePackage");
	qRegisterMetaType<CProcessUpload>("CProcessUpload");
    connect(g_httpBllPtr.get(), &CHttpBll::sgnProcessUpload, this, &faceCompare::onProcessUpload);
    connect(g_httpBllPtr.get(), &CHttpBll::sgnSaveFaceCompareResult, this, &faceCompare::onSaveFaceCompareResult);


    QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
    sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
    if(!QFile::exists(sFileName))
    {
        CHttpRequestPackage hrp;
        hrp.sUri = g_appInfoPtr->m_sStudentPhotoPath;
        hrp.sCommonStr = sFileName;
        hrp.nRequestType = RequestType::rtDownLoadFile;

        g_httpBllPtr->downLoad(hrp);
    }

    m_pinitTimer = std::make_shared<QTimer>();
    m_pinitTimer->setInterval(1000);
    connect(m_pinitTimer.get(), &QTimer::timeout, this, [&](){
        m_pinitTimer->stop();
        if(!m_cam.open(0))
        {
            ShowMsg(QString::fromLocal8Bit("打开摄像头失败"), this);
			return;
        }

        int inWidth = ui->widget_fc_camera->width();
        m_cam.set(CV_CAP_PROP_FRAME_WIDTH, inWidth);
        int inHeight = ui->widget_fc_camera->height();
        m_cam.set(CV_CAP_PROP_FRAME_HEIGHT, inHeight);
        m_cam.set(CV_CAP_PROP_FPS, 5);
        m_pVideoTimer->start();


    });

    m_pVideoTimer = std::make_shared<QTimer>();
    m_pVideoTimer->setInterval(200);
    connect(m_pVideoTimer.get(), &QTimer::timeout, this, [&](){

        cv::Mat frame;
        m_cam>>frame;

        if(frame.empty())
        {
            qDebug()<<"widgetCameraTest frame is empty";
            return;
        }

        m_nCurImage = frame;
        QImage img = CCommonTools::Mat2QImage(frame);

        ui->widget_fc_camera->setAutoFillBackground(true);
        QPalette palette;
        palette.setBrush(QPalette::Window, QBrush(img.scaled(ui->widget_fc_camera->width(), ui->widget_fc_camera->height())));
        ui->widget_fc_camera->setPalette(palette);
    });

	m_pinitTimer->start();

	connect(this, &faceCompare::compareFailed, this, [&](QString sErrorMsg) {
		ShowMsg(sErrorMsg, this);
		ui->btn_fc_compare->setEnabled(true);
	});

    m_bIsRun = true;
    m_thread = std::thread(std::bind(&faceCompare::threadProc, this));
}

faceCompare::~faceCompare()
{
    m_pVideoTimer->stop();

    m_bIsRun = false;
    m_thread.join();

    delete ui;
}

void faceCompare::initUI()
{
    QDesktopWidget *dekwiget = QApplication::desktop();
    setGeometry(0, 0, dekwiget->width(), dekwiget->height());
    ui->widget_mask->setGeometry(0, 0, dekwiget->width(), dekwiget->height());
    ui->widget_fc_BG->setGeometry((width() - g_appInfoPtr->m_fRate*800)/2, (height() - g_appInfoPtr->m_fRate*536)/2,
                                   g_appInfoPtr->m_fRate*800, g_appInfoPtr->m_fRate*536);
    ui->label_fc_title->adjustSize();
    ui->label_fc_title->setGeometry(g_appInfoPtr->m_fRate*20, g_appInfoPtr->m_fRate*16,
                                    ui->label_fc_title->width(), ui->label_fc_title->height());
    ui->btn_fc_close->setGeometry(ui->widget_fc_BG->width() - g_appInfoPtr->m_fRate*(20 + 16),
                                  g_appInfoPtr->m_fRate*16, g_appInfoPtr->m_fRate*16, g_appInfoPtr->m_fRate*16);
    ui->label_HLine->setGeometry(0, ui->label_fc_title->y() + ui->label_fc_title->height() + g_appInfoPtr->m_fRate*16,
                                 ui->widget_fc_BG->width(), g_appInfoPtr->m_fRate*1);
    ui->label_fc_basePhoto->setGeometry(g_appInfoPtr->m_fRate*30, ui->label_HLine->y() + ui->label_HLine->height() + g_appInfoPtr->m_fRate*20,
                                        g_appInfoPtr->m_fRate*140, g_appInfoPtr->m_fRate*180);
	QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
	sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
	ui->label_fc_basePhoto->setPixmap(QPixmap(sFileName).scaled(ui->label_fc_basePhoto->width(), ui->label_fc_basePhoto->height(),
		Qt::IgnoreAspectRatio));
	ui->label_fc_basePhotoTips->setGeometry(ui->label_fc_basePhoto->x() + g_appInfoPtr->m_fRate*10,
                                            ui->label_fc_basePhoto->y() + ui->label_fc_basePhoto->height() - g_appInfoPtr->m_fRate*(10+20),
                                            ui->label_fc_basePhoto->width() - g_appInfoPtr->m_fRate*10*2, g_appInfoPtr->m_fRate*20);
    ui->widget_fc_camera->setGeometry(ui->label_fc_basePhoto->x() + ui->label_fc_basePhoto->width() + g_appInfoPtr->m_fRate*20,
                                     ui->label_fc_basePhoto->y(), g_appInfoPtr->m_fRate*580, g_appInfoPtr->m_fRate*300);
    ui->btn_fc_compare->setGeometry((ui->widget_fc_camera->width() - g_appInfoPtr->m_fRate*120)/2,
                                    ui->widget_fc_camera->height() - g_appInfoPtr->m_fRate*(20 + 40),
                                    g_appInfoPtr->m_fRate*120, g_appInfoPtr->m_fRate*40);
    ui->label_fc_tips->adjustSize();
    ui->label_fc_tips->setGeometry(ui->widget_fc_camera->x(), ui->widget_fc_camera->y() + ui->widget_fc_camera->height() + g_appInfoPtr->m_fRate*20,
                                   ui->label_fc_tips->width(), ui->label_fc_tips->height());
    ui->label_fc_note->setGeometry(ui->widget_fc_camera->x(), ui->label_fc_tips->y() + ui->label_fc_tips->height() + g_appInfoPtr->m_fRate*5,
                                   g_appInfoPtr->m_fRate*580, g_appInfoPtr->m_fRate*100);
}

void faceCompare::on_btn_fc_compare_clicked()
{
    if(g_faceRecProcPtr == nullptr)
    {
        g_faceRecProcPtr = std::make_shared<CFaceRecProc>();

        if (!g_appInfoPtr->m_sStudentPhotoPath.isEmpty())
        {
            QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
            sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
            if(!QFile::exists(sFileName))
            {
                ShowMsg(QString::fromLocal8Bit("底照下载失败，请检查网络"), this);
                return;
            }
			QFileInfo filePath(sFileName);
			
            g_faceRecProcPtr->setBaseImage(filePath.absoluteFilePath());
        }
        else
        {
            ShowMsg(QString::fromLocal8Bit("当前考试未底照"), this);
            return;
        }
    }
    m_bStartCompare = true;
	ui->btn_fc_compare->setEnabled(false);
}

void faceCompare::on_btn_fc_close_clicked()
{
    emit exitFaceCompare();
}

void faceCompare::threadProc()
{
    while(m_bIsRun)
    {
        if(m_bStartCompare)
        {
            cv::Mat img = m_nCurImage;
            if(!img.empty())
            {
                //人脸比对
                int nFaceCount = 0;
                float fScore = 0;
                bool bRealness = false;
				int nTime = 0;
                if(!g_faceRecProcPtr->getMaxFaceScoreWithBase(img, nFaceCount, fScore, bRealness, nTime))
                {
                    //比对失败
                    QString sErrorMsg = g_faceRecProcPtr->errorMsg();
                    emit compareFailed(sErrorMsg);
                }
                else
                {
                    if(nFaceCount == 0)
                    {
                        //无人脸
                        emit compareFailed(QString::fromLocal8Bit("请让我看到您的正脸"));
                    }
                    else if(nFaceCount > 1 && g_appInfoPtr->m_oExamInfo.bIsStrangerEnable)
                    {
                        //陌生人
                        emit compareFailed(QString::fromLocal8Bit("检测到陌生人"));
                    }
                    else
                    {
                        if(fScore*100 > g_appInfoPtr->m_oExamInfo.nWarnThreshold)
                        {
							m_fScore = fScore;
							m_nFaceCount = nFaceCount;
							m_nTime = nTime;
                            //比对成功
                            QString sFileName = QString("temp/photo/%1.png").arg(CCommonTools::getUuid());
                            QImage imgCompare = CCommonTools::Mat2QImage(img);
                            imgCompare.save(sFileName, "PNG");

                            CHttpRequestPackage hrp;
                            hrp.sUri = "/api/ecs_oe_student/client/exam/process/upload";
                            hrp.nRequestType = RequestType::rtProcessUpload;
                            hrp.sParamList.push_back(QString("formdataFileType,file,%1").arg(sFileName));
                            hrp.sParamList.push_back(QString("md5,%1").arg(CCommonTools::fileMd5(sFileName)));

                            hrp.eParamType = HttpParamType::hptFormdata;
                            g_httpBllPtr->post(hrp);
                        }
                        else
                        {
                            //低于阈值
                            emit compareFailed(QString::fromLocal8Bit("检测失败"));
                        }
                    }
                }
				m_bStartCompare = false;
            }
        }
        else
        {
            Sleep(100);
        }
    }
}

//文件上传
void faceCompare::onProcessUpload(CProcessUpload processUpload)
{
    if(processUpload.nCode == 200)
    {
		CHttpRequestPackage hrp;
		hrp.sUri = "/api/ecs_oe_student/client/exam/process/saveFaceCompareResult";
		hrp.nRequestType = RequestType::rtSaveFaceCompareResult;		
		Json::Value jBody = Json::Value::null;
		jBody["faceCompareResult"] = QString::number(m_fScore).toStdString();
		jBody["fileUrl"] = processUpload.sFileUrl.toStdString();
		jBody["pass"] = true;
		jBody["processTime"] = m_nTime;
		jBody["stranger"] = m_nFaceCount > 1;
		hrp.sParamList.push_back(QString("CustomBody,%1").arg(jBody.toStyledString().c_str()));
		hrp.eParamType = HttpParamType::hptCustomBody;
	
		g_httpBllPtr->post(hrp);
    }
    else
    {
        if(processUpload.sMessage.isEmpty())
        {
            ShowMsg(QString::fromLocal8Bit("上传照片失败"), this);
        }
        else
        {
            ShowMsg(processUpload.sMessage, this);
        }
    }
}

//保存人脸识别比对验证结果
void faceCompare::onSaveFaceCompareResult(CBaseResponsePackage res)
{
    if(res.nCode == 200)
    {
        ShowMsg(QString::fromLocal8Bit("人脸比对成功"), this);
        QTimer::singleShot(3000, this, [&](){
            emit faceComparePass();
        });

    }
    else
    {
        if(res.sMessage.isEmpty())
        {
            ShowMsg(QString::fromLocal8Bit("保存人脸识别信息失败"), this);
        }
        else
        {
            ShowMsg(res.sMessage, this);
        }
    }
}
