#include "servicemanager.h"

#include <QDebug>

ServiceManager::ServiceManager(DWORD flags): flags(flags)
{

}

bool ServiceManager::Open()
{
    schSCManager = OpenSCManager(
                       NULL,                    // local computer
                       NULL,                    // ServicesActive database
                       flags);  // full access rights
    if (NULL == schSCManager) {
        qDebug() << "OpenSCManager failed" << GetLastError();
        return false;
    }
    return true;
}

bool ServiceManager::Exist(const QString &serviceName)
{
    bool exist = false;
    SC_HANDLE serviceHandle = OpenService(schSCManager,
                                          serviceName.toStdWString().c_str(),
                                          GENERIC_READ);
    if (!serviceHandle) {
        if (ERROR_SERVICE_DOES_NOT_EXIST != GetLastError()) {
            qCritical() << "OpenService failed";
        } else {
            qCritical() << "Service does not exist";
        }
    } else {
        exist = true;
        CloseServiceHandle(serviceHandle);
    }

    return exist;
}

bool ServiceManager::IsRunning(const QString &serviceName)
{
    DWORD dwSize;
    SERVICE_STATUS_PROCESS ssStatus;
    SC_HANDLE serviceHandle = OpenService(schSCManager,
                                          serviceName.toStdWString().c_str(),
                                          GENERIC_READ);
    if (!serviceHandle) {
        if (ERROR_SERVICE_DOES_NOT_EXIST != GetLastError()) {
            qCritical() << "OpenService failed";
        } else {
            qCritical() << "Service does not exist";
        }
        return false;
    }

    QueryServiceStatusEx(
        serviceHandle,
        SC_STATUS_PROCESS_INFO,
        (LPBYTE) &ssStatus,
        sizeof(ssStatus),
        &dwSize
    );

    CloseServiceHandle(serviceHandle);

    if (ssStatus.dwCurrentState != SERVICE_RUNNING) {
        qCritical() << "Service status error" << ssStatus.dwCurrentState;
        return false;
    }
    return true;
}

// need SC_MANAGER_ALL_ACCESS
void ServiceManager::Start(const QString &serviceName)
{
    SC_HANDLE serviceHandle = OpenService(schSCManager,
                                          serviceName.toStdWString().c_str(),
                                          SC_MANAGER_ALL_ACCESS);
    if (!serviceHandle) {
        if (ERROR_SERVICE_DOES_NOT_EXIST != GetLastError()) {
            qCritical() << "OpenService failed";
        } else {
            qCritical() << "Service does not exist";
        }
    } else {
        if (!StartService(serviceHandle, NULL, NULL)) {
            qCritical() << "StartService " << GetLastError();
        }
        CloseServiceHandle(serviceHandle);
    }
}

void ServiceManager::Stop(const QString &serviceName)
{
    SC_HANDLE serviceHandle = OpenService(schSCManager,
                                          serviceName.toStdWString().c_str(),
                                          SC_MANAGER_ALL_ACCESS);
    if (!serviceHandle) {
        if (ERROR_SERVICE_DOES_NOT_EXIST != GetLastError()) {
            qCritical() << "OpenService failed";
        } else {
            qCritical() << "Service does not exist";
        }
    } else {
        SERVICE_STATUS ss;
        if (!ControlService(serviceHandle, SERVICE_CONTROL_STOP, &ss)) {
            qCritical() << "StartService " << GetLastError();
        }
        CloseServiceHandle(serviceHandle);
    }
}

void ServiceManager::Install(const QString &serviceName, const QString &path)
{
    // Create the service
    SC_HANDLE schService = CreateService(
                               schSCManager,              // SCM database
                               serviceName.toStdWString().c_str(),             // name of service
                               serviceName.toStdWString().c_str(),             // service name to display
                               SERVICE_ALL_ACCESS,        // desired access
                               SERVICE_WIN32_OWN_PROCESS, // service type
                               SERVICE_AUTO_START,        // start type
                               SERVICE_ERROR_NORMAL,      // error control type
                               path.toStdWString().c_str(),                    // path to service's binary
                               NULL,                      // no load ordering group
                               NULL,                      // no tag identifier
                               NULL,                      // no dependencies
                               NULL,                      // LocalSystem account
                               NULL);                     // no password
    if (schService == NULL) {
        qDebug() << "CreateService failed" << GetLastError();
        return;
    }

    StartService(schService, NULL, NULL);
    CloseServiceHandle(schService);
}



