#include "CWebsocketProc.h"

#include <QNetworkRequest>
#include <QUrlQuery>
#include <QCryptographicHash>
#include "CCommonTools.h"
#include "CAppInfo.h"
#include "logproc.h"

std::shared_ptr<CWebsocketProc> g_websocketPtr;

CWebsocketProc::CWebsocketProc()
{
    m_sToken = "";
    m_nTimeOutTimes = 0;
    m_nTimeOutLimit = 4;
    m_nTimeOutSecord = 30;
    m_bConnected = false;
    m_pWebsocket = new QWebSocket;
    m_isExitClosed = false;

    QSslConfiguration config = m_pWebsocket->sslConfiguration();
    config.setPeerVerifyMode(QSslSocket::VerifyNone);
    config.setProtocol(QSsl::TlsV1SslV3);
    m_pWebsocket->setSslConfiguration(config);

    m_pTime = new QTimer;
    connect(m_pTime, &QTimer::timeout, this, &CWebsocketProc::reconnect);

    connect(m_pWebsocket, &QWebSocket::disconnected, this, &CWebsocketProc::onDisconnected);
    bool ret = connect(m_pWebsocket, &QWebSocket::textMessageReceived, this, &CWebsocketProc::onTextReceived);
    ret = connect(m_pWebsocket, &QWebSocket::connected, this, &CWebsocketProc::onConnected);
}

CWebsocketProc::~CWebsocketProc()
{
    m_pWebsocket->errorString();
    m_pWebsocket->close();    
    RELEASE_PTR(m_pWebsocket);

    m_pTime->stop();
    RELEASE_PTR(m_pTime);

}

void CWebsocketProc::setUrl(QString sUrl, QString sToken, QString sKey)
{
    m_sUrl = sUrl;
    m_sToken = sToken;
    m_sKey = sKey;
}

void CWebsocketProc::open()
{    
    m_isExitClosed = false;
    if(!m_sUrl.isEmpty())
    {      
        QUrl url(m_sUrl);
        QUrlQuery urlQuery;        
        urlQuery.addQueryItem("key", m_sKey);
        urlQuery.addQueryItem("token", m_sToken);
        url.setQuery(urlQuery);
        qDebug()<<url.url();
        m_pWebsocket->open(url);
        m_pTime->start(m_nTimeOutSecord*1000);
        myServerLog()<<url.url();
    }

}

void CWebsocketProc::open(QString sUrl, QString sToken, QString sKey)
{    
    m_sToken = sToken;
    m_sKey = sKey;
    m_sUrl = sUrl;

    open();
}



void CWebsocketProc::close()
{
    m_isExitClosed = true;
    m_pTime->stop();
    m_bConnected = false;
//    m_pWebsocket->abort();
    m_pWebsocket->close();    
}

bool CWebsocketProc::isConnected()
{
    return m_bConnected;
}

qint64 CWebsocketProc::sendText(QString sText)
{
    if(m_bConnected)
    {

//        QByteArray data = sText.remove(QRegExp("\\s")).toLatin1();
        qDebug()<<sText;

        return m_pWebsocket->sendTextMessage(sText);
    }
    else
    {
        return 0;
    }
}

//断开连接会触发这个槽函数
void CWebsocketProc::onDisconnected()
{
    qDebug() << m_pWebsocket->errorString();
    m_bConnected = false;
    if(!m_isExitClosed)
    {
        m_pTime->start(m_nTimeOutSecord*1000);
        emit networkWeak();
    }    
    qDebug()<<"Websocket Disconnected";
    myServerLog() <<"Websocket Disconnected";
}

//连接成功会触发这个槽函数
void CWebsocketProc::onConnected()
{   
    m_bConnected = true;
    m_nTimeOutTimes = 0;
    m_pTime->stop();
    emit connected();
    qDebug()<<"Websocket Connected";
    myServerLog()<<"Websocket Connected";
}

//收到服务发来的消息会触发这个槽函数
void CWebsocketProc::onTextReceived(QString msg)
{
    try
    {
        qDebug()<<"recv:"<<msg;

        Json::Value jRececvMsg = Json::Value::null;
        Json::Reader reader;
        if(!reader.parse(msg.toStdString(), jRececvMsg))
        {
            myServerLog() << QString::fromLocal8Bit("解析后台数据出错：") << msg;
            emit websocketError("解析后台数据出错");
            return;
        }

        QString sCode = jRececvMsg["status"]["code"].asString().c_str();
		if (sCode != "200")
		{
			emit websocketError(jRececvMsg["status"]["desc"].asString().c_str());
		}
		else
		{
			QString sType = jRececvMsg["content"]["eventType"].asString().c_str();
			if (sType == "SCAN_QR_CODE")//移动端拍照/录音扫描完成
			{
				if (jRececvMsg["content"]["isSuccess"].asBool())
				{
					QString sScanStatus = jRececvMsg["content"]["data"]["scanStatus"].asString().c_str();
					__int64 nExamRecordDataId = jRececvMsg["content"]["data"]["examRecordDataId"].asInt64();
					int nOrder = jRececvMsg["content"]["data"]["order"].asInt();
					emit mobileStatus(nExamRecordDataId, nOrder, sScanStatus);
				}
				else
				{
					QString sErrorMsg = jRececvMsg["content"]["errorMessage"].asString().c_str();
					emit websocketError(sErrorMsg);
				}
			}
			else if (sType == "GET_FILE_ANSWER")//移动端拍照/录音上传成功
			{
				if (jRececvMsg["content"]["isSuccess"].asBool())
				{
					QString sFileType = jRececvMsg["content"]["data"]["transferFileType"].asString().c_str();
					QString sFileUrl = jRececvMsg["content"]["data"]["fileUrl"].asString().c_str();
					__int64 nExamRecordDataId = jRececvMsg["content"]["data"]["examRecordDataId"].asInt64();
					int nOrder = jRececvMsg["content"]["data"]["order"].asInt();
					emit fileAnswer(nExamRecordDataId, nOrder, sFileType, sFileUrl);
				}
				else
				{
					QString sErrorMsg = jRececvMsg["content"]["errorMessage"].asString().c_str();
					emit websocketError(sErrorMsg);
				}
			}
		}

        m_bConnected = true;
        m_nTimeOutTimes = 0;
        m_pTime->stop();
    }
    catch (std::exception &e)
    {
        emit websocketError(QString::fromLocal8Bit("接收数据出错：%1").arg(e.what()));
    }

}

//断开连接会启动定时器，触发这个槽函数重新连接
void CWebsocketProc::reconnect()
{
    m_nTimeOutTimes++;
    if(m_nTimeOutTimes > m_nTimeOutLimit)
    {
        emit clientOffLine();
        return;
    }
    else
    {
        emit networkWeak();
    }
    m_bConnected = false;
    m_pWebsocket->abort();
    open();
}
