/*
* Copyright (C) 2021, KylinSoft Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/&gt;.
*
*/

#include <QThread>

#include "network_device_detector.h"
#include "zconfservicebrowser.h"
#include "snmpwalk_browser.h"
#include "common.h"

QString getValueBySnmpwalk(const QString &name, const QString &key)
{
    std::string sname = name.toStdString();
    std::string skey = key.toStdString();

    const char * cname = sname.c_str();
    const char * ckey = skey.c_str();

    std::vector<OidNode> oids = {
        { ckey },
    };


    std::vector<HostNode> hosts = {
        { cname, "public" },
    };

    std::vector<std::string> buf;

    if (::snmpwalkBrowser_initialize(oids) != STAT_SUCCESS) {
        return QString ("error");
    }
    int ans = ::snmpwalkBrowser_synchronous(buf, hosts, oids);
    if (ans != STAT_SUCCESS) {
        return QString("error");
    }
    if (!buf.size()) {
        return QString("error");
    }
    QString res =  QString(buf.at(0).c_str());

    if (res.contains("IpAddress")
     || res.contains("STRING")) {

        res = res.split(":").at(1);
        res.remove(0,1);
        res.remove("\"");
        return res;
    }
    return "";
}

// *****************************************************
// NetworkDeviceDetector start
NetworkDeviceDetector::~NetworkDeviceDetector()
{

}

NetworkDeviceDetector::NetworkDeviceDetector(/* args */)
{
    /**
     * @brief zconfserver循环事件
     *
     */
    connect(ZConfServiceBrowser::getInstance(), &ZConfServiceBrowser::serviceEntryAdded,
            this, &NetworkDeviceDetector::zconfPreSet,
            Qt::QueuedConnection);

    connect (this, &NetworkDeviceDetector::autoDetectStart, [=](){


        ZConfServiceBrowser::getInstance()->browse();
    });

    connect (this, &NetworkDeviceDetector::autoDetectStop, [=](){

//        m_thread->deleteLater();
    });

    connect (this, &NetworkDeviceDetector::newDeviceSend,
             this, &NetworkDeviceDetector::newDeviceGet,
             Qt::QueuedConnection);
}

DetectResult NetworkDeviceDetector::detectNetWorkNode(DeviceInformation &deviceInfo)
{
    deviceInfo.networkNode = ::getValueBySnmpwalk(deviceInfo.host, "1.3.6.1.2.1.1.5");
    if (deviceInfo.networkNode.isEmpty()) {
        return DetectResult::DETECT_ERROR;
    }
    return DetectResult::DETECT_OK;
}

DetectResult NetworkDeviceDetector::detectVendorAndModel(DeviceInformation &deviceInfo)
{

    QString res = ::getValueBySnmpwalk(deviceInfo.host, "1.3.6.1.2.1.25.3.2.1.3");

    if (res.isEmpty() || res == "error") {
        return DetectResult::DETECT_ERROR;
    }
    // Brother ADS-3600W
    if (res.contains(' ')) {
        deviceInfo.vendor = res.left(res.indexOf(' '));
        deviceInfo.model =  res.right(res.size() - 1 - res.indexOf(' '));
    } else {
        deviceInfo.vendor = res;
    }


    return DetectResult::DETECT_OK;
}

DetectResult NetworkDeviceDetector::detectSerial(DeviceInformation &deviceInfo)
{
    deviceInfo.serial = ::getValueBySnmpwalk(deviceInfo.host, "1.3.6.1.2.1.43.5.1.1.17");
    if (deviceInfo.serial.isEmpty()) {
        return DetectResult::DETECT_ERROR;
    }
    return DetectResult::DETECT_OK;
}


DeviceInformation NetworkDeviceDetector::newDeviceGet(DeviceInformation &deviceInfo)
{

     if (deviceInfo.host.isEmpty())
        return DeviceInformation();


    if (deviceInfo.host == "error") {
        deviceInfo.connectType = ConnectType::InfoFrom_Invalid;
        return DeviceInformation();
    }

    if (deviceInfo.host.isEmpty()) {
        deviceInfo.connectType = ConnectType::InfoFrom_Invalid;
        return DeviceInformation();
    }

    if (!ipIsValid(deviceInfo.host)) {
        deviceInfo.connectType = ConnectType::InfoFrom_Invalid;
        return DeviceInformation();
    }

    this->detectVendorAndModel (deviceInfo);
    this->detectSerial         (deviceInfo);

    if (deviceInfo.vendor.isEmpty()
     || deviceInfo.model.isEmpty()  ) {

        deviceInfo.connectType = ConnectType::InfoFrom_Invalid;
    }


    switch (deviceInfo.connectType)
    {
    case (ConnectType::InfoFrom_Invalid):
    case (ConnectType::InfoFrom_USB):
        return DeviceInformation();

    case (ConnectType::InfoFrom_NETWORK_DETECT):
        emit this->findNetworkConnect(deviceInfo);
        return DeviceInformation();
    case (ConnectType::InfoFrom_PRINTER_IP):
        return deviceInfo;
    }

    return DeviceInformation();
}

void NetworkDeviceDetector::zconfPreSet(QString name) {
    DeviceInformation deviceInfo;
    qDebug() << name;
    deviceInfo.connectType = ConnectType::InfoFrom_NETWORK_DETECT;
    deviceInfo.host = ZConfServiceBrowser::getInstance()->serviceEntry(name).ip;

    emit this->newDeviceSend(deviceInfo);
    return ;
}
