#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <ctype.h>
#include <stdbool.h>
#include <string.h>

// from winnt.h
#define EVENTLOG_SUCCESS 0x0000
#define EVENTLOG_ERROR_TYPE 0x0001
#define EVENTLOG_WARNING_TYPE 0x0002
#define EVENTLOG_INFORMATION_TYPE 0x0004
#define EVENTLOG_AUDIT_SUCCESS 0x0008
#define EVENTLOG_AUDIT_FAILURE 0x0010

// the severities we define in .mc file
#define STATUS_SEVERITY_INFORMATIONAL 0x1
#define STATUS_SEVERITY_WARNING 0x2
#define STATUS_SEVERITY_ERROR 0x3

#define FACILITY_APPLICATION 0x0fff

#include "nd_log-common.h"
#include "nd_log-to-windows-common.h"

const char *get_msg_symbol(MESSAGE_ID msg) {
    switch(msg) {
        case MSGID_MESSAGE_ONLY:
            return "MESSAGE_ONLY";

        case MSGID_MESSAGE_ERRNO:
            return "MESSAGE_ERRNO";

        case MSGID_REQUEST_ONLY:
            return "REQUEST_ONLY";

        case MSGID_ACCESS_MESSAGE:
            return "ACCESS_MESSAGE";

        case MSGID_ACCESS_MESSAGE_REQUEST:
            return "ACCESS_MESSAGE_REQUEST";

        case MSGID_ACCESS_MESSAGE_USER:
            return "ACCESS_MESSAGE_USER";

        case MSGID_ACCESS:
            return "ACCESS";

        case MSGID_ACCESS_USER:
            return "ACCESS_USER";

        case MSGID_ACCESS_FORWARDER:
            return "ACCESS_FORWARDER";

        case MSGID_ACCESS_FORWARDER_USER:
            return "ACCESS_FORWARDER_USER";

        case MSGID_ALERT_TRANSITION:
            return "ALERT_TRANSITION";

        default:
            fprintf(stderr, "\n\nInvalid message id %d!\n\n\n", msg);
            exit(1);
    }
}

const char *get_msg_format(MESSAGE_ID msg) {
    switch(msg) {
        case MSGID_MESSAGE_ONLY:
            return "%2(%12): %64\r\n";

        case MSGID_MESSAGE_ERRNO:
            return "%2(%12): %64%n\r\n"
                   "%n\r\n"
                   "  Unix Errno   : %5%n\r\n"
                   "  Windows Error: %6%n\r\n"
                   ;

        case MSGID_REQUEST_ONLY:
            return "%2(%12): %63\r\n";

        case MSGID_ACCESS_MESSAGE:
            return "%64\r\n";

        case MSGID_ACCESS_MESSAGE_REQUEST:
            return "%64%n\r\n"
                   "%n\r\n"
                   "  Request: %63%n\r\n"
                    ;

        case MSGID_ACCESS_MESSAGE_USER:
            return "%64%n\r\n"
                   "%n\r\n"
                   "  User: %21, role: %22, permissions: %23%n\r\n"
                   ;

        case MSGID_ACCESS:
            return "%33 %63%n\r\n"
                   "%n\r\n"
                   "  Response Code : %34%n\r\n"
                   "  Transaction ID: %36%n\r\n"
                   "  Source IP     : %24%n\r\n"
                   ;

        case MSGID_ACCESS_USER:
            return "%33 %63%n\r\n"
                   "%n\r\n"
                   "  Response Code : %34%n\r\n"
                   "  Transaction ID: %36%n\r\n"
                   "  Source IP     : %24%n\r\n"
                   "  User          : %21, role: %22, permissions: %23%n\r\n"
                   ;

        case MSGID_ACCESS_FORWARDER:
            return "%33 %63%n\r\n"
                   "%n\r\n"
                   "  Response Code : %34%n\r\n"
                   "  Transaction ID: %36%n\r\n"
                   "  Source IP     : %24, For %27%n\r\n"
                   ;

        case MSGID_ACCESS_FORWARDER_USER:
            return "%33 %63%n\r\n"
                   "%n\r\n"
                   "  Response Code : %34%n\r\n"
                   "  Transaction ID: %36%n\r\n"
                   "  Source IP     : %24, For %27%n\r\n"
                   "  User          : %21, role: %22, permissions: %23%n\r\n"
                   ;

        case MSGID_ALERT_TRANSITION:
            return "Alert '%47' of instance '%16' on node '%15' transitioned from %57 to %56\r\n";

        default:
            fprintf(stderr, "\n\nInvalid message id %d!\n\n\n", msg);
            exit(1);
    }
}

int main(int argc, const char **argv) {
    (void)argc; (void)argv;

    const char *header = NULL, *footer = NULL, *s_header = NULL, *s_footer = NULL;

    bool manifest = false;
    if(argc == 2 && strcmp(argv[1], "--manifest") == 0) {
        manifest = true;

        header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
                 "<!--\r\n"
                 "\r\n"
                 "    THIS FILE IS AUTOMATICALLY GENERATED - DO NOT EDIT\r\n"
                 "\r\n"
                 "    This XML file can be verified by running mc.exe (the MS tool) with this manifest as param.\r\n"
                 "\r\n"
                 "    \"c:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.26100.0\\x64\\mc.exe\" wevt_netdata_manifest.xml wevt_netdata.mc\r\n"
                 "\r\n"
                 " -->\r\n"
                 "<instrumentationManifest\r\n"
                 "        xmlns=\"http://schemas.microsoft.com/win/2004/08/events\"\r\n"
                 "        xmlns:win=\"http://manifests.microsoft.com/win/2004/08/windows/events\"\r\n"
                 "        xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\r\n"
                 "    <instrumentation>\r\n"
                 "        <events>\r\n"
                 "\r\n"
                 "            <provider name=\"" NETDATA_ETW_PROVIDER_NAME "\"\r\n"
                 "                      guid=\"" NETDATA_ETW_PROVIDER_GUID_STR "\"\r\n"
                 "                      symbol=\"NETDATA_ETW_PROVIDER_GUID\"\r\n"
                 "                      messageFileName=\"%SystemRoot%\\System32\\wevt_netdata.dll\"\r\n"
                 "                      resourceFileName=\"%SystemRoot%\\System32\\wevt_netdata.dll\"\r\n"
                 "                      message=\"$(string.ND_PROVIDER_NAME)\">\r\n"
                 "\r\n"
                 "                <!-- Define the provider sub-channels -->\r\n"
                 "                <channels>\r\n"
                 "                    <channel name=\"" NETDATA_ETW_CHANNEL_NAME "/" NETDATA_ETW_SUBCHANNEL_DAEMON "\"\r\n"
                 "                             symbol=\"CHANNEL_DAEMON\"\r\n"
                 "                             type=\"Operational\"\r\n"
                 "                             message=\"$(string.Channel.Daemon)\"\r\n"
                 "                             enabled=\"true\"\r\n"
                 "                             />\r\n"
                 "\r\n"
                 "                    <channel name=\"" NETDATA_ETW_CHANNEL_NAME "/" NETDATA_ETW_SUBCHANNEL_COLLECTORS "\"\r\n"
                 "                             symbol=\"CHANNEL_COLLECTORS\"\r\n"
                 "                             type=\"Operational\"\r\n"
                 "                             message=\"$(string.Channel.Collectors)\"\r\n"
                 "                             enabled=\"true\"\r\n"
                 "                             />\r\n"
                 "\r\n"
                 "                    <channel name=\"" NETDATA_ETW_CHANNEL_NAME "/" NETDATA_ETW_SUBCHANNEL_ACCESS "\"\r\n"
                 "                             symbol=\"CHANNEL_ACCESS\"\r\n"
                 "                             type=\"Operational\"\r\n"
                 "                             message=\"$(string.Channel.Access)\"\r\n"
                 "                             enabled=\"true\"\r\n"
                 "                             />\r\n"
                 "\r\n"
                 "                    <channel name=\"" NETDATA_ETW_CHANNEL_NAME "/" NETDATA_ETW_SUBCHANNEL_HEALTH "\"\r\n"
                 "                             symbol=\"CHANNEL_HEALTH\"\r\n"
                 "                             type=\"Operational\"\r\n"
                 "                             message=\"$(string.Channel.Health)\"\r\n"
                 "                             enabled=\"true\"\r\n"
                 "                             />\r\n"
                 "\r\n"
                 "                    <channel name=\"" NETDATA_ETW_CHANNEL_NAME "/" NETDATA_ETW_SUBCHANNEL_ACLK "\"\r\n"
                 "                             symbol=\"CHANNEL_ACLK\"\r\n"
                 "                             type=\"Operational\"\r\n"
                 "                             message=\"$(string.Channel.Aclk)\"\r\n"
                 "                             enabled=\"true\"\r\n"
                 "                             />\r\n"
                 "                </channels>\r\n"
                 "\r\n"
                 "                <levels>\r\n"
                 "                </levels>\r\n"
                 "\r\n"
                 "                <opcodes>\r\n"
                 "                </opcodes>\r\n"
                 "\r\n"
                 "                <tasks>\r\n"
                 "                </tasks>\r\n"
                 "\r\n"
                 "                <templates>\r\n"
                 "                    <template tid=\"AllFieldsTemplate\">\r\n"
                 "                        <!-- 0 (NDF_STOP) should not be here %1 is Timestamp, %64 is the Message -->\r\n"
                 "                        <data name=\"Timestamp\" inType=\"win:UnicodeString\"/>           <!-- 1 (NDF_TIMESTAMP_REALTIME_USEC) -->\r\n"
                 "                        <data name=\"Program\" inType=\"win:UnicodeString\"/>             <!-- 2 (NDF_SYSLOG_IDENTIFIER) -->\r\n"
                 "                        <data name=\"NetdataLogSource\" inType=\"win:UnicodeString\"/>    <!-- 3 (NDF_LOG_SOURCE) -->\r\n"
                 "                        <data name=\"Level\" inType=\"win:UnicodeString\"/>               <!-- 4 (NDF_PRIORITY) -->\r\n"
                 "                        <data name=\"UnixErrno\" inType=\"win:UnicodeString\"/>           <!-- 5 (NDF_ERRNO) -->\r\n"
                 "                        <data name=\"WindowsLastError\" inType=\"win:UnicodeString\"/>    <!-- 6 (NDF_WINERROR) -->\r\n"
                 "                        <data name=\"InvocationID\" inType=\"win:UnicodeString\"/>        <!-- 7 (NDF_INVOCATION_ID) -->\r\n"
                 "                        <data name=\"CodeLine\" inType=\"win:UnicodeString\"/>                   <!-- 8 (NDF_LINE) -->\r\n"
                 "                        <data name=\"CodeFile\" inType=\"win:UnicodeString\"/>            <!-- 9 (NDF_FILE) -->\r\n"
                 "                        <data name=\"CodeFunction\" inType=\"win:UnicodeString\"/>        <!-- 10 (NDF_FUNC) -->\r\n"
                 "                        <data name=\"ThreadID\" inType=\"win:UnicodeString\"/>                   <!-- 11 (NDF_TID) -->\r\n"
                 "                        <data name=\"ThreadName\" inType=\"win:UnicodeString\"/>          <!-- 12 (NDF_THREAD_TAG) -->\r\n"
                 "                        <data name=\"MessageID\" inType=\"win:UnicodeString\"/>           <!-- 13 (NDF_MESSAGE_ID) -->\r\n"
                 "                        <data name=\"Module\" inType=\"win:UnicodeString\"/>              <!-- 14 (NDF_MODULE) -->\r\n"
                 "                        <data name=\"Node\" inType=\"win:UnicodeString\"/>                <!-- 15 (NDF_NIDL_NODE) -->\r\n"
                 "                        <data name=\"Instance\" inType=\"win:UnicodeString\"/>            <!-- 16 (NDF_NIDL_INSTANCE) -->\r\n"
                 "                        <data name=\"Context\" inType=\"win:UnicodeString\"/>             <!-- 17 (NDF_NIDL_CONTEXT) -->\r\n"
                 "                        <data name=\"Dimension\" inType=\"win:UnicodeString\"/>           <!-- 18 (NDF_NIDL_DIMENSION) -->\r\n"
                 "                        <data name=\"SourceTransport\" inType=\"win:UnicodeString\"/>     <!-- 19 (NDF_SRC_TRANSPORT) -->\r\n"
                 "                        <data name=\"AccountID\" inType=\"win:UnicodeString\"/>           <!-- 20 (NDF_ACCOUNT_ID) -->\r\n"
                 "                        <data name=\"UserName\" inType=\"win:UnicodeString\"/>            <!-- 21 (NDF_USER_NAME) -->\r\n"
                 "                        <data name=\"UserRole\" inType=\"win:UnicodeString\"/>            <!-- 22 (NDF_USER_ROLE) -->\r\n"
                 "                        <data name=\"UserPermissions\" inType=\"win:UnicodeString\"/>     <!-- 23 (NDF_USER_ACCESS) -->\r\n"
                 "                        <data name=\"SourceIP\" inType=\"win:UnicodeString\"/>            <!-- 24 (NDF_SRC_IP) -->\r\n"
                 "                        <data name=\"SourceForwardedHost\" inType=\"win:UnicodeString\"/> <!-- 25 (NDF_SRC_PORT) -->\r\n"
                 "                        <data name=\"SourceForwardedFor\" inType=\"win:UnicodeString\"/>  <!-- 26 (NDF_SRC_FORWARDED_HOST) -->\r\n"
                 "                        <data name=\"SourcePort\" inType=\"win:UnicodeString\"/>                 <!-- 27 (NDF_SRC_FORWARDED_FOR) -->\r\n"
                 "                        <data name=\"SourceCapabilities\" inType=\"win:UnicodeString\"/>  <!-- 28 (NDF_SRC_CAPABILITIES) -->\r\n"
                 "                        <data name=\"DestinationTransport\" inType=\"win:UnicodeString\"/> <!-- 29 (NDF_DST_TRANSPORT) -->\r\n"
                 "                        <data name=\"DestinationIP\" inType=\"win:UnicodeString\"/>       <!-- 30 (NDF_DST_IP) -->\r\n"
                 "                        <data name=\"DestinationPort\" inType=\"win:UnicodeString\"/>            <!-- 31 (NDF_DST_PORT) -->\r\n"
                 "                        <data name=\"DestinationCapabilities\" inType=\"win:UnicodeString\"/> <!-- 32 (NDF_DST_CAPABILITIES) -->\r\n"
                 "                        <data name=\"RequestMethod\" inType=\"win:UnicodeString\"/>       <!-- 33 (NDF_REQUEST_METHOD) -->\r\n"
                 "                        <data name=\"ResponseCode\" inType=\"win:UnicodeString\"/>               <!-- 34 (NDF_RESPONSE_CODE) -->\r\n"
                 "                        <data name=\"ConnectionID\" inType=\"win:UnicodeString\"/>        <!-- 35 (NDF_CONNECTION_ID) -->\r\n"
                 "                        <data name=\"TransactionID\" inType=\"win:UnicodeString\"/>       <!-- 36 (NDF_TRANSACTION_ID) -->\r\n"
                 "                        <data name=\"ResponseSentBytes\" inType=\"win:UnicodeString\"/>          <!-- 37 (NDF_RESPONSE_SENT_BYTES) -->\r\n"
                 "                        <data name=\"ResponseSizeBytes\" inType=\"win:UnicodeString\"/>          <!-- 38 (NDF_RESPONSE_SIZE_BYTES) -->\r\n"
                 "                        <data name=\"ResponsePreparationTimeUsec\" inType=\"win:UnicodeString\"/> <!-- 39 (NDF_RESPONSE_PREPARATION_TIME_USEC) -->\r\n"
                 "                        <data name=\"ResponseSentTimeUsec\" inType=\"win:UnicodeString\"/>       <!-- 40 (NDF_RESPONSE_SENT_TIME_USEC) -->\r\n"
                 "                        <data name=\"ResponseTotalTimeUsec\" inType=\"win:UnicodeString\"/>      <!-- 41 (NDF_RESPONSE_TOTAL_TIME_USEC) -->\r\n"
                 "                        <data name=\"AlertID\" inType=\"win:UnicodeString\"/>             <!-- 42 (NDF_ALERT_ID) -->\r\n"
                 "                        <data name=\"AlertUniqueID\" inType=\"win:UnicodeString\"/>       <!-- 43 (NDF_ALERT_UNIQUE_ID) -->\r\n"
                 "                        <data name=\"AlertTransitionID\" inType=\"win:UnicodeString\"/>   <!-- 44 (NDF_ALERT_TRANSITION_ID) -->\r\n"
                 "                        <data name=\"AlertEventID\" inType=\"win:UnicodeString\"/>        <!-- 45 (NDF_ALERT_EVENT_ID) -->\r\n"
                 "                        <data name=\"AlertConfig\" inType=\"win:UnicodeString\"/>         <!-- 46 (NDF_ALERT_CONFIG_HASH) -->\r\n"
                 "                        <data name=\"AlertName\" inType=\"win:UnicodeString\"/>           <!-- 47 (NDF_ALERT_NAME) -->\r\n"
                 "                        <data name=\"AlertClass\" inType=\"win:UnicodeString\"/>          <!-- 48 (NDF_ALERT_CLASS) -->\r\n"
                 "                        <data name=\"AlertComponent\" inType=\"win:UnicodeString\"/>      <!-- 49 (NDF_ALERT_COMPONENT) -->\r\n"
                 "                        <data name=\"AlertType\" inType=\"win:UnicodeString\"/>           <!-- 50 (NDF_ALERT_TYPE) -->\r\n"
                 "                        <data name=\"AlertExec\" inType=\"win:UnicodeString\"/>           <!-- 51 (NDF_ALERT_EXEC) -->\r\n"
                 "                        <data name=\"AlertRecipient\" inType=\"win:UnicodeString\"/>      <!-- 52 (NDF_ALERT_RECIPIENT) -->\r\n"
                 "                        <data name=\"AlertDuration\" inType=\"win:UnicodeString\"/>              <!-- 53 (NDF_ALERT_DURATION) -->\r\n"
                 "                        <data name=\"AlertValue\" inType=\"win:UnicodeString\"/>                 <!-- 54 (NDF_ALERT_VALUE) -->\r\n"
                 "                        <data name=\"AlertOldValue\" inType=\"win:UnicodeString\"/>              <!-- 55 (NDF_ALERT_VALUE_OLD) -->\r\n"
                 "                        <data name=\"AlertStatus\" inType=\"win:UnicodeString\"/>         <!-- 56 (NDF_ALERT_STATUS) -->\r\n"
                 "                        <data name=\"AlertOldStatus\" inType=\"win:UnicodeString\"/>      <!-- 57 (NDF_ALERT_STATUS_OLD) -->\r\n"
                 "                        <data name=\"Source\" inType=\"win:UnicodeString\"/>              <!-- 58 (NDF_ALERT_SOURCE) -->\r\n"
                 "                        <data name=\"AlertUnits\" inType=\"win:UnicodeString\"/>          <!-- 59 (NDF_ALERT_UNITS) -->\r\n"
                 "                        <data name=\"AlertSummary\" inType=\"win:UnicodeString\"/>        <!-- 60 (NDF_ALERT_SUMMARY) -->\r\n"
                 "                        <data name=\"AlertInfo\" inType=\"win:UnicodeString\"/>           <!-- 61 (NDF_ALERT_INFO) -->\r\n"
                 "                        <data name=\"AlertNotificationTime\" inType=\"win:UnicodeString\"/>      <!-- 62 (NDF_ALERT_NOTIFICATION_REALTIME_USEC) -->\r\n"
                 "                        <data name=\"Request\" inType=\"win:UnicodeString\"/>             <!-- 63 (NDF_REQUEST) -->\r\n"
                 "                        <data name=\"Message\" inType=\"win:UnicodeString\"/>             <!-- 64 (NDF_MESSAGE) -->\r\n"
                 "                        <data name=\"StackTrace\" inType=\"win:UnicodeString\"/>          <!-- 65 (NDF_STACK_TRACE) -->\r\n"
                 "                    </template>\r\n"
                 "                </templates>\r\n"
                 "\r\n"
                 "                <events>\r\n"
                 ;

        footer = "                </events>\r\n"
                 "            </provider>\r\n"
                 "        </events>\r\n"
                 "    </instrumentation>\r\n"
                 ;

        s_header = "    <localization>\r\n"
                   "        <resources culture=\"en-US\">\r\n"
                   "            <stringTable>\r\n"
                   "                <string id=\"ND_PROVIDER_NAME\" value=\"" NETDATA_ETW_PROVIDER_NAME "\"/>\r\n"
                   "\r\n"
                   "                <string id=\"Channel.Daemon\" value=\"Daemon\"/>\r\n"
                   "                <string id=\"Channel.Collectors\" value=\"Collectors\"/>\r\n"
                   "                <string id=\"Channel.Access\" value=\"Access\"/>\r\n"
                   "                <string id=\"Channel.Health\" value=\"Health\"/>\r\n"
                   "                <string id=\"Channel.Aclk\" value=\"Aclk\"/>\r\n"
                   "\r\n"
                   ;

        s_footer = "            </stringTable>\r\n"
                   "        </resources>\r\n"
                   "    </localization>\r\n"
                   "</instrumentationManifest>\r\n"
                   ;
    }
    else {
        header = ";// THIS FILE IS AUTOMATICALLY GENERATED - DO NOT EDIT\r\n"
                 "\r\n"
                 "MessageIdTypedef=DWORD\r\n"
                 "\r\n"
                 "SeverityNames=(\r\n"
                 "                Informational=0x1:STATUS_SEVERITY_INFORMATIONAL\r\n"
                 "                Warning=0x2:STATUS_SEVERITY_WARNING\r\n"
                 "                Error=0x3:STATUS_SEVERITY_ERROR\r\n"
                 "              )\r\n"
                 "\r\n"
                 "FacilityNames=(\r\n"
                 "                " NETDATA_CHANNEL_NAME "=0x0FFF:FACILITY_NETDATA\r\n"
                 "              )\r\n"
                 "\r\n"
                 "LanguageNames=(\r\n"
                 "                English=0x409:MSG00409\r\n"
                 "              )\r\n"
                 "\r\n"
                 ;

        footer = "";
    }

    bool done[UINT16_MAX] = { 0 };
    char symbol[1024];

    printf("%s", header);
    for(size_t src = 1; src < _NDLS_MAX ;src++) {
        for(size_t pri = 0; pri < _NDLP_MAX ;pri++) {
            uint8_t severity = get_severity_from_priority(pri);

            for(size_t msg = 1; msg < _MSGID_MAX ;msg++) {

                if(src >= 16) {
                    fprintf(stderr, "\n\nSource %zu is bigger than 4 bits!\n\n", src);
                    return 1;
                }

                if(pri >= 16) {
                    fprintf(stderr, "\n\nPriority %zu is bigger than 4 bits!\n\n", pri);
                    return 1;
                }

                if(msg >= 256) {
                    fprintf(stderr, "\n\nMessageID %zu is bigger than 8 bits!\n\n", msg);
                    return 1;
                }

                uint16_t eventID = construct_event_code(src, pri, msg);
                if((eventID & 0xFFFF) != eventID) {
                    fprintf(stderr, "\n\nEventID 0x%x is bigger than 16 bits!\n\n", eventID);
                    return 1;
                }

                if(done[eventID]) continue;
                done[eventID] = true;

                const char *level = get_level_from_priority_str(pri);
                const char *pri_txt;
                switch(pri) {
                    case NDLP_EMERG:
                        pri_txt = "EMERG";
                        break;

                    case NDLP_CRIT:
                        pri_txt = "CRIT";
                        break;

                    case NDLP_ALERT:
                        pri_txt = "ALERT";
                        break;

                    case NDLP_ERR:
                        pri_txt = "ERR";
                        break;

                    case NDLP_WARNING:
                        pri_txt = "WARN";
                        break;

                    case NDLP_INFO:
                        pri_txt = "INFO";
                        break;

                    case NDLP_NOTICE:
                        pri_txt = "NOTICE";
                        break;

                    case NDLP_DEBUG:
                        pri_txt = "DEBUG";
                        break;

                    default:
                        fprintf(stderr, "\n\nInvalid priority %zu!\n\n\n", pri);
                        return 1;
                }

                const char *channel;
                const char *src_txt;
                switch(src) {
                    case NDLS_COLLECTORS:
                        src_txt = "COLLECTORS";
                        channel = NETDATA_ETW_CHANNEL_NAME "/" NETDATA_ETW_SUBCHANNEL_COLLECTORS;
                        break;

                    case NDLS_ACCESS:
                        src_txt = "ACCESS";
                        channel = NETDATA_ETW_CHANNEL_NAME "/" NETDATA_ETW_SUBCHANNEL_ACCESS;
                        break;

                    case NDLS_HEALTH:
                        src_txt = "HEALTH";
                        channel = NETDATA_ETW_CHANNEL_NAME "/" NETDATA_ETW_SUBCHANNEL_HEALTH;
                        break;

                    case NDLS_DEBUG:
                        src_txt = "DEBUG";
                        channel = NETDATA_ETW_CHANNEL_NAME "/" NETDATA_ETW_SUBCHANNEL_DAEMON;
                        break;

                    case NDLS_DAEMON:
                        src_txt = "DAEMON";
                        channel = NETDATA_ETW_CHANNEL_NAME "/" NETDATA_ETW_SUBCHANNEL_DAEMON;
                        break;

                    case NDLS_ACLK:
                        src_txt = "ACLK";
                        channel = NETDATA_ETW_CHANNEL_NAME "/" NETDATA_ETW_SUBCHANNEL_ACLK;
                        break;

                    default:
                        fprintf(stderr, "\n\nInvalid source %zu!\n\n\n", src);
                        return 1;
                }

                const char *msg_txt = get_msg_symbol(msg);
                const char *format = get_msg_format(msg);

                const char *severity_txt;
                switch (severity) {
                    case STATUS_SEVERITY_INFORMATIONAL:
                        severity_txt = "Informational";
                        break;

                    case STATUS_SEVERITY_ERROR:
                        severity_txt = "Error";
                        break;

                    case STATUS_SEVERITY_WARNING:
                        severity_txt = "Warning";
                        break;

                    default:
                        fprintf(stderr, "\n\nInvalid severity id %u!\n\n\n", severity);
                        return 1;
                }

                if(manifest)
                    snprintf(symbol, sizeof(symbol), "ED_%s_%s_%s", src_txt, pri_txt, msg_txt);
                else
                    snprintf(symbol, sizeof(symbol), "MC_%s_%s_%s", src_txt, pri_txt, msg_txt);

                if(manifest)
                    printf("                    <event symbol=\"%s\"\r\n"
                           "                           value=\"0x%x\"\r\n"
                           "                           message=\"$(string.msg.MAN_%s)\"\r\n"
                           "                           channel=\"%s\"\r\n"
                           "                           level=\"%s\"\r\n"
                           "                           task=\"win:None\"\r\n"
                           "                           opcode=\"win:Info\"\r\n"
                           "                           template=\"AllFieldsTemplate\"/>\r\n\r\n",
                           symbol, eventID, msg_txt, channel, level);
                else
                    printf("MessageId=0x%x\r\n"
                           "Severity=%s\r\n"
                           "Facility=" NETDATA_CHANNEL_NAME "\r\n"
                           "SymbolicName=%s\r\n"
                           "Language=English\r\n"
                           "%s"
                           ".\r\n"
                           "\r\n",
                           eventID, severity_txt, symbol, format);
            }
        }
    }
    printf("%s", footer);

    if(s_header) {
        printf("%s", s_header);

        for(size_t msg = 1; msg < _MSGID_MAX ;msg++) {
            const char *msg_txt = get_msg_symbol(msg);
            const char *format = get_msg_format(msg);
            printf("                <string id=\"msg.MAN_%s\" value=\"%s\"/>\r\n", msg_txt, format);
        }

        printf("%s", s_footer);
    }
}

