/**
 *
 *  gsd_TcpPlugin.cc
 *
 */

#include "gsd_TcpPlugin.h"
#include "config.hpp"

using namespace drogon;
using namespace gsd;
using namespace utility;

void TcpPlugin::initAndStart(const Json::Value &config)
{
    this->tcpClient = std::shared_ptr<TCPClient>(new TCPClient);
    NoticeCenter::Instance().addListener(0, NOTICE_NETTY,
        [&](const Buffer::Ptr &pBuf){
        this->ListenNettyData(pBuf);
    });
    this->pool = std::make_shared<ThreadPool>(1,ThreadPool::PRIORITY_HIGHEST, false);
}

void TcpPlugin::shutdown() 
{
    /// Shutdown the plugin
}

/**
 * @description: 启动任务
 * @return {*}
 */
void TcpPlugin::StartTask(){
    // 连接Netty
    this->tcpClient->startConnect(config::getPtr()->NettyIP, config::getPtr()->NettyPort);
    // 心跳定时器
    this->HeartbeatTimer = std::make_shared<Timer>(10.0f,[this](){
        if(this->tcpClient == nullptr){
            this->tcpClient = std::shared_ptr<TCPClient>(new TCPClient);
            return true;
        }   
        this->SendHeartbeatData();
        return true;
    }, nullptr);
}   

/**
 * @description: 发送心跳数据
 * @return {*}
 */
void TcpPlugin::SendHeartbeatData(){
    if(this->tcpClient->alive()){
        if(!this->TcpNettyLogin){
            this->TCPLoginNetty();
        }
    }
    else{
        this->tcpClient->startConnect(config::getPtr()->NettyIP, config::getPtr()->NettyPort);
    }
}   

/**
 * @description: 登录Netty
 * @return {*}
 */
void TcpPlugin::TCPLoginNetty(){
    config::Ptr m_config = config::getPtr();
    // 登录
    SendLogin sendLogin;
    sendLogin.setAccount(m_config->usr);
    sendLogin.setPwd(md5(m_config->usr + m_config->pwd));
    DebugL << "VPN_IP:" << m_config->vpnIP << endl;
    sendLogin.setCameraIp(m_config->vpnIP);
    sendLogin.setSimCode(m_config->SimCode);
    std::string str;
    DeviceInfo deviceInfo;
    deviceInfo.localIp = m_config->vpnIP;
    deviceInfo.stream = "rtsp://"+ deviceInfo.localIp + ":8554/live";
    deviceInfo.objectToJson(str);
    sendLogin.setAttr1(str);
    
    NettyClientResultMsg<SendLogin> nettyClientResultMsg;
    std::string RequestId = uuid::generate();
    nettyClientResultMsg.setRequestId(RequestId);
    nettyClientResultMsg.setDataType(NettyClientCommandEnum().login);
    nettyClientResultMsg.setData(sendLogin);
    std::string json;
    nettyClientResultMsg.objectToJson(json);
    json += "\r\n";

    if(this->tcpClient->alive()){
        this->tcpClient->sendRequest(RequestId, NettyClientCommandEnum().login ,json, [&](int status,std::string buf){
            if(!config::getPtr()->debug){
                if(status == 200) TcpNettyLogin = true;
                else TcpNettyLogin = false;
            }else{
                TcpNettyLogin = true;
            }
        });
    }
}

/**
 * @description: 获取登录Netty结果
 * @return {*}
 */
bool TcpPlugin::getLoginNetty(){
    return this->TcpNettyLogin;
}

/**
 * @description: 监听netty数据
 * @param {Ptr} &buf
 * @return {*}
 */
void TcpPlugin::ListenNettyData(const Buffer::Ptr &buf)
{
    std::string json = buf->toString();
    if(config::getPtr()->debug) DebugL << json << endl;
    NettyServerResultMsg<RecDeviceCommand> nettyServerResultMsg;
    NettyServerResultMsg<RecLoginMsg> NettyServerResultMsgLogin;
    if(nettyServerResultMsg.jsonToObject(json)){
        if(config::getPtr()->debug) InfoL << "接收到控制指令" << endl;
        std::string deviceId = std::to_string(nettyServerResultMsg.getData().getDeviceId());
        ExpelDevice expelDevice;
        if(!config::getPtr()->LowVersion){
            vector<vector<std::string>> results;
            SqlWriter selete("SELECT DeviceToken,DeviceType,ServerIp,ServerCname,ServerCpwd FROM gsdDB.`DeviceList` WHERE DeviceId = '?' and ISDELETE=0");
            selete << deviceId << results;
            if(results.empty()){
                WarnL << "No device is queried" << endl;
                return;
            }
            expelDevice.DeviceId = deviceId;
            expelDevice.deviceToken = (enum DeviceToken)std::atoi(results[0][0].c_str());
            expelDevice.deviceType = (enum DeviceType)std::atoi(results[0][1].c_str());
            expelDevice.ServerIp = results[0][2];
            expelDevice.ServerCname = results[0][3];
            expelDevice.ServerCpwd = results[0][4];
        }else{
            expelDevice.DeviceId = deviceId;
            expelDevice.deviceType = (enum DeviceType)config::getPtr()->deviceType;
            expelDevice.deviceToken = serial;
        }
        this->pool->async([&,nettyServerResultMsg, expelDevice](){
            NettyServerResultMsg<RecDeviceCommand> ResultMsg = nettyServerResultMsg;
            Expel::getPtr() -> sendDeviceMsgCallback(ResultMsg, expelDevice);
        });
        this->pool->start();
    }else if(NettyServerResultMsgLogin.jsonToObject(json)){
        RecLoginMsg Loginmsg = NettyServerResultMsgLogin.getData();
        if(NettyServerResultMsgLogin.getDataType() == "client_conn_success"){
            InfoL << "连接Netty成功,发送登录信息" << endl;
            this->TCPLoginNetty();
        }
    }
}

/**
 * @description: 获取与Netty的通讯是否存活
 * @return {*}
 */
bool TcpPlugin::getAlive(){
    if(!config::getPtr()->debug) {
        if(!this->tcpClient->alive() || !this->TcpNettyLogin) return false;
        else return true;
    }else{
        return this->tcpClient->alive();
    }
}


/**
* @description: 发送请求
* @param {string} RequestId  UUID
* @param {string} CommandEnum 命令枚举
* @param {string&} data  数据
* @param {function<void(std::string)>} t 回调函数（请求结果, 返回的数据）
* @return {*}
*/    
void TcpPlugin::sendRequest(std::string RequestId,std::string CommandEnum, std::string& data,function<void(int, std::string)> t){
    this->tcpClient->sendRequest(RequestId, CommandEnum, data, t);
}