/// <summary>
        /// Handles logging of messages for events that the application throws out
        /// </summary>
        /// <param name="showMessagebox">"True" will force a message box to appear regardless of application settings</param>
        /// <param name="messageLevel">Integer determining error level based on above legend</param>
        /// <param name="error">Exception returned from try-catch statement; may be null</param>
        /// <param name="context">What the application was doing at the time of the message</param>
        public static void handleMessage(bool showMessagebox, int messageLevel, Exception error, string context)
        {
            MessageLevelDefinition messageDef = MessageLevel.level(messageLevel);

            if (messageLevel <= _eventViewerLoggingLevel)
            {
                logEventViewerEvent(messageDef, error, context);
            }

            if (messageLevel <= _applicationLogFileLoggingLevel)
            {
                logApplicationLogFileEntry(messageDef, error, context);
            }

            if (showMessagebox || _debugMode)
            {
                if (error != null)
                {
                    MessageBox.Show(messageDef.messageBoxIntro + "\n\nContext:\n" + context + "\n\nError message:\n" + error.Message, messageDef.messageBoxTitle);
                }
                else
                {
                    MessageBox.Show(messageDef.messageBoxIntro + "\n\nContext:\n" + context + "\n\nNo Exception object generated", messageDef.messageBoxTitle);
                }
            }
        }
        /// <summary>
        /// When given an integer representation of a message level, returns the full MessageDefinition. Returns a default MessageDefinition if none is found.
        /// </summary>
        /// <param name="levelNumber">Integer representing message level - matches with the index in the _messageLevelDict</param>
        /// <returns></returns>
        public static MessageLevelDefinition level(int levelNumber)
        {
            if (_messageLevelDict == null)
            {
                buildDefaultDict();
            }

            if (_messageLevelDict.ContainsKey(levelNumber))
            {
                return(_messageLevelDict[levelNumber]);
            }
            else
            {
                MessageLevelDefinition unconfiguredErrorMessage = new MessageLevelDefinition();
                unconfiguredErrorMessage.levelName         = "Incorrectly Handled Error";
                unconfiguredErrorMessage.messageBoxTitle   = "Incorrectly Handled Error";
                unconfiguredErrorMessage.messageBoxIntro   = "An incorrectly handled error has occurred. Please report this to the developer, who will need to ensure that the error level number has been added to MessageLevel._messageLevelDict.";
                unconfiguredErrorMessage.windowsErrorLevel = EventLogEntryType.Warning;

                return(unconfiguredErrorMessage);
            }
        }
        /// <summary>
        /// Adds a new message definition to _messageLevelDict, or updates an existing one
        /// </summary>
        /// <param name="levelNumber">Integer code for the message level</param>
        /// <param name="levelName">Short name for the message level (e.g. "Warn", "Fatal", "Info")</param>
        /// <param name="messageBoxTitle">Title that will be used in any MessageBox created for this message</param>
        /// <param name="messageBoxIntro">Intro text that will be used in any MessageBox created for this message</param>
        /// <param name="windowsErrorLevel">Windows error level, used when creating an event in Event Viewer</param>
        public static void addMessageDefinition(int levelNumber, string levelName, string messageBoxTitle, string messageBoxIntro, EventLogEntryType windowsErrorLevel)
        {
            if (_messageLevelDict == null)
            {
                buildDefaultDict();
            }

            MessageLevelDefinition levelDef = new MessageLevelDefinition();

            levelDef.levelName         = levelName;
            levelDef.messageBoxTitle   = messageBoxTitle;
            levelDef.messageBoxIntro   = messageBoxIntro;
            levelDef.windowsErrorLevel = windowsErrorLevel;

            if (_messageLevelDict.ContainsKey(levelNumber))
            {
                _messageLevelDict[levelNumber] = levelDef;
            }
            else
            {
                _messageLevelDict.Add(levelNumber, levelDef);
            }
        }
        /// <summary>
        /// Currently not functional, need an installer to create the Event Viewer source
        /// Logs an event in the Windows Event Viewer, spawns a message box if this fails
        /// </summary>
        /// <param name="messageDef">Definition of the message type</param>
        /// <param name="error">Exception, if there was one</param>
        /// <param name="context">Specifies what the application was doing when the error occurred</param>
        private static void logEventViewerEvent(MessageLevelDefinition messageDef, Exception error, string context)
        {
            string eventContent = "Logged at " + DateTime.Now + " (" + DateTime.UtcNow + ") UTC\n\n"
                                  + "Error Message: " + error.Message + "\n\n"
                                  + "Application error level: " + messageDef.levelName + "\n\n"
                                  + "HResult: " + error.HResult + "\n\n"
                                  + "Source: " + error.Source + "\n\n"
                                  + "TargetSite: " + error.TargetSite + "\n\n"
                                  + "Stack Trace:\n" + error.StackTrace;

            try
            {
                if (!EventLog.SourceExists(error.Source))
                {
                    EventLog.CreateEventSource(error.Source, "Application");
                }

                EventLog.WriteEntry(error.Source, eventContent, messageDef.windowsErrorLevel);
            }
            catch (Exception e)
            {
                MessageBox.Show("Unable to log event viewer message: " + e.Message + "\n\n" + eventContent);
            }
        }
        /// <summary>
        /// Saves events to the application log file, creating the file if it doesn't exist
        /// </summary>
        /// <param name="messageDef">Definition of the message type</param>
        /// <param name="error">Exception, if there was one</param>
        /// <param name="context">Specifies what the application was doing when the error occurred</param>
        private static void logApplicationLogFileEntry(MessageLevelDefinition messageDef, Exception error, string context)
        {
            // Confirm the log file location has been specified
            if (_applicationLogFileLocation == null)
            {
                return;
            }

            // Create the log file, if it doesn't exist
            if (!File.Exists(_applicationLogFileLocation))
            {
                try
                {
                    FileInfo logFileInfo = new FileInfo(_applicationLogFileLocation);
                    Directory.CreateDirectory(logFileInfo.Directory.FullName);

                    XmlDocument newDoc = new XmlDocument();
                    newDoc.LoadXml("<logs></logs>");

                    XmlTextWriter xmlWriter = new XmlTextWriter(_applicationLogFileLocation, null);
                    xmlWriter.Formatting = Formatting.Indented;
                    newDoc.Save(xmlWriter);

                    xmlWriter.Dispose();
                }
                catch (Exception e)
                {
                    MessageBox.Show("Unable to create log file in " + _applicationLogFileLocation + "\n\n"
                                    + e.Message);
                }
            }

            // Load the Xml document
            XmlDocument logFile = new XmlDocument();

            logFile.Load(_applicationLogFileLocation);

            XmlNode rootNode = logFile.SelectSingleNode("logs");

            // Build the log entry
            XmlNode newNode = logFile.CreateElement("log");

            XmlAttribute utcTimeAttribute = logFile.CreateAttribute("utctime");

            utcTimeAttribute.Value = DateTime.UtcNow.ToString();
            newNode.Attributes.Append(utcTimeAttribute);

            XmlAttribute levelAttribute = logFile.CreateAttribute("level");

            levelAttribute.Value = messageDef.levelName;
            newNode.Attributes.Append(levelAttribute);

            XmlAttribute contextAttribute = logFile.CreateAttribute("context");

            contextAttribute.Value = context;
            newNode.Attributes.Append(contextAttribute);

            if (error != null)
            {
                newNode.InnerText = error.Message;
            }
            else
            {
                newNode.InnerText = "No Exception object for event";
            }

            // Append the log entry
            rootNode.AppendChild(newNode);

            // Save the log file
            logFile.Save(_applicationLogFileLocation);
        }