//----------------------------------------------------------------------------------------------------------------------
/// \file
/// <summary>Class used for logging initialization and finalization.</summary>
// Copyright (c) Microsoft Corporation.  All Rights Reserved.
//----------------------------------------------------------------------------------------------------------------------
#pragma once
#if defined(_WIN32)
#include "Wex.Logger.h"

#include "WexString.h"

/// \namespace WEX::Logging
/// <summary>
/// The WEX::Logging namespace contains the Native API's for the Wex Logger.
/// </summary>
namespace WEX { namespace Logging 
{
    /// <summary>
    /// 
    /// </summary>
    using WexLoggerErrorCallback = void (__stdcall*)(const unsigned short* pszMessage, HRESULT hr);

    namespace Private
    {
        extern "C" WEXLOGGER_API HRESULT WEXLOGGER_STDCALL LogController_InitializeLogging(_In_z_ const wchar_t* pszLogName) noexcept;
        extern "C" WEXLOGGER_API HRESULT WEXLOGGER_STDCALL LogController_InitializeLoggingWithErrorCallback(_In_z_ const wchar_t* pszLogName,
            WexLoggerErrorCallback pfnErrorCallback) noexcept;
        extern "C" WEXLOGGER_API HRESULT WEXLOGGER_STDCALL LogController_InitializeLoggingWithConnectionData(_In_z_ const wchar_t* pszConnectionData,
            WexLoggerErrorCallback pfnErrorCallback) noexcept;
        extern "C" WEXLOGGER_API bool WEXLOGGER_STDCALL LogController_IsInitialized() noexcept;
        extern "C" WEXLOGGER_API const wchar_t* WEXLOGGER_STDCALL LogController_GetLogName() noexcept;
        extern "C" WEXLOGGER_API HRESULT WEXLOGGER_STDCALL LogController_FinalizeLogging() noexcept;
    }/* namespace Private */

    class LogController final
    {
    public:
        /// <summary>
        /// Initialize logging functionality
        /// </summary>
        static HRESULT InitializeLogging() noexcept
        {
            return Private::LogController_InitializeLogging(L"");
        }

        /// <summary>
        /// Initialize logging functionality and provide a callback to be notified of any logging errors
        /// </summary>
        /// <param name="pfnErrorCallback"> </param>
        static HRESULT InitializeLogging(WexLoggerErrorCallback pfnErrorCallback) noexcept
        {
            return Private::LogController_InitializeLoggingWithErrorCallback(L"", pfnErrorCallback);
        }

        /// <summary>
        /// Initialize logging functionality and specify the log name
        /// </summary>
        /// <param name="pszLogName"> </param>
        static HRESULT InitializeLogging(_In_z_ const wchar_t* pszLogName) noexcept
        {
            return Private::LogController_InitializeLogging(pszLogName);
        }

        /// <summary>
        /// Initialize logging functionality, specify the log name and provide a callback to be notified of any logging errors
        /// </summary>
        /// <param name="pszLogName"> </param>
        /// <param name="pfnErrorCallback"> </param>
        static HRESULT InitializeLogging(_In_z_ const wchar_t* pszLogName, WexLoggerErrorCallback pfnErrorCallback)
        {
            return Private::LogController_InitializeLoggingWithErrorCallback(pszLogName, pfnErrorCallback);
        }

        /// <summary>
        /// Initializes logging using a connection data string from RemoteLogController::GenerateConnectionData.
        /// </summary>
        /// <param name="pszConnectionData">a connection data string from RemoteLogController::GenerateConnectionData</param>
        /// <param name="pfnErrorCallback">an optional callback for when a Wex.Logger API fails</param>
        static HRESULT InitializeLoggingWithConnectionData(_In_z_ const wchar_t* pszConnectionData, WexLoggerErrorCallback pfnErrorCallback = nullptr)
        {
            return Private::LogController_InitializeLoggingWithConnectionData(pszConnectionData, pfnErrorCallback);
        }

        /// <summary>
        /// Returns whether or not the LogController has been initialized for this process
        /// </summary>
        static bool IsInitialized() noexcept
        {
            return Private::LogController_IsInitialized();
        }

        /// <summary>
        /// Returns the name that was specified for the log in the InitializeLogging call (if any).
        /// </summary>
        static const unsigned short* GetLogName() noexcept
        {
            // The cast to "const unsigned short*" is for backwards compatibility reasons. We might change the GetLogName return type to use wchar_t in the future.
            return reinterpret_cast<const unsigned short*>(Private::LogController_GetLogName());
        }

        /// <summary>
        /// Finalize logging functionality
        /// </summary>
        static HRESULT FinalizeLogging() noexcept
        {
            return Private::LogController_FinalizeLogging();
        }

    private:
        // Disallow construction of static class
        LogController() = delete;
        ~LogController() = delete;
        LogController(const LogController&) = delete;
        LogController& operator=(const LogController&) = delete;
    };

#if defined(__cpp_inline_variables)
    inline
#else
    static
#endif
    constexpr wchar_t c_szWexLoggerRemoteConnectionData[] = L"/wexlogger_connectiondata=";

    /// <summary>
    /// Class used for preparing an incoming remote logging connection
    /// </summary>
    class WEXLOGGER_API RemoteLogController final
    {
    public:
        /// <summary>
        /// Generate the connection data needed for the remote process to connect and log back to this process
        /// </summary>
        /// <param name="connectionData">Reference to a NoThrowString that will be populated with the connection data</param>
        static HRESULT __stdcall GenerateConnectionData(WEX::Common::NoThrowString& connectionData);

        /// <summary>
        /// Generate the connection data needed for the remote process to connect and log back to this process
        /// </summary>
        /// <param name="pszMachineName">The name of the machine on which the process will be created; only use this overload when creating a process on a remote machine.</param>
        /// <param name="connectionData">Reference to a NoThrowString that will be populated with the connection data</param>
        static HRESULT __stdcall GenerateConnectionData(const wchar_t* pszMachineName, WEX::Common::NoThrowString& connectionData);
        
        /// <summary>
        /// Initialize remote logging functionality
        /// </summary>
        /// <param name="pszConnectionData">Connection data used to connect to the remote process for receiving logging messages</param>
        static HRESULT __stdcall InitializeLogging(_In_z_ const wchar_t* pszConnectionData);

        // wchar_t native type exports
#if defined(WEXLOGGER_EXPORTS)
        static HRESULT __stdcall GenerateConnectionData(const unsigned short* pszMachineName, WEX::Common::NoThrowString& connectionData);
        static HRESULT __stdcall InitializeLogging(_In_z_ const unsigned short* pszConnectionData);
#endif

    private:
        // Disallow construction of static class
        RemoteLogController() = delete;
        ~RemoteLogController() = delete;
        RemoteLogController(const RemoteLogController&) = delete;
        RemoteLogController& operator=(const RemoteLogController&) = delete;
    };
}/* namespace Logging */}/* namespace WEX */
#endif // #if defined(_WIN32)
