--- **Core** - Manages various settings for missions, providing a menu for players to tweak settings in running missions.
--
-- ===
--
-- ## Features:
--
--   * Provide a settings menu system to the players.
--   * Provide a player settings menu and an overall mission settings menu.
--   * Mission settings provide default settings, while player settings override mission settings.
--   * Provide a menu to select between different coordinate formats for A2G coordinates.
--   * Provide a menu to select between different coordinate formats for A2A coordinates.
--   * Provide a menu to select between different message time duration options.
--   * Provide a menu to select between different metric systems.
--
-- ===
--
-- The documentation of the SETTINGS class can be found further in this document.
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Contributions:
--
-- ### Authors:
--
--   * **FlightControl**: Design & Programming
--
-- @module Core.Settings
-- @image Core_Settings.JPG


---
-- @type SETTINGS
-- @extends Core.Base#BASE

--- Takes care of various settings that influence the behavior of certain functionalities and classes within the MOOSE framework.
--
-- ===
--
-- The SETTINGS class takes care of various settings that influence the behavior of certain functionalities and classes within the MOOSE framework.
-- SETTINGS can work on 2 levels:
--
--   - **Default settings**: A running mission has **Default settings**.
--   - **Player settings**: For each player its own **Player settings** can be defined, overriding the **Default settings**.
--
-- So, when there isn't any **Player setting** defined for a player for a specific setting, or, the player cannot be identified, the **Default setting** will be used instead.
--
-- # 1) \_SETTINGS object
--
-- MOOSE defines by default a singleton object called **\_SETTINGS**. Use this object to modify all the **Default settings** for a running mission.
-- For each player, MOOSE will automatically allocate also a **player settings** object, and will expose a radio menu to allow the player to adapt the settings to his own preferences.
--
-- # 2) SETTINGS Menu
--
-- Settings can be adapted by the Players and by the Mission Administrator through **radio menus, which are automatically available in the mission**.
-- These menus can be found **on level F10 under "Settings"**. There are two kinds of menus generated by the system.
--
-- ## 2.1) Default settings menu
--
-- A menu is created automatically per Command Center that allows to modify the **Default** settings.
-- So, when joining a CC unit, a menu will be available that allows to change the settings parameters **FOR ALL THE PLAYERS**!
-- Note that the **Default settings** will only be used when a player has not chosen its own settings.
--
-- ## 2.2) Player settings menu
--
-- A menu is created automatically per Player Slot (group) that allows to modify the **Player** settings.
-- So, when joining a slot, a menu wil be available that allows to change the settings parameters **FOR THE PLAYER ONLY**!
-- Note that when a player has not chosen a specific setting, the **Default settings** will be used.
--
-- ## 2.3) Show or Hide the Player Setting menus
--
-- Of course, it may be required not to show any setting menus. In this case, a method is available on the **\_SETTINGS object**.
-- Use @{#SETTINGS.SetPlayerMenuOff}() to hide the player menus, and use @{#SETTINGS.SetPlayerMenuOn}() show the player menus.
-- Note that when this method is used, any player already in a slot will not have its menus visibility changed.
-- The option will only have effect when a player enters a new slot or changes a slot.
--
-- Example:
--
--      _SETTINGS:SetPlayerMenuOff() -- will disable the player menus.
--      _SETTINGS:SetPlayerMenuOn() -- will enable the player menus.
--      -- But only when a player exits and reenters the slot these settings will have effect!
--
--
-- # 3) Settings
--
-- There are different settings that are managed and applied within the MOOSE framework.
-- See below a comprehensive description of each.
--
-- ## 3.1) **A2G coordinates** display formatting
--
-- ### 3.1.1) A2G coordinates setting **types**
--
-- Will customize which display format is used to indicate A2G coordinates in text as part of the Command Center communications.
--
--   - A2G BR: [Bearing Range](https://en.wikipedia.org/wiki/Bearing_\(navigation\)).
--   - A2G MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
--   - A2G LL DMS: Latitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
--   - A2G LL DDM: Latitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
--
-- ### 3.1.2) A2G coordinates setting **menu**
--
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
--
-- ### 3.1.3) A2G coordinates setting **methods**
--
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
--
--   - @{#SETTINGS.SetA2G_BR}(): Enable the BR display formatting by default.
--   - @{#SETTINGS.SetA2G_MGRS}(): Enable the MGRS display formatting by default. Use @{#SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
--   - @{#SETTINGS.SetA2G_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{#SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
--   - @{#SETTINGS.SetA2G_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{#SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
--
-- ### 3.1.4) A2G coordinates setting - additional notes
--
-- One additional note on BR. In a situation when a BR coordinate should be given,
-- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied!
--
-- ## 3.2) **A2A coordinates** formatting
--
-- ### 3.2.1) A2A coordinates setting **types**
--
-- Will customize which display format is used to indicate A2A coordinates in text as part of the Command Center communications.
--
--   - A2A BRAA: [Bearing Range Altitude Aspect](https://en.wikipedia.org/wiki/Bearing_\(navigation\)).
--   - A2A MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
--   - A2A LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
--   - A2A LL DDM: Lattitude Longitude [Decimal Degrees and Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
--   - A2A BULLS: [Bullseye](http://falcon4.wikidot.com/concepts:bullseye).
--
-- ### 3.2.2) A2A coordinates setting **menu**
--
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
--
-- ### 3.2.3) A2A coordinates setting **methods**
--
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
--
--   - @{#SETTINGS.SetA2A_BRAA}(): Enable the BR display formatting by default.
--   - @{#SETTINGS.SetA2A_MGRS}(): Enable the MGRS display formatting by default. Use @{#SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
--   - @{#SETTINGS.SetA2A_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{#SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
--   - @{#SETTINGS.SetA2A_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{#SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
--   - @{#SETTINGS.SetA2A_BULLS}(): Enable the BULLSeye display formatting by default.
--
-- ### 3.2.4) A2A coordinates settings - additional notes
--
-- One additional note on BRAA. In a situation when a BRAA coordinate should be given,
-- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied!
--
-- ## 3.3) **Measurements** formatting
--
-- ### 3.3.1) Measurements setting **types**
--
-- Will customize the measurements system being used as part as part of the Command Center communications.
--
--   - **Metrics** system: Applies the [Metrics system](https://en.wikipedia.org/wiki/Metric_system) ...
--   - **Imperial** system: Applies the [Imperial system](https://en.wikipedia.org/wiki/Imperial_units) ...
--
-- ### 3.3.2) Measurements setting **menu**
--
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
--
-- ### 3.3.3) Measurements setting **methods**
--
-- There are different methods that can be used to change the **Default settings** using the \_SETTINGS object.
--
--   - @{#SETTINGS.SetMetric}(): Enable the Metric system.
--   - @{#SETTINGS.SetImperial}(): Enable the Imperial system.
--
-- ## 3.4) **Message** display times
--
-- ### 3.4.1) Message setting **types**
--
-- There are various **Message Types** that will influence the duration how long a message will appear as part of the Command Center communications.
--
--   - **Update** message: A short update message.
--   - **Information** message: Provides new information **while** executing a mission.
--   - **Briefing** message: Provides a complete briefing **before** executing a mission.
--   - **Overview report**: Provides a short report overview, the summary of the report.
--   - **Detailed report**: Provides a complete report.
--
-- ### 3.4.2) Message setting **menu**
--
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
--
-- Each Message Type has specific timings that will be applied when the message is displayed.
-- The Settings Menu will provide for each Message Type a selection of proposed durations from which can be chosen.
-- So the player can choose its own amount of seconds how long a message should be displayed of a certain type.
-- Note that **Update** messages can be chosen not to be displayed at all!
--
-- ### 3.4.3) Message setting **methods**
--
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
--
--   - @{#SETTINGS.SetMessageTime}(): Define for a specific @{Core.Message#MESSAGE.MessageType} the duration to be displayed in seconds.
--   - @{#SETTINGS.GetMessageTime}(): Retrieves for a specific @{Core.Message#MESSAGE.MessageType} the duration to be displayed in seconds.
--
-- ## 3.5) **Era** of the battle
--
-- The threat level metric is scaled according the era of the battle. A target that is AAA, will pose a much greater threat in WWII than on modern warfare.
-- Therefore, there are 4 era that are defined within the settings:
--
--   - **WWII** era: Use for warfare with equipment during the world war II time.
--   - **Korea** era: Use for warfare with equipment during the Korea war time.
--   - **Cold War** era: Use for warfare with equipment during the cold war time.
--   - **Modern** era: Use for warfare with modern equipment in the 2000s.
--
-- There are different API defined that you can use with the _SETTINGS object to configure your mission script to work in one of the 4 era:
-- @{#SETTINGS.SetEraWWII}(), @{#SETTINGS.SetEraKorea}(), @{#SETTINGS.SetEraCold}(), @{#SETTINGS.SetEraModern}()
--
-- ===
--
-- @field #SETTINGS
SETTINGS = {
  ClassName = "SETTINGS",
  ShowPlayerMenu = true,
  MenuShort = false,
  MenuStatic = false,
}

SETTINGS.__Enum = {}

---
-- @type SETTINGS.__Enum.Era
-- @field #number WWII
-- @field #number Korea
-- @field #number Cold
-- @field #number Modern
SETTINGS.__Enum.Era = {
  WWII = 1,
  Korea = 2,
  Cold = 3,
  Modern = 4,
}

do -- SETTINGS

  --- SETTINGS constructor.
  -- @param #SETTINGS self
  -- @param #string PlayerName (Optional) Set settings for this player.
  -- @return #SETTINGS
  function SETTINGS:Set( PlayerName )

    if PlayerName == nil then
      local self = BASE:Inherit( self, BASE:New() ) -- #SETTINGS
      self:SetMetric() -- Defaults
      self:SetA2G_BR() -- Defaults
      self:SetA2A_BRAA() -- Defaults
      self:SetLL_Accuracy( 3 ) -- Defaults
      self:SetMGRS_Accuracy( 5 ) -- Defaults
      self:SetMessageTime( MESSAGE.Type.Briefing, 180 )
      self:SetMessageTime( MESSAGE.Type.Detailed, 60 )
      self:SetMessageTime( MESSAGE.Type.Information, 30 )
      self:SetMessageTime( MESSAGE.Type.Overview, 60 )
      self:SetMessageTime( MESSAGE.Type.Update, 15 )
      self:SetEraModern()
      self:SetLocale("en")
      return self
    else
      local Settings = _DATABASE:GetPlayerSettings( PlayerName )
      if not Settings then
        Settings = BASE:Inherit( self, BASE:New() ) -- #SETTINGS
        _DATABASE:SetPlayerSettings( PlayerName, Settings )
      end
      return Settings
    end
  end

  --- Set short text for menus on (*true*) or off (*false*).
  -- Short text are better suited for, e.g., VR.
  -- @param #SETTINGS self
  -- @param #boolean onoff If *true* use short menu texts. If *false* long ones (default).
  function SETTINGS:SetMenutextShort( onoff )
    _SETTINGS.MenuShort = onoff
  end

  --- Set menu to be static.
  -- @param #SETTINGS self
  -- @param #boolean onoff If *true* menu is static. If *false* menu will be updated after changes (default).
  function SETTINGS:SetMenuStatic( onoff )
    _SETTINGS.MenuStatic = onoff
  end

  --- Sets the SETTINGS metric.
  -- @param #SETTINGS self
  function SETTINGS:SetMetric()
    self.Metric = true
  end

  --- Sets the SETTINGS default text locale.
  -- @param #SETTINGS self
  -- @param #string Locale
  function SETTINGS:SetLocale(Locale)
    self.Locale = Locale or "en"
  end

  --- Gets the SETTINGS text locale.
  -- @param #SETTINGS self
  -- @return #string
  function SETTINGS:GetLocale()
    return self.Locale or _SETTINGS:GetLocale()
  end

  --- Gets if the SETTINGS is metric.
  -- @param #SETTINGS self
  -- @return #boolean true if metric.
  function SETTINGS:IsMetric()
    return (self.Metric ~= nil and self.Metric == true) or (self.Metric == nil and _SETTINGS:IsMetric())
  end

  --- Sets the SETTINGS imperial.
  -- @param #SETTINGS self
  function SETTINGS:SetImperial()
    self.Metric = false
  end

  --- Gets if the SETTINGS is imperial.
  -- @param #SETTINGS self
  -- @return #boolean true if imperial.
  function SETTINGS:IsImperial()
    return (self.Metric ~= nil and self.Metric == false) or (self.Metric == nil and _SETTINGS:IsImperial())
  end

  --- Sets the SETTINGS LL accuracy.
  -- @param #SETTINGS self
  -- @param #number LL_Accuracy
  -- @return #SETTINGS
  function SETTINGS:SetLL_Accuracy( LL_Accuracy )
    self.LL_Accuracy = LL_Accuracy
  end

  --- Gets the SETTINGS LL accuracy.
  -- @param #SETTINGS self
  -- @return #number
  function SETTINGS:GetLL_DDM_Accuracy()
    return self.LL_DDM_Accuracy or _SETTINGS:GetLL_DDM_Accuracy()
  end

  --- Sets the SETTINGS MGRS accuracy.
  -- @param #SETTINGS self
  -- @param #number MGRS_Accuracy 0 to 5
  -- @return #SETTINGS
  function SETTINGS:SetMGRS_Accuracy( MGRS_Accuracy )
    self.MGRS_Accuracy = MGRS_Accuracy
  end

  --- Gets the SETTINGS MGRS accuracy.
  -- @param #SETTINGS self
  -- @return #number
  function SETTINGS:GetMGRS_Accuracy()
    return self.MGRS_Accuracy or _SETTINGS:GetMGRS_Accuracy()
  end

  --- Sets the SETTINGS Message Display Timing of a MessageType
  -- @param #SETTINGS self
  -- @param Core.Message#MESSAGE MessageType The type of the message.
  -- @param #number MessageTime The display time duration in seconds of the MessageType.
  function SETTINGS:SetMessageTime( MessageType, MessageTime )
    self.MessageTypeTimings = self.MessageTypeTimings or {}
    self.MessageTypeTimings[MessageType] = MessageTime
  end

  --- Gets the SETTINGS Message Display Timing of a MessageType
  -- @param #SETTINGS self
  -- @param Core.Message#MESSAGE MessageType The type of the message.
  -- @return #number
  function SETTINGS:GetMessageTime( MessageType )
    return (self.MessageTypeTimings and self.MessageTypeTimings[MessageType]) or _SETTINGS:GetMessageTime( MessageType )
  end

  --- Sets A2G LL DMS
  -- @param #SETTINGS self
  -- @return #SETTINGS
  function SETTINGS:SetA2G_LL_DMS()
    self.A2GSystem = "LL DMS"
  end

  --- Sets A2G LL DDM
  -- @param #SETTINGS self
  -- @return #SETTINGS
  function SETTINGS:SetA2G_LL_DDM()
    self.A2GSystem = "LL DDM"
  end

  --- Is LL DMS
  -- @param #SETTINGS self
  -- @return #boolean true if LL DMS
  function SETTINGS:IsA2G_LL_DMS()
    return (self.A2GSystem and self.A2GSystem == "LL DMS") or (not self.A2GSystem and _SETTINGS:IsA2G_LL_DMS())
  end

  --- Is LL DDM
  -- @param #SETTINGS self
  -- @return #boolean true if LL DDM
  function SETTINGS:IsA2G_LL_DDM()
    return (self.A2GSystem and self.A2GSystem == "LL DDM") or (not self.A2GSystem and _SETTINGS:IsA2G_LL_DDM())
  end

  --- Sets A2G MGRS
  -- @param #SETTINGS self
  -- @return #SETTINGS
  function SETTINGS:SetA2G_MGRS()
    self.A2GSystem = "MGRS"
  end

  --- Is MGRS
  -- @param #SETTINGS self
  -- @return #boolean true if MGRS
  function SETTINGS:IsA2G_MGRS()
    return (self.A2GSystem and self.A2GSystem == "MGRS") or (not self.A2GSystem and _SETTINGS:IsA2G_MGRS())
  end

  --- Sets A2G BRA
  -- @param #SETTINGS self
  -- @return #SETTINGS
  function SETTINGS:SetA2G_BR()
    self.A2GSystem = "BR"
  end

  --- Is BRA
  -- @param #SETTINGS self
  -- @return #boolean true if BRA
  function SETTINGS:IsA2G_BR()
    return (self.A2GSystem and self.A2GSystem == "BR") or (not self.A2GSystem and _SETTINGS:IsA2G_BR())
  end

  --- Sets A2A BRA
  -- @param #SETTINGS self
  -- @return #SETTINGS
  function SETTINGS:SetA2A_BRAA()
    self.A2ASystem = "BRAA"
  end

  --- Is BRA
  -- @param #SETTINGS self
  -- @return #boolean true if BRA
  function SETTINGS:IsA2A_BRAA()
    return (self.A2ASystem and self.A2ASystem == "BRAA") or (not self.A2ASystem and _SETTINGS:IsA2A_BRAA())
  end

  --- Sets A2A BULLS
  -- @param #SETTINGS self
  -- @return #SETTINGS
  function SETTINGS:SetA2A_BULLS()
    self.A2ASystem = "BULLS"
  end

  --- Is BULLS
  -- @param #SETTINGS self
  -- @return #boolean true if BULLS
  function SETTINGS:IsA2A_BULLS()
    return (self.A2ASystem and self.A2ASystem == "BULLS") or (not self.A2ASystem and _SETTINGS:IsA2A_BULLS())
  end

  --- Sets A2A LL DMS
  -- @param #SETTINGS self
  -- @return #SETTINGS
  function SETTINGS:SetA2A_LL_DMS()
    self.A2ASystem = "LL DMS"
  end

  --- Sets A2A LL DDM
  -- @param #SETTINGS self
  -- @return #SETTINGS
  function SETTINGS:SetA2A_LL_DDM()
    self.A2ASystem = "LL DDM"
  end

  --- Is LL DMS
  -- @param #SETTINGS self
  -- @return #boolean true if LL DMS
  function SETTINGS:IsA2A_LL_DMS()
    return (self.A2ASystem and self.A2ASystem == "LL DMS") or (not self.A2ASystem and _SETTINGS:IsA2A_LL_DMS())
  end

  --- Is LL DDM
  -- @param #SETTINGS self
  -- @return #boolean true if LL DDM
  function SETTINGS:IsA2A_LL_DDM()
    return (self.A2ASystem and self.A2ASystem == "LL DDM") or (not self.A2ASystem and _SETTINGS:IsA2A_LL_DDM())
  end

  --- Sets A2A MGRS
  -- @param #SETTINGS self
  -- @return #SETTINGS
  function SETTINGS:SetA2A_MGRS()
    self.A2ASystem = "MGRS"
  end

  --- Is MGRS
  -- @param #SETTINGS self
  -- @return #boolean true if MGRS
  function SETTINGS:IsA2A_MGRS()
    return (self.A2ASystem and self.A2ASystem == "MGRS") or (not self.A2ASystem and _SETTINGS:IsA2A_MGRS())
  end

  --- @param #SETTINGS self
  -- @param Wrapper.Group#GROUP MenuGroup Group for which to add menus.
  -- @param #table RootMenu Root menu table
  -- @return #SETTINGS
  function SETTINGS:SetSystemMenu( MenuGroup, RootMenu )

    local MenuText = "System Settings"

    local MenuTime = timer.getTime()

    local SettingsMenu = MENU_GROUP:New( MenuGroup, MenuText, RootMenu ):SetTime( MenuTime )

    -------
    -- A2G Coordinate System
    -------

    local text = "A2G Coordinate System"
    if _SETTINGS.MenuShort then
      text = "A2G Coordinates"
    end
    local A2GCoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )

    -- Set LL DMS
    if not self:IsA2G_LL_DMS() then
      local text = "Lat/Lon Degree Min Sec (LL DMS)"
      if _SETTINGS.MenuShort then
        text = "LL DMS"
      end
      MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
    end

    -- Set LL DDM
    if not self:IsA2G_LL_DDM() then
      local text = "Lat/Lon Degree Dec Min (LL DDM)"
      if _SETTINGS.MenuShort then
        text = "LL DDM"
      end
      MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
    end

    -- Set LL DMS accuracy.
    if self:IsA2G_LL_DDM() then
      local text1 = "LL DDM Accuracy 1"
      local text2 = "LL DDM Accuracy 2"
      local text3 = "LL DDM Accuracy 3"
      if _SETTINGS.MenuShort then
        text1 = "LL DDM"
      end
      MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
      MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
      MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
    end

    -- Set BR.
    if not self:IsA2G_BR() then
      local text = "Bearing, Range (BR)"
      if _SETTINGS.MenuShort then
        text = "BR"
      end
      MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime )
    end

    -- Set MGRS.
    if not self:IsA2G_MGRS() then
      local text = "Military Grid (MGRS)"
      if _SETTINGS.MenuShort then
        text = "MGRS"
      end
      MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
    end

    -- Set MGRS accuracy.
    if self:IsA2G_MGRS() then
      MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 1", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
      MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 2", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
      MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 3", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
      MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 4", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime )
      MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime )
    end

    -------
    -- A2A Coordinate System
    -------

    local text = "A2A Coordinate System"
    if _SETTINGS.MenuShort then
      text = "A2A Coordinates"
    end
    local A2ACoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )

    if not self:IsA2A_LL_DMS() then
      local text = "Lat/Lon Degree Min Sec (LL DMS)"
      if _SETTINGS.MenuShort then
        text = "LL DMS"
      end
      MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
    end

    if not self:IsA2A_LL_DDM() then
      local text = "Lat/Lon Degree Dec Min (LL DDM)"
      if _SETTINGS.MenuShort then
        text = "LL DDM"
      end
      MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
    end

    if self:IsA2A_LL_DDM() or self:IsA2A_LL_DMS() then
      MENU_GROUP_COMMAND:New( MenuGroup, "LL Accuracy 0", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 0 ):SetTime( MenuTime )
      MENU_GROUP_COMMAND:New( MenuGroup, "LL Accuracy 1", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
      MENU_GROUP_COMMAND:New( MenuGroup, "LL Accuracy 2", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
      MENU_GROUP_COMMAND:New( MenuGroup, "LL Accuracy 3", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
    end

    if not self:IsA2A_BULLS() then
      local text = "Bullseye (BULLS)"
      if _SETTINGS.MenuShort then
        text = "Bulls"
      end
      MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BULLS" ):SetTime( MenuTime )
    end

    if not self:IsA2A_BRAA() then
      local text = "Bearing Range Altitude Aspect (BRAA)"
      if _SETTINGS.MenuShort then
        text = "BRAA"
      end
      MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BRAA" ):SetTime( MenuTime )
    end

    if not self:IsA2A_MGRS() then
      local text = "Military Grid (MGRS)"
      if _SETTINGS.MenuShort then
        text = "MGRS"
      end
      MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
    end

    if self:IsA2A_MGRS() then
      MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 1", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
      MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 2", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
      MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 3", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
      MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 4", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime )
      MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime )
    end

    local text = "Measures and Weights System"
    if _SETTINGS.MenuShort then
      text = "Unit System"
    end
    local MetricsMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )

    if self:IsMetric() then
      local text = "Imperial (Miles,Feet)"
      if _SETTINGS.MenuShort then
        text = "Imperial"
      end
      MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, false ):SetTime( MenuTime )
    end

    if self:IsImperial() then
      local text = "Metric (Kilometers,Meters)"
      if _SETTINGS.MenuShort then
        text = "Metric"
      end
      MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, true ):SetTime( MenuTime )
    end

    local text = "Messages and Reports"
    if _SETTINGS.MenuShort then
      text = "Messages & Reports"
    end
    local MessagesMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )

    local UpdateMessagesMenu = MENU_GROUP:New( MenuGroup, "Update Messages", MessagesMenu ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "Off", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 0 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "5 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 5 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "10 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 10 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 15 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 30 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 60 ):SetTime( MenuTime )

    local InformationMessagesMenu = MENU_GROUP:New( MenuGroup, "Information Messages", MessagesMenu ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "5 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 5 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "10 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 10 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 15 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 30 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 60 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 120 ):SetTime( MenuTime )

    local BriefingReportsMenu = MENU_GROUP:New( MenuGroup, "Briefing Reports", MessagesMenu ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 15 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 30 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 60 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 120 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 180 ):SetTime( MenuTime )

    local OverviewReportsMenu = MENU_GROUP:New( MenuGroup, "Overview Reports", MessagesMenu ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 15 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 30 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 60 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 120 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 180 ):SetTime( MenuTime )

    local DetailedReportsMenu = MENU_GROUP:New( MenuGroup, "Detailed Reports", MessagesMenu ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 15 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 30 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 60 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 120 ):SetTime( MenuTime )
    MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 180 ):SetTime( MenuTime )

    SettingsMenu:Remove( MenuTime )

    return self
  end

  --- Sets the player menus on, so that the **Player setting menus** show up for the players.
  -- But only when a player exits and reenters the slot these settings will have effect!
  -- It is advised to use this method at the start of the mission.
  -- @param #SETTINGS self
  -- @return #SETTINGS
  -- @usage
  --   _SETTINGS:SetPlayerMenuOn() -- will enable the player menus.
  function SETTINGS:SetPlayerMenuOn()
    self.ShowPlayerMenu = true
  end

  --- Sets the player menus off, so that the **Player setting menus** won't show up for the players.
  -- But only when a player exits and reenters the slot these settings will have effect!
  -- It is advised to use this method at the start of the mission.
  -- @param #SETTINGS self
  -- @return #SETTINGS self
  -- @usage
  --   _SETTINGS:SetPlayerMenuOff() -- will disable the player menus.
  function SETTINGS:SetPlayerMenuOff()
    self.ShowPlayerMenu = false
  end

  --- Updates the menu of the player seated in the PlayerUnit.
  -- @param #SETTINGS self
  -- @param Wrapper.Client#CLIENT PlayerUnit
  -- @return #SETTINGS self
  function SETTINGS:SetPlayerMenu( PlayerUnit )

    if _SETTINGS.ShowPlayerMenu == true then

      local PlayerGroup = PlayerUnit:GetGroup()
      local PlayerName = PlayerUnit:GetPlayerName() or "None"
      --local PlayerNames = PlayerGroup:GetPlayerNames()

      local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"' )

      self.PlayerMenu = PlayerMenu

      self:T( string.format( "Setting menu for player %s", tostring( PlayerName ) ) )

      local submenu = MENU_GROUP:New( PlayerGroup, "LL Accuracy", PlayerMenu )
      MENU_GROUP_COMMAND:New( PlayerGroup, "LL 0 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 0 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "LL 1 Decimal", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "LL 2 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "LL 3 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "LL 4 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )

      local submenu = MENU_GROUP:New( PlayerGroup, "MGRS Accuracy", PlayerMenu )
      MENU_GROUP_COMMAND:New( PlayerGroup, "MRGS Accuracy 0", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 0 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "MRGS Accuracy 1", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "MRGS Accuracy 2", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "MRGS Accuracy 3", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "MRGS Accuracy 4", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "MRGS Accuracy 5", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )

      ------
      -- A2G Coordinate System
      ------

      local text = "A2G Coordinate System"
      if _SETTINGS.MenuShort then
        text = "A2G Coordinates"
      end
      local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )

      if not self:IsA2G_LL_DMS() or _SETTINGS.MenuStatic then
        local text = "Lat/Lon Degree Min Sec (LL DMS)"
        if _SETTINGS.MenuShort then
          text = "A2G LL DMS"
        end
        MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
      end

      if not self:IsA2G_LL_DDM() or _SETTINGS.MenuStatic then
        local text = "Lat/Lon Degree Dec Min (LL DDM)"
        if _SETTINGS.MenuShort then
          text = "A2G LL DDM"
        end
        MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
      end

      if not self:IsA2G_BR() or _SETTINGS.MenuStatic then
        local text = "Bearing, Range (BR)"
        if _SETTINGS.MenuShort then
          text = "A2G BR"
        end
        MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" )
      end

      if not self:IsA2G_MGRS() or _SETTINGS.MenuStatic then
        local text = "Military Grid (MGRS)"
        if _SETTINGS.MenuShort then
          text = "A2G MGRS"
        end
        MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
      end

      ------
      -- A2A Coordinates Menu
      ------

      local text = "A2A Coordinate System"
      if _SETTINGS.MenuShort then
        text = "A2A Coordinates"
      end
      local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )

      if not self:IsA2A_LL_DMS() or _SETTINGS.MenuStatic then
        local text = "Lat/Lon Degree Min Sec (LL DMS)"
        if _SETTINGS.MenuShort then
          text = "A2A LL DMS"
        end
        MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
      end

      if not self:IsA2A_LL_DDM() or _SETTINGS.MenuStatic then
        local text = "Lat/Lon Degree Dec Min (LL DDM)"
        if _SETTINGS.MenuShort then
          text = "A2A LL DDM"
        end
        MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
      end

      if not self:IsA2A_BULLS() or _SETTINGS.MenuStatic then
        local text = "Bullseye (BULLS)"
        if _SETTINGS.MenuShort then
          text = "A2A BULLS"
        end
        MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" )
      end

      if not self:IsA2A_BRAA() or _SETTINGS.MenuStatic then
        local text = "Bearing Range Altitude Aspect (BRAA)"
        if _SETTINGS.MenuShort then
          text = "A2A BRAA"
        end
        MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" )
      end

      if not self:IsA2A_MGRS() or _SETTINGS.MenuStatic then
        local text = "Military Grid (MGRS)"
        if _SETTINGS.MenuShort then
          text = "A2A MGRS"
        end
        MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
      end

      ---
      -- Unit system
      ---

      local text = "Measures and Weights System"
      if _SETTINGS.MenuShort then
        text = "Unit System"
      end
      local MetricsMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )

      if self:IsMetric() or _SETTINGS.MenuStatic then
        local text = "Imperial (Miles,Feet)"
        if _SETTINGS.MenuShort then
          text = "Imperial"
        end
        MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
      end

      if self:IsImperial() or _SETTINGS.MenuStatic then
        local text = "Metric (Kilometers,Meters)"
        if _SETTINGS.MenuShort then
          text = "Metric"
        end
        MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
      end

      ---
      -- Messages and Reports
      ---

      local text = "Messages and Reports"
      if _SETTINGS.MenuShort then
        text = "Messages & Reports"
      end
      local MessagesMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )

      local UpdateMessagesMenu = MENU_GROUP:New( PlayerGroup, "Update Messages", MessagesMenu )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Updates Off", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 0 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Updates 5 sec", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 5 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Updates 10 sec", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 10 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Updates 15 sec", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 15 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Updates 30 sec", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 30 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Updates 1 min", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 60 )

      local InformationMessagesMenu = MENU_GROUP:New( PlayerGroup, "Info Messages", MessagesMenu )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Info 5 sec", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 5 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Info 10 sec", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 10 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Info 15 sec", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 15 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Info 30 sec", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 30 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Info 1 min", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 60 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Info 2 min", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 120 )

      local BriefingReportsMenu = MENU_GROUP:New( PlayerGroup, "Briefing Reports", MessagesMenu )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Brief 15 sec", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 15 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Brief 30 sec", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 30 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Brief 1 min", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 60 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Brief 2 min", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 120 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Brief 3 min", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 180 )

      local OverviewReportsMenu = MENU_GROUP:New( PlayerGroup, "Overview Reports", MessagesMenu )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Overview 15 sec", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 15 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Overview 30 sec", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 30 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Overview 1 min", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 60 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Overview 2 min", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 120 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Overview 3 min", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 180 )

      local DetailedReportsMenu = MENU_GROUP:New( PlayerGroup, "Detailed Reports", MessagesMenu )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Detailed 15 sec", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 15 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Detailed 30 sec", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 30 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Detailed 1 min", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 60 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Detailed 2 min", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 120 )
      MENU_GROUP_COMMAND:New( PlayerGroup, "Detailed 3 min", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 180 )

    end

    return self
  end

  --- Removes the player menu from the PlayerUnit.
  -- @param #SETTINGS self
  -- @param Wrapper.Client#CLIENT PlayerUnit
  -- @return #SETTINGS self
  function SETTINGS:RemovePlayerMenu( PlayerUnit )

    if self.PlayerMenu then
      self.PlayerMenu:Remove()
      self.PlayerMenu = nil
    end

    return self
  end

  --- @param #SETTINGS self
  function SETTINGS:A2GMenuSystem( MenuGroup, RootMenu, A2GSystem )
    self.A2GSystem = A2GSystem
    MESSAGE:New( string.format( "Settings: Default A2G coordinate system set to %s for all players!", A2GSystem ), 5 ):ToAll()
    self:SetSystemMenu( MenuGroup, RootMenu )
  end

  --- @param #SETTINGS self
  function SETTINGS:A2AMenuSystem( MenuGroup, RootMenu, A2ASystem )
    self.A2ASystem = A2ASystem
    MESSAGE:New( string.format( "Settings: Default A2A coordinate system set to %s for all players!", A2ASystem ), 5 ):ToAll()
    self:SetSystemMenu( MenuGroup, RootMenu )
  end

  --- @param #SETTINGS self
  function SETTINGS:MenuLL_DDM_Accuracy( MenuGroup, RootMenu, LL_Accuracy )
    self.LL_Accuracy = LL_Accuracy
    MESSAGE:New( string.format( "Settings: Default LL accuracy set to %s for all players!", LL_Accuracy ), 5 ):ToAll()
    self:SetSystemMenu( MenuGroup, RootMenu )
  end

  --- @param #SETTINGS self
  function SETTINGS:MenuMGRS_Accuracy( MenuGroup, RootMenu, MGRS_Accuracy )
    self.MGRS_Accuracy = MGRS_Accuracy
    MESSAGE:New( string.format( "Settings: Default MGRS accuracy set to %s for all players!", MGRS_Accuracy ), 5 ):ToAll()
    self:SetSystemMenu( MenuGroup, RootMenu )
  end

  --- @param #SETTINGS self
  function SETTINGS:MenuMWSystem( MenuGroup, RootMenu, MW )
    self.Metric = MW
    MESSAGE:New( string.format( "Settings: Default measurement format set to %s for all players!", MW and "Metric" or "Imperial" ), 5 ):ToAll()
    self:SetSystemMenu( MenuGroup, RootMenu )
  end

  --- @param #SETTINGS self
  function SETTINGS:MenuMessageTimingsSystem( MenuGroup, RootMenu, MessageType, MessageTime )
    self:SetMessageTime( MessageType, MessageTime )
    MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToAll()
  end

  do
    --- @param #SETTINGS self
    function SETTINGS:MenuGroupA2GSystem( PlayerUnit, PlayerGroup, PlayerName, A2GSystem )
      --BASE:E( {PlayerUnit:GetName(), A2GSystem } )
      self.A2GSystem = A2GSystem
      MESSAGE:New( string.format( "Settings: A2G format set to %s for player %s.", A2GSystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
      if _SETTINGS.MenuStatic == false then
        self:RemovePlayerMenu( PlayerUnit )
        self:SetPlayerMenu( PlayerUnit )
      end
    end

    --- @param #SETTINGS self
    function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem )
      self.A2ASystem = A2ASystem
      MESSAGE:New( string.format( "Settings: A2A format set to %s for player %s.", A2ASystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
      if _SETTINGS.MenuStatic == false then
        self:RemovePlayerMenu( PlayerUnit )
        self:SetPlayerMenu( PlayerUnit )
      end
    end

    --- @param #SETTINGS self
    function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
      self.LL_Accuracy = LL_Accuracy
      MESSAGE:New( string.format( "Settings: LL format accuracy set to %d decimal places for player %s.", LL_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
      if _SETTINGS.MenuStatic == false then
        self:RemovePlayerMenu( PlayerUnit )
        self:SetPlayerMenu( PlayerUnit )
      end
    end

    --- @param #SETTINGS self
    function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy )
      self.MGRS_Accuracy = MGRS_Accuracy
      MESSAGE:New( string.format( "Settings: MGRS format accuracy set to %d for player %s.", MGRS_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
      if _SETTINGS.MenuStatic == false then
        self:RemovePlayerMenu( PlayerUnit )
        self:SetPlayerMenu( PlayerUnit )
      end
    end

    --- @param #SETTINGS self
    function SETTINGS:MenuGroupMWSystem( PlayerUnit, PlayerGroup, PlayerName, MW )
      self.Metric = MW
      MESSAGE:New( string.format( "Settings: Measurement format set to %s for player %s.", MW and "Metric" or "Imperial", PlayerName ), 5 ):ToGroup( PlayerGroup )
      if _SETTINGS.MenuStatic == false then
        self:RemovePlayerMenu( PlayerUnit )
        self:SetPlayerMenu( PlayerUnit )
      end
    end

    --- @param #SETTINGS self
    function SETTINGS:MenuGroupMessageTimingsSystem( PlayerUnit, PlayerGroup, PlayerName, MessageType, MessageTime )
      self:SetMessageTime( MessageType, MessageTime )
      MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToGroup( PlayerGroup )
    end

  end

  --- Configures the era of the mission to be WWII.
  -- @param #SETTINGS self
  -- @return #SETTINGS self
  function SETTINGS:SetEraWWII()

    self.Era = SETTINGS.__Enum.Era.WWII

  end

  --- Configures the era of the mission to be Korea.
  -- @param #SETTINGS self
  -- @return #SETTINGS self
  function SETTINGS:SetEraKorea()

    self.Era = SETTINGS.__Enum.Era.Korea

  end

  --- Configures the era of the mission to be Cold war.
  -- @param #SETTINGS self
  -- @return #SETTINGS self
  function SETTINGS:SetEraCold()

    self.Era = SETTINGS.__Enum.Era.Cold

  end

  --- Configures the era of the mission to be Modern war.
  -- @param #SETTINGS self
  -- @return #SETTINGS self
  function SETTINGS:SetEraModern()

    self.Era = SETTINGS.__Enum.Era.Modern

  end

end
