#include "tool.h"

#include <QCoreApplication>
#include <QtConcurrent>
#include <QDateTime>

#ifdef Q_OS_WIN
#include <Windows.h>
#endif

#ifdef Q_OS_LINUX
#include <iwlib.h>
#endif

namespace Tool
{

int randBetween(int low, int high) {
    qsrand(static_cast<uint>(QTime::currentTime().msec()));
    return qrand() % ((high + 1) - low) + low;
}

/*
 * wps-office license file save in "/home/xxx/.kingsoft/office6/data/license2.dat"
 *
 *THUV2-32HH7-6NMHN-PTX7Y-QQCTH
 *7LR67-WTXPA-KLUHV-GEK2E-QW4CK
 *EUYTH-3KWKL-PJMX7-XBCPW-9U2DD
 *R8R8P-MTT6F-KLRPM-J7CAB-PJM8C
*/
QStringList getWPSProductkeys(QString productkeyPath)
{
    QString keys = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    QStringList productKeys;

    QFile f(productkeyPath);
    if (f.open(QIODevice::ReadOnly)) {
        QByteArray r = f.readAll();
        QList<int> indexs;
        QMap<int, char> words;
        for (int i = 0 ; i < r.count(); i++) {
            char c = r.at(i);
            if (keys.contains(QChar(c))) {
                words.insert(i, c);
                indexs.append(i);
            }
        }

        QList<QList<int>> sequenceNumbers;
        for (int i = 0; i <= indexs.count() - 25; i++) {
            QList<int> sequenceNumber = indexs.mid(i, 25);
            if (sequenceNumber.count() == 25 && Tool::isSequenceList(sequenceNumber, 2)) {
                i += 24;
                sequenceNumbers << sequenceNumber;
            }
        }
        for (auto &sequenceNumber : sequenceNumbers) {
            QString productkey;
            for (int i = 0; i < sequenceNumber.count() ; i++) {
                char w = words.value(sequenceNumber.at(i));
                productkey += w;
                if ((i + 1) % 5 == 0 && (i + 1) != 25) {
                    productkey += "-";
                }
            }
            productKeys << productkey;
        }
    }
    f.close();
    return productKeys;
}


#ifdef Q_OS_WIN
bool setSingleInstance(const QString &key)
{
    HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, 0, key.toStdWString().c_str());
    if (!hMutex) {
        hMutex = CreateMutex(0, 0, key.toStdWString().c_str());
        return (hMutex != NULL);
    } else {
        return false;
    }
}

bool isWireless(const char *)
{
    return false;
}

#endif

#ifdef Q_OS_LINUX
static bool tryAcquireSystemSemaphore(QSystemSemaphore *ss, qint64 timeout = 10)
{
    if (ss->error() != QSystemSemaphore::NoError) {
        return false;
    }

    QSystemSemaphore _tmp_ss(QString("%1-%2").arg("DTK::tryAcquireSystemSemaphore").arg(ss->key()), 1, QSystemSemaphore::Open);

    _tmp_ss.acquire();

    QElapsedTimer t;
    QFuture<bool> request = QtConcurrent::run(ss, &QSystemSemaphore::acquire);

    t.start();

    while (Q_LIKELY(t.elapsed() < timeout && !request.isFinished()));

    if (request.isFinished()) {
        return true;
    }

    if (Q_LIKELY(request.isRunning())) {
        if (Q_LIKELY(ss->release(1))) {
            request.waitForFinished();
        }
    }

    return false;
}

bool setSingleInstance(const QString &key)
{
    static QSystemSemaphore ss(key, 1, QSystemSemaphore::Open);
    static bool singleInstance = false;

    if (singleInstance) {
        return true;
    }

    Q_ASSERT_X(ss.error() == QSystemSemaphore::NoError, "DApplicationPrivate::setSingleInstanceBySemaphore:", ss.errorString().toLocal8Bit().constData());

    singleInstance = tryAcquireSystemSemaphore(&ss);

    if (singleInstance) {
        QtConcurrent::run([] {
            QPointer<QCoreApplication> that = qApp;

            while (ss.acquire() && singleInstance)
            {
                if (!that) {
                    return;
                }

                if (that->startingUp() || that->closingDown()) {
                    break;
                }

                ss.release(1);
            }
        });

        auto clean_fun = [] {
            ss.release(1);
            singleInstance = false;
        };

        qAddPostRoutine(clean_fun);
        atexit(clean_fun);
    }

    return singleInstance;
}

bool isWireless(const char *ifname)
{
    int sock = -1;
    struct iwreq pwrq;
    memset(&pwrq, 0, sizeof(pwrq));
    strncpy(pwrq.ifr_name, ifname, IFNAMSIZ);
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        return false;
    }
    if (ioctl(sock, SIOCGIWNAME, &pwrq) != -1) {
        close(sock);
        return true;
    }
    close(sock);
    return false;
}

#endif


QString getVersion()
{
    qDebug() << "current version: " << PROJECT_VERSION;
    return PROJECT_VERSION;
}

void cleanOldVersion()
{
    QString applicationDir =  QFileInfo(qApp->applicationFilePath()).absolutePath();
    QString projectDir = QFileInfo(applicationDir).absolutePath();

    for (auto &info : QDir(projectDir).entryInfoList(QDir::NoDotAndDotDot | QDir::AllDirs)) {
        if (info.fileName() != PROJECT_VERSION) {
            bool ret = QDir(info.filePath()).removeRecursively();
            qDebug() << "remove dir:" << info.filePath() << ret;
        }
    }
}


bool isSequenceList(QList<int> data, int difference)
{
    for (int i = 0; i < data.count() - 1; i++) {
        if (data[i + 1] - data[i] != difference) {
            return false;
        }
    }
    return true;
}

}
