/// <summary>
        /// Assert a condition.
        /// </summary>
        /// <param name="condition">The condition to assert.</param>
        /// <param name="message">The assert message.</param>
        /// <param name="destinationOverride">
        /// Overrides the message log destination.
        /// Defaults to <see cref="LoggerDestination.None"/> indicating no log destination override.
        /// </param>
        /// <param name="sourceFilePath">The file path from where the call was made.</param>
        /// <param name="sourceLineNumber">The line number from where the call was made.</param>
        public static void Assert(bool condition, string message        = null,
                                  LoggerDestination destinationOverride = LoggerDestination.None, [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
        {
            if (condition)
            {
                return;
            }

            string assertMessage = $"Assert failed! {sourceFilePath} at line {sourceLineNumber}";

            message = !string.IsNullOrEmpty(message) ? $"{assertMessage}{Environment.NewLine}{message}" : assertMessage;

            Log(string.Empty, message, LoggerVerbosity.Error, destinationOverride);
            Environment.Exit(-1);
        }
        public static void LogFunctionEntry(string category = "", string message = "",
                                            LoggerVerbosity messageVerbosity = LoggerVerbosity.Info, bool separateLineHere = false, LoggerDestination destinationOverride = LoggerDestination.None)
        {
            // Get the last stack frame and find the calling method name.
            MethodBase methodFrame  = new StackTrace().GetFrame(1).GetMethod();
            string     functionName = methodFrame.Name;
            string     className    = "NotAvailable";

            // Attempt to retrieve the class name of the calling method.
            // If we cannot retrieve the class name, it will show up as NotAvailable
            if (methodFrame.DeclaringType != null)
            {
                className = methodFrame.DeclaringType.FullName;
            }

            string messageContents = string.IsNullOrEmpty(message) ? string.Empty : $": {message}";
            string actualMessage   = $"{className}::{functionName}{messageContents}";

            Log(category, actualMessage, messageVerbosity, destinationOverride, separateLineHere);
        }
 /// <summary>
 /// Log a message with formatting options.
 /// </summary>
 /// <param name="message">The message to log.</param>
 /// <param name="messageVerbosity">The verbosity of the message.</param>
 /// <param name="separateLineHere">Should this message be separated by a line?</param>
 /// <param name="args">The formatting arguments.</param>
 /// <param name="destinationOverride">
 /// Overrides the message log destination.
 /// Defaults to <see cref="LoggerDestination.None"/> indicating no log destination override.
 /// </param>
 public static void LogFormat(string message, LoggerVerbosity messageVerbosity = LoggerVerbosity.Info,
                              bool separateLineHere = false, LoggerDestination destinationOverride = LoggerDestination.None, params object[] args)
 {
     Log(string.Empty, string.Format(message, args), messageVerbosity, destinationOverride, separateLineHere);
 }
        /// <summary>
        /// Log a message in a category with a specified verbosity.
        /// </summary>
        /// <param name="category">The category to log in.</param>
        /// <param name="message">The message to log.</param>
        /// <param name="messageVerbosity">The verbosity to log with.</param>
        /// <param name="separateLineHere">Should this message be separated by a line?</param>
        /// <param name="destinationOverride">
        /// Overrides the message log destination.
        /// Defaults to <see cref="LoggerDestination.None"/> indicating no log destination override.
        /// </param>
        public static void Log(string category, object message, LoggerVerbosity messageVerbosity = LoggerVerbosity.Info,
                               LoggerDestination destinationOverride = LoggerDestination.None, bool separateLineHere = false)
        {
            // The none verbosity turns off logging.
            if (messageVerbosity == LoggerVerbosity.None)
            {
                return;
            }

            // Lock the output stream of the console for operation.
            lock (Console.Out)
            {
                if (Verbosity > messageVerbosity)
                {
                    return;
                }

                // Check if the category we are trying to log into allows the specified verbosity.
                if (CategoryVerbosities != null)
                {
                    bool allowAnyCategoryVerbosities = CategoryVerbosities.ContainsKey(AllowAnyCategoryVerbosities);
                    if (!CategoryVerbosities.ContainsKey(category) && !allowAnyCategoryVerbosities)
                    {
                        return;
                    }

                    if (CategoryVerbosities.ContainsKey(category))
                    {
                        if (CategoryVerbosities[category] > messageVerbosity)
                        {
                            return;
                        }
                    }
                }

                MessageCount++;

                string output           = string.Concat(GetMessageHeader(messageVerbosity, category), message, MessageSuffix);
                string messageSeperator = string.Empty;

                bool shouldSeparateLine = separateLineHere || LineSeperatorMessageInterval > 0 &&
                                          MessageCount % LineSeperatorMessageInterval == 0;

                if (!string.IsNullOrEmpty(LineSeperator) && shouldSeparateLine)
                {
                    messageSeperator = LineSeperator.Multiply(output.Length);
                }

                LoggerDestination destination = destinationOverride == LoggerDestination.None ? Destination : destinationOverride;

                // Log to the file.
                if (destination.HasFlag(LoggerDestination.File))
                {
                    messageBuffer.AppendLine(output);
                    if (!string.IsNullOrEmpty(messageSeperator))
                    {
                        messageBuffer.AppendLine(messageSeperator);
                    }
                }

                // Log to the console.
                if (destination.HasFlag(LoggerDestination.Output))
                {
                    ConsoleColor oldConsoleColor = Console.ForegroundColor;
                    Console.ForegroundColor = GetVerbosityConsoleColour(messageVerbosity);

                    if (messageVerbosity == LoggerVerbosity.Plain)
                    {
                        Console.WriteLine(message);
                    }
                    else
                    {
                        Console.WriteLine(output);
                    }

                    if (!string.IsNullOrEmpty(messageSeperator))
                    {
                        Console.WriteLine(messageSeperator);
                    }

                    Console.ForegroundColor = oldConsoleColor;
                }

                // Log using message box
                if (destination.HasFlag(LoggerDestination.Form))
                {
                    // The caption of the message box is either the category or assembly name.
                    string caption = string.IsNullOrEmpty(category) ? Assembly.GetEntryAssembly().GetName().Name : category;

                    // Show a message box with the appropriate icon corresponding to the message verbosity
                    switch (messageVerbosity)
                    {
                    case LoggerVerbosity.Plain:
                        MessageBox.Show(message.ToString(), caption, MessageBoxButton.OK, MessageBoxImage.None);
                        break;

                    case LoggerVerbosity.Info:
                        MessageBox.Show(message.ToString(), caption, MessageBoxButton.OK, MessageBoxImage.Information);
                        break;

                    case LoggerVerbosity.Warning:
                        MessageBox.Show(message.ToString(), caption, MessageBoxButton.OK, MessageBoxImage.Warning);
                        break;

                    case LoggerVerbosity.Error:
                        MessageBox.Show(message.ToString(), caption, MessageBoxButton.OK, MessageBoxImage.Error);
                        break;
                    }
                }

                if (!destination.HasFlag(LoggerDestination.None))
                {
                    OnMessageLogged(new MessagedLoggerEventArgs(message.ToString()));
                }

                // Flush the message buffer if it is time.
                messageCountSinceLastFlush++;
                if (messageVerbosity >= FlushVerbosity || messageCountSinceLastFlush == FlushBufferMessageCapacity)
                {
                    FlushMessageBuffer();
                }
            }
        }