/*
 * SPDX-FileCopyrightText: 2025 Copyright contributors to the cppTango project
 *
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */
#include <tango/windows/NTEventLogger.h>

#include <tango/internal/windows.h>

#include <tango/server/Except.h>

#include <iostream>

namespace Tango
{

// ----------------------------------------------------------------------
// NTEventLogger private and protected member implementation
// ----------------------------------------------------------------------

void NTEventLogger::emitMessage(int eventType, const char *msg)
{
    const char *strings[1];

    strings[0] = msg;

    ::ReportEvent(eventSource_, // handle of event source
                  eventType,    // event type
                  0,            // event logger
                  eventId_,     // event ID
                  nullptr,      // current user's SID
                  1,            // strings in lpszStrings
                  0,            // no bytes of raw data
                  strings,      // array of error strings
                  nullptr);     // no raw data
}

bool NTEventLogger::installValues(HKEY key)
{
    char path[512];

    //
    // Get path to executable.
    //

    if(::GetModuleFileName(nullptr, path, sizeof(path)) == 0)
    {
        CORBA::String_var err = GetErrorText();
        std::cerr << "GetModuleFileName failed: " << err.in() << std::endl;
        return false;
    }

    const char *keyname;

    //
    // Add two keys EventMessageFile which contains the path to the
    // resources file, and TypesSupported which contains a DWORD with
    // the permitted event types.
    //

    keyname = "EventMessageFile";
    if(::RegSetValueEx(key, keyname, 0, REG_SZ, (unsigned char *) path, strlen(path) + 1) == ERROR_SUCCESS)
    {
        DWORD supported = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
        keyname = "TypesSupported";
        if(::RegSetValueEx(key, "TypesSupported", 0, REG_DWORD, (unsigned char *) &supported, sizeof(supported)) ==
           ERROR_SUCCESS)
        {
            return true;
        }
    }

    CORBA::String_var err = GetErrorText();
    std::cerr << "RegSetValueEx " << keyname << " failed: " << err.in() << std::endl;
    return false;
}

// ----------------------------------------------------------------------
// NTEventLogger constructor/destructor
// ----------------------------------------------------------------------

NTEventLogger::NTEventLogger(const char *service, DWORD eventId) :
    service_(service),
    eventId_(eventId)
{
    eventSource_ = ::RegisterEventSource(nullptr, service);
    if(eventSource_ == 0)
    {
        TANGO_THROW_EXCEPTION(API_DatabaseAccess, "RegisterEventsource failed");
    }
}

NTEventLogger::~NTEventLogger()
{
    ::DeregisterEventSource(eventSource_);
}

// ----------------------------------------------------------------------
// NTEventLogger public member implementation
// ----------------------------------------------------------------------

bool NTEventLogger::install()
{
    //
    // Constructor the key name
    //

    std::string keyName("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\");
    keyName += service_;

    //
    // The key goes into HKEY_LOCAL_MACHINE
    //

    HKEY regHandle = HKEY_LOCAL_MACHINE;

    //
    // First try to open the key.
    //

    HKEY keyHandle;
    if(::RegOpenKeyEx(regHandle, keyName.c_str(), 0, KEY_ALL_ACCESS, &keyHandle) != ERROR_SUCCESS)
    {
        //
        // Create the key
        //
        DWORD d;
        if(::RegCreateKeyEx(
               regHandle, keyName.c_str(), 0, "REG_SZ", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &keyHandle, &d) !=
           ERROR_SUCCESS)
        {
            CORBA::String_var err = GetErrorText();
            std::cerr << "RegCreateKeyEx " << keyName.c_str() << " failed: " << err.in() << std::endl;
            return false;
        }
    }

    bool rc = installValues(keyHandle);

    ::RegCloseKey(keyHandle);

    return rc;
}

bool NTEventLogger::uninstall()
{
    //
    // Constructor the key name
    //

    std::string keyName("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\");
    keyName += service_;

    return ::RegDeleteKey(HKEY_LOCAL_MACHINE, keyName.c_str()) == ERROR_SUCCESS;
}

void NTEventLogger::info(const char *msg)
{
    emitMessage(EVENTLOG_INFORMATION_TYPE, msg);
}

void NTEventLogger::error(const char *msg)
{
    emitMessage(EVENTLOG_ERROR_TYPE, msg);
}

void NTEventLogger::warning(const char *msg)
{
    emitMessage(EVENTLOG_WARNING_TYPE, msg);
}

void NTEventLogger::trace(const char *logger, const char *msg)
{
    std::string s(logger);
    s += ": ";
    s += msg;
    emitMessage(EVENTLOG_INFORMATION_TYPE, s.c_str());
}

} // namespace Tango
