#include "eventsink.h"

#include <QDebug>
#include <QDateTime>
#include <QThread>

#include "variant.h"
#include "wmiobject.h"

#pragma comment(lib, "wbemuuid.lib")

namespace Win
{

ULONG EventSink::AddRef()
{
    return InterlockedIncrement(&m_lRef);
}

ULONG EventSink::Release()
{
    LONG lRef = InterlockedDecrement(&m_lRef);
    if (lRef == 0) {
        delete this;
    }
    return lRef;
}

HRESULT EventSink::QueryInterface(REFIID riid, void **ppv)
{
    if (riid == IID_IUnknown || riid == IID_IWbemObjectSink) {
        *ppv = (IWbemObjectSink *) this;
        AddRef();
        return WBEM_S_NO_ERROR;
    } else { return E_NOINTERFACE; }
}

HRESULT EventSink::Indicate(long lObjectCount,
                            IWbemClassObject **apObjArray)
{
    HRESULT hr = S_OK;
    _variant_t vtProp;

    for (int i = 0; i < lObjectCount; i++) {
        bool CreateorDel = false;
        _variant_t cn;
        QString LClassStr;
        hr = apObjArray[i]->Get(_bstr_t(TEXT("__Class")), 0, &cn, 0, 0);
        if (SUCCEEDED(hr)) {
            LClassStr = QString::fromStdWString(cn.bstrVal);
            if (LClassStr == (QStringLiteral("__InstanceDeletionEvent"))) {
//                qDebug() << "Deletion" << endl;
                CreateorDel = true;
            } else if (LClassStr == (QStringLiteral("__InstanceCreationEvent"))) {
//                qDebug() << "Creation" << endl;
                CreateorDel = true;
            } else {
                CreateorDel = false;
                //wcout << "Modification " << endl;
            }
        }
        VariantClear(&cn);

        if (CreateorDel) {
            hr = apObjArray[i]->Get(_bstr_t(L"TargetInstance"), 0, &vtProp, 0, 0);
            if (!FAILED(hr)) {
                IUnknown *str = vtProp;
                hr = str->QueryInterface(IID_IWbemClassObject, reinterpret_cast< void ** >(&apObjArray[i]));
                if (SUCCEEDED(hr)) {
//                    dumpWmiObj(apObjArray[i]);

//                  VT_BSTR "CreationDate" : "20180428143252.768460+480"
//                  VT_BSTR "ExecutablePath" : "D:\\Share\\deepin-legalization-checker.exe"
//                  VT_BSTR "CommandLine" : "\"C:\\Program Files (x86)\\360\\360sd\\360sd.exe\" /autorun"

                    QMap<QString, QVariant> data;
                    _variant_t cn;
                    hr = apObjArray[i]->Get(TEXT("ExecutablePath"), 0, &cn, NULL, NULL);
                    auto ExecutablePath = Win::qVariant(cn).toString();
                    data.insert(QStringLiteral("ExecutablePath"), ExecutablePath);
                    VariantClear(&cn);

                    hr = apObjArray[i]->Get(TEXT("CommandLine"), 0, &cn, NULL, NULL);
                    auto CommandLine = Win::qVariant(cn).toString();
                    data.insert(QStringLiteral("CommandLine"), CommandLine);
                    VariantClear(&cn);

                    hr = apObjArray[i]->Get(TEXT("ProcessId"), 0, &cn, NULL, NULL);
                    auto  ProcessId = Win::qVariant(cn).toInt();
                    data.insert(QStringLiteral("ProcessId"), ProcessId);
                    VariantClear(&cn);

                    hr = apObjArray[i]->Get(TEXT("CreationDate"), 0, &cn, NULL, NULL);
                    // "20180210061925.000000+480"
                    auto  timeStr = Win::qVariant(cn).toString();
                    auto CreationDate = QDateTime::fromString(timeStr.split(".").value(0), "yyyyMMddhhmmss");
                    data.insert(QStringLiteral("CreationDate"), qlonglong(CreationDate.toMSecsSinceEpoch()));
                    VariantClear(&cn);

                    Q_EMIT m_wmiObj->wmiEventIndicate(LClassStr, data);
                }
            }
            VariantClear(&vtProp);
        }

    }

    return WBEM_S_NO_ERROR;
}

HRESULT EventSink::SetStatus(
    /* [in] */ LONG lFlags,
    /* [in] */ HRESULT hResult,
    /* [in] */ BSTR strParam,
    /* [in] */ IWbemClassObject __RPC_FAR *pObjParam
)
{
    if (lFlags == WBEM_STATUS_COMPLETE) {
        qDebug() << "Call complete. hResult = 0x%X\n" << hResult;
    } else if (lFlags == WBEM_STATUS_PROGRESS) {
        qDebug() << ("Call in progress.\n");
    }

    return WBEM_S_NO_ERROR;
}
}
