--- **Core** - Client Menu Management.
--
-- **Main Features:**
--
--    * For complex, non-static menu structures
--    * Lightweigt implementation as alternative to MENU
--    * Separation of menu tree creation from menu on the clients's side
--    * Works with a SET_CLIENT set of clients
--    * Allow manipulation of the shadow tree in various ways
--    * Push to all or only one client
--    * Change entries' menu text
--    * Option to make an entry usable once only across all clients
--    * Auto appends GROUP and CLIENT objects to menu calls
--
-- ===
--
-- ### Author: **applevangelist**
-- 
-- ===
-- 
-- @module Core.ClientMenu
-- @image Core_Menu.JPG
-- last change: Sept 2023

-- TODO
----------------------------------------------------------------------------------------------------------------
--
-- CLIENTMENU
--
----------------------------------------------------------------------------------------------------------------

---
-- @type CLIENTMENU
-- @field #string ClassName Class Name
-- @field #string lid Lid for log entries
-- @field #string version Version string
-- @field #string name Name
-- @field #string groupname Group name
-- @field #table path
-- @field #table parentpath
-- @field #CLIENTMENU Parent
-- @field Wrapper.Client#CLIENT client
-- @field #number GroupID Group ID
-- @field #number ID Entry ID
-- @field Wrapper.Group#GROUP group
-- @field #string UUID Unique ID based on path+name
-- @field #string Function
-- @field #table Functionargs
-- @field #table Children
-- @field #boolean Once
-- @field #boolean Generic
-- @field #boolean debug
-- @field #CLIENTMENUMANAGER Controller
-- @extends Core.Base#BASE

---
-- @field #CLIENTMENU
CLIENTMENU = {
  ClassName = "CLIENTMENUE",
  lid = "",
  version = "0.1.1",
  name = nil,
  path = nil,
  group = nil,
  client = nil,
  GroupID = nil,
  Children = {},
  Once = false,
  Generic = false,
  debug = false,
  Controller = nil,
  groupname = nil,
}

---
-- @field #CLIENTMENU_ID
CLIENTMENU_ID = 0

--- Create an new CLIENTMENU object.
-- @param #CLIENTMENU self
-- @param Wrapper.Client#CLIENT Client The client for whom this entry is.
-- @param #string Text Text of the F10 menu entry.
-- @param #CLIENTMENU Parent The parent menu entry.
-- @param #string Function (optional) Function to call when the entry is used.
-- @param ... (optional) Arguments for the Function, comma separated
-- @return #CLIENTMENU self 
function CLIENTMENU:NewEntry(Client,Text,Parent,Function,...)
  -- Inherit everything from BASE class.
  local self=BASE:Inherit(self, BASE:New()) -- #CLIENTMENU
  CLIENTMENU_ID = CLIENTMENU_ID + 1
  self.ID = CLIENTMENU_ID
  if Client then
    self.group = Client:GetGroup()
    self.client = Client
    self.GroupID = self.group:GetID()
    self.groupname = self.group:GetName() or "Unknown Groupname"
  else
    self.Generic = true
  end
  self.name = Text or "unknown entry"
  if Parent then
    if Parent:IsInstanceOf("MENU_BASE") then
      self.parentpath = Parent.MenuPath
    else
      self.parentpath = Parent:GetPath()
      Parent:AddChild(self)
    end
  end
  self.Parent = Parent
  self.Function = Function
  self.Functionargs = arg or {}
  table.insert(self.Functionargs,self.group)
  table.insert(self.Functionargs,self.client)
  if self.Functionargs and self.debug then
    self:T({"Functionargs",self.Functionargs})
  end
  if not self.Generic then
    if Function ~= nil then
      local ErrorHandler = function( errmsg )
        env.info( "MOOSE Error in CLIENTMENU COMMAND function: " .. errmsg )
        if BASE.Debug ~= nil then
          env.info( BASE.Debug.traceback() )
        end
        return errmsg
      end
      self.CallHandler = function()
      local function MenuFunction() 
        return self.Function( unpack( self.Functionargs ) )
      end
        local Status, Result = xpcall( MenuFunction, ErrorHandler)
        if self.Once == true then
          self:Clear()
        end
      end
      self.path = missionCommands.addCommandForGroup(self.GroupID,Text,self.parentpath, self.CallHandler)
    else
      self.path = missionCommands.addSubMenuForGroup(self.GroupID,Text,self.parentpath)
    end
  else
    if self.parentpath then
      self.path = UTILS.DeepCopy(self.parentpath)
    else
      self.path = {}
    end
    self.path[#self.path+1] = Text
  end
  self.UUID = table.concat(self.path,";")
  self:T({self.UUID})
  self.Once = false
  -- Log id.
  self.lid=string.format("CLIENTMENU %s | %s | ", self.ID, self.name)
  self:T(self.lid.."Created")
  return self
end

--- Create a UUID
-- @param #CLIENTMENU self
-- @param #CLIENTMENU Parent The parent object if any
-- @param #string Text The menu entry text
-- @return #string UUID
function CLIENTMENU:CreateUUID(Parent,Text)
  local path = {}
  if Parent and Parent.path then
    path = Parent.path
  end
  path[#path+1] = Text
  local UUID = table.concat(path,";")
  return UUID
end

--- Set the CLIENTMENUMANAGER for this entry.
-- @param #CLIENTMENU self
-- @param #CLIENTMENUMANAGER Controller The controlling object.
-- @return #CLIENTMENU self 
function CLIENTMENU:SetController(Controller)
  self.Controller = Controller
  return self
end

--- The entry will be deleted after being used used - for menu entries with functions only.
-- @param #CLIENTMENU self
-- @return #CLIENTMENU self 
function CLIENTMENU:SetOnce()
  self:T(self.lid.."SetOnce")
  self.Once = true
  return self
end

--- Remove the entry from the F10 menu.
-- @param #CLIENTMENU self
-- @return #CLIENTMENU self 
function CLIENTMENU:RemoveF10()
  self:T(self.lid.."RemoveF10")
  if self.GroupID then
    --self:I(self.lid.."Removing "..table.concat(self.path,";"))
    local function RemoveFunction()
      return missionCommands.removeItemForGroup(self.GroupID , self.path )
    end
    local status, err = pcall(RemoveFunction)
    if not status then
      self:I(string.format("**** Error Removing Menu Entry %s for %s!",tostring(self.name),self.groupname))
    end
  end
  return self
end

--- Get the menu path table.
-- @param #CLIENTMENU self
-- @return #table Path
function CLIENTMENU:GetPath()
  self:T(self.lid.."GetPath")
  return self.path 
end

--- Get the UUID.
-- @param #CLIENTMENU self
-- @return #string UUID
function CLIENTMENU:GetUUID()
  self:T(self.lid.."GetUUID")
  return self.UUID
end

--- Link a child entry.
-- @param #CLIENTMENU self
-- @param #CLIENTMENU Child The entry to link as a child.
-- @return #CLIENTMENU self
function CLIENTMENU:AddChild(Child)
  self:T(self.lid.."AddChild "..Child.ID)
  table.insert(self.Children,Child.ID,Child)
  return self
end

--- Remove a child entry.
-- @param #CLIENTMENU self
-- @param #CLIENTMENU Child The entry to remove from the children.
-- @return #CLIENTMENU self
function CLIENTMENU:RemoveChild(Child)
  self:T(self.lid.."RemoveChild "..Child.ID)
  table.remove(self.Children,Child.ID)
  return self
end

--- Remove all subentries (children) from this entry.
-- @param #CLIENTMENU self
-- @return #CLIENTMENU self
function CLIENTMENU:RemoveSubEntries()
  self:T(self.lid.."RemoveSubEntries")
  self:T({self.Children})
  for _id,_entry in pairs(self.Children) do
    self:T("Removing ".._id)
    if _entry then
      _entry:RemoveSubEntries()
      _entry:RemoveF10()
      if _entry.Parent then
        _entry.Parent:RemoveChild(self)
      end
      --if self.Controller then
        --self.Controller:_RemoveByID(_entry.ID)
      --end
      --_entry = nil
    end
  end
  return self
end

--- Remove this entry and all subentries (children) from this entry.
-- @param #CLIENTMENU self
-- @return #CLIENTMENU self
function CLIENTMENU:Clear()
  self:T(self.lid.."Clear")
  for _id,_entry in pairs(self.Children) do
    if _entry then
      _entry:RemoveSubEntries()
      _entry = nil
    end
  end
  self:RemoveF10()
  if self.Parent then
    self.Parent:RemoveChild(self)
  end
  --if self.Controller then
    --self.Controller:_RemoveByID(self.ID)
  --end
  return self
end

-- TODO
----------------------------------------------------------------------------------------------------------------
--
-- CLIENTMENUMANAGER
--
----------------------------------------------------------------------------------------------------------------


--- Class CLIENTMENUMANAGER              
-- @type CLIENTMENUMANAGER
-- @field #string ClassName Class Name
-- @field #string lid Lid for log entries
-- @field #string version Version string
-- @field #string name Name
-- @field Core.Set#SET_CLIENT clientset The set of clients this menu manager is for
-- @field #table flattree
-- @field #table rootentries
-- @field #table menutree
-- @field #number entrycount
-- @field #boolean debug
-- @extends Core.Base#BASE

--- *As a child my family's menu consisted of two choices: take it, or leave it.*
--
-- ===
--
-- ## CLIENTMENU and CLIENTMENUMANAGER
-- 
-- Manage menu structures for a SET_CLIENT of clients.
-- 
-- ## Concept
-- 
-- Separate creation of a menu tree structure from pushing it to each client. Create a shadow "reference" menu structure tree for your client pilot's in a mission. 
-- This can then be propagated to all clients. Manipulate the entries in the structure with removing, clearing or changing single entries, create replacement sub-structures 
-- for entries etc, push to one or all clients.
-- 
-- Many functions can either change the tree for one client or for all clients.
-- 
-- ## Create a base reference tree and send to all clients
-- 
--            local clientset = SET_CLIENT:New():FilterStart()
--            
--            local menumgr = CLIENTMENUMANAGER:New(clientset,"Dayshift")
--            local mymenu = menumgr:NewEntry("Top")
--            local mymenu_lv1a = menumgr:NewEntry("Level 1 a",mymenu)
--            local mymenu_lv1b = menumgr:NewEntry("Level 1 b",mymenu)
--            -- next one is a command menu entry, which can only be used once
--            local mymenu_lv1c = menumgr:NewEntry("Action Level 1 c",mymenu, testfunction, "testtext"):SetOnce()
--            
--            local mymenu_lv2a = menumgr:NewEntry("Go here",mymenu_lv1a)
--            local mymenu_lv2b = menumgr:NewEntry("Level 2 ab",mymenu_lv1a)
--            local mymenu_lv2c = menumgr:NewEntry("Level 2 ac",mymenu_lv1a)
--            
--            local mymenu_lv2ba = menumgr:NewEntry("Level 2 ba",mymenu_lv1b)
--            local mymenu_lv2bb = menumgr:NewEntry("Level 2 bb",mymenu_lv1b)
--            local mymenu_lv2bc = menumgr:NewEntry("Level 2 bc",mymenu_lv1b)
--            
--            local mymenu_lv3a = menumgr:NewEntry("Level 3 aaa",mymenu_lv2a)
--            local mymenu_lv3b = menumgr:NewEntry("Level 3 aab",mymenu_lv2a)
--            local mymenu_lv3c = menumgr:NewEntry("Level 3 aac",mymenu_lv2a)
--            
--            menumgr:Propagate()
--            
-- ## Remove a single entry's subtree
-- 
--            menumgr:RemoveSubEntries(mymenu_lv3a)
--            
 -- ## Remove a single entry and also it's subtree
-- 
--            menumgr:DeleteEntry(mymenu_lv3a)
-- 
-- ## Add a single entry
-- 
--            local baimenu = menumgr:NewEntry("BAI",mymenu_lv1b)
--            
--            menumgr:AddEntry(baimenu)  
--            
-- ## Add an entry with a function 
-- 
--            local baimenu = menumgr:NewEntry("Task Action", mymenu_lv1b, TestFunction, Argument1, Argument1)
--            
--  Now, the class will **automatically append the call with GROUP and CLIENT objects**, as this is can only be done when pushing the entry to the clients. So, the actual function implementation needs to look like this:
--  
--            function TestFunction( Argument1, Argument2, Group, Client)
--            
--  **Caveat is**, that you need to ensure your arguments are not **nil** or **false**, as LUA will optimize those away. You would end up having Group and Client in wrong places in the function call. Hence,
--  if you need/ want to send **nil** or **false**, send a place holder instead and ensure your function can handle this, e.g.
--  
--            local baimenu = menumgr:NewEntry("Task Action", mymenu_lv1b, TestFunction, "nil", Argument1)
--     
-- ## Change the text of a leaf entry in the menu tree          
--            
--            menumgr:ChangeEntryTextForAll(mymenu_lv1b,"Attack")
--            
-- ## Reset a single clients menu tree
-- 
--            menumgr:ResetMenu(client)
--            
-- ## Reset all and clear the reference tree
-- 
--            menumgr:ResetMenuComplete() 
--
-- @field #CLIENTMENUMANAGER
CLIENTMENUMANAGER = {
  ClassName = "CLIENTMENUMANAGER",
  lid = "",
  version = "0.1.1",
  name = nil,
  clientset = nil,
  menutree = {},
  flattree = {},
  playertree = {},
  entrycount = 0,
  rootentries = {},
  debug = true,
}

--- Create a new ClientManager instance.
-- @param #CLIENTMENUMANAGER self
-- @param Core.Set#SET_CLIENT ClientSet The set of clients to manage.
-- @param #string Alias The name of this manager.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:New(ClientSet, Alias)
  -- Inherit everything from FSM class.
  local self=BASE:Inherit(self, BASE:New()) -- #CLIENTMENUMANAGER
  self.clientset = ClientSet
  self.name = Alias or "Nightshift"
    -- Log id.
  self.lid=string.format("CLIENTMENUMANAGER %s | %s | ", self.version, self.name)
  if self.debug then
    self:T(self.lid.."Created")
  end
  return self
end

--- Create a new entry in the generic structure.
-- @param #CLIENTMENUMANAGER self
-- @param #string Text Text of the F10 menu entry.
-- @param #CLIENTMENU Parent The parent menu entry.
-- @param #string Function (optional) Function to call when the entry is used.
-- @param ... (optional) Arguments for the Function, comma separated.
-- @return #CLIENTMENU Entry
function CLIENTMENUMANAGER:NewEntry(Text,Parent,Function,...)
  self:T(self.lid.."NewEntry "..Text or "None")
  self.entrycount = self.entrycount + 1
  local entry = CLIENTMENU:NewEntry(nil,Text,Parent,Function,unpack(arg))
  if not Parent then
    self.rootentries[self.entrycount] = entry
  end
  local depth = #entry.path
  if not self.menutree[depth] then self.menutree[depth] = {} end
  table.insert(self.menutree[depth],entry.UUID)
  self.flattree[entry.UUID] = entry
  return entry
end

--- Check matching entry in the generic structure by UUID.
-- @param #CLIENTMENUMANAGER self
-- @param #string UUID UUID of the menu entry.
-- @return #boolean Exists
function CLIENTMENUMANAGER:EntryUUIDExists(UUID)
  local exists = self.flattree[UUID] and true or false
  return exists
end

--- Find matching entry in the generic structure by UUID.
-- @param #CLIENTMENUMANAGER self
-- @param #string UUID UUID of the menu entry.
-- @return #CLIENTMENU Entry The #CLIENTMENU object found or nil.
function CLIENTMENUMANAGER:FindEntryByUUID(UUID)
  self:T(self.lid.."FindEntryByUUID "..UUID or "None")
  local entry = nil
  for _gid,_entry in pairs(self.flattree) do
    local Entry = _entry -- #CLIENTMENU
    if Entry and Entry.UUID == UUID then
      entry = Entry
    end
  end
  return entry
end

--- Find matching entries by text in the generic structure by UUID.
-- @param #CLIENTMENUMANAGER self
-- @param #string Text Text or partial text of the menu entry to find.
-- @param #CLIENTMENU Parent (Optional) Only find entries under this parent entry.
-- @return #table Table of matching UUIDs of #CLIENTMENU objects
-- @return #table Table of matching #CLIENTMENU objects
-- @return #number Number of matches
function CLIENTMENUMANAGER:FindUUIDsByText(Text,Parent)
  self:T(self.lid.."FindUUIDsByText "..Text or "None")
  local matches = {}
  local entries = {}
  local n = 0
  for _uuid,_entry in pairs(self.flattree) do
    local Entry = _entry -- #CLIENTMENU
    if Parent then
      if Entry and string.find(Entry.name,Text,1,true) and string.find(Entry.UUID,Parent.UUID,1,true) then
        table.insert(matches,_uuid)
        table.insert(entries,Entry )
        n=n+1
      end
    else
      if Entry and string.find(Entry.name,Text,1,true) then
        table.insert(matches,_uuid)
        table.insert(entries,Entry )
        n=n+1
      end
    end
  end
  return matches, entries, n
end

--- Find matching entries in the generic structure by the menu text.
-- @param #CLIENTMENUMANAGER self
-- @param #string Text Text or partial text of the F10 menu entry.
-- @param #CLIENTMENU Parent (Optional) Only find entries under this parent entry.
-- @return #table Table of matching #CLIENTMENU objects.
-- @return #number Number of matches
function CLIENTMENUMANAGER:FindEntriesByText(Text,Parent)
  self:T(self.lid.."FindEntriesByText "..Text or "None")
  local matches, objects, number = self:FindUUIDsByText(Text, Parent)
  return objects, number
end

--- Find matching entries under a parent in the generic structure by UUID.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Parent Find entries under this parent entry.
-- @return #table Table of matching UUIDs of #CLIENTMENU objects
-- @return #table Table of matching #CLIENTMENU objects
-- @return #number Number of matches
function CLIENTMENUMANAGER:FindUUIDsByParent(Parent)
  self:T(self.lid.."FindUUIDsByParent")
  local matches = {}
  local entries = {}
  local n = 0
  for _uuid,_entry in pairs(self.flattree) do
    local Entry = _entry -- #CLIENTMENU
    if Parent then
      if Entry and string.find(Entry.UUID,Parent.UUID,1,true) then
        table.insert(matches,_uuid)
        table.insert(entries,Entry )
        n=n+1
      end
    end
  end
  return matches, entries, n
end

--- Find matching entries in the generic structure under a parent.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Parent Find entries under this parent entry.
-- @return #table Table of matching #CLIENTMENU objects.
-- @return #number Number of matches
function CLIENTMENUMANAGER:FindEntriesByParent(Parent)
  self:T(self.lid.."FindEntriesByParent")
  local matches, objects, number = self:FindUUIDsByParent(Parent)
  return objects, number
end

--- Alter the text of a leaf entry in the generic structure and push to one specific client's F10 menu.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The menu entry.
-- @param #string Text New Text of the F10 menu entry.
-- @param Wrapper.Client#CLIENT Client (optional) The client for whom to alter the entry, if nil done for all clients.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:ChangeEntryText(Entry, Text, Client)
  self:T(self.lid.."ChangeEntryText "..Text or "None")
  local newentry = CLIENTMENU:NewEntry(nil,Text,Entry.Parent,Entry.Function,unpack(Entry.Functionargs))
  self:DeleteF10Entry(Entry,Client)
  self:DeleteGenericEntry(Entry)
  if not Entry.Parent then
    self.rootentries[self.entrycount] = newentry
  end
  local depth = #newentry.path
  if not self.menutree[depth] then self.menutree[depth] = {} end
  table.insert(self.menutree[depth],newentry.UUID)
  self.flattree[newentry.UUID] = newentry
  self:AddEntry(newentry,Client)
  return self
end

--- Push the complete menu structure to each of the clients in the set - refresh the menu tree of the clients.
-- @param #CLIENTMENUMANAGER self
-- @param Wrapper.Client#CLIENT Client (optional) If given, propagate only for this client.
-- @return #CLIENTMENU Entry
function CLIENTMENUMANAGER:Propagate(Client)
  self:T(self.lid.."Propagate")
  self:T(Client)
  local Set = self.clientset.Set
  if Client then
    Set = {Client}
  end
  self:ResetMenu(Client)
  for _,_client in pairs(Set) do
    local client = _client -- Wrapper.Client#CLIENT
    if client and client:IsAlive() then
      local playername = client:GetPlayerName()
        if not self.playertree[playername] then
          self.playertree[playername] = {}
        end
        for level,branch in pairs (self.menutree) do
          self:T("Building branch:" .. level)
          for _,leaf in pairs(branch) do
            self:T("Building leaf:" .. leaf)
            local entry = self:FindEntryByUUID(leaf)
            if entry then
              self:T("Found generic entry:" .. entry.UUID)
              local parent = nil
              if entry.Parent and entry.Parent.UUID then
                parent = self.playertree[playername][entry.Parent.UUID] or self:FindEntryByUUID(entry.Parent.UUID)
              end
              self.playertree[playername][entry.UUID] = CLIENTMENU:NewEntry(client,entry.name,parent,entry.Function,unpack(entry.Functionargs))
              self.playertree[playername][entry.UUID].Once = entry.Once
            else
              self:T("NO generic entry for:" .. leaf)
            end  
          end
        end
    end
  end
  return self
end

--- Push a single previously created entry into the menu structure of all clients.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry to add.
-- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client. 
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:AddEntry(Entry,Client)
  self:T(self.lid.."AddEntry")
  local Set = self.clientset.Set
  if Client then
    Set = {Client}
  end
  for _,_client in pairs(Set) do
    local client = _client -- Wrapper.Client#CLIENT
    if client and client:IsAlive() then
      local playername = client:GetPlayerName()
      if Entry then
        self:T("Adding generic entry:" .. Entry.UUID)
        local parent = nil
        if not self.playertree[playername] then
          self.playertree[playername] = {}
        end
        if Entry.Parent and Entry.Parent.UUID then
          parent = self.playertree[playername][Entry.Parent.UUID] or self:FindEntryByUUID(Entry.Parent.UUID)
        end
        self.playertree[playername][Entry.UUID] = CLIENTMENU:NewEntry(client,Entry.name,parent,Entry.Function,unpack(Entry.Functionargs))
        self.playertree[playername][Entry.UUID].Once = Entry.Once
      else
        self:T("NO generic entry given")
      end 
    end
  end
  return self
end

--- Blank out the menu - remove **all root entries** and all entries below from the client's F10 menus, leaving the generic structure untouched.
-- @param #CLIENTMENUMANAGER self
-- @param Wrapper.Client#CLIENT Client (optional) If given, remove only for this client.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:ResetMenu(Client)
  self:T(self.lid.."ResetMenu")
  for _,_entry in pairs(self.rootentries) do
    --local RootEntry = self.structure.generic[_entry]
    if _entry then
      self:DeleteF10Entry(_entry,Client)
    end
  end
  return self
end

--- Blank out the menu - remove **all root entries** and all entries below from all clients' F10 menus, and **delete** the generic structure.
-- @param #CLIENTMENUMANAGER self
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:ResetMenuComplete()
  self:T(self.lid.."ResetMenuComplete")
  for _,_entry in pairs(self.rootentries) do
    --local RootEntry = self.structure.generic[_entry]
    if _entry then
      self:DeleteF10Entry(_entry)
    end
  end
  self.playertree = nil
  self.playertree = {}
  self.rootentries = nil
  self.rootentries = {}
  self.menutree = nil
  self.menutree = {}
  return self
end

--- Remove the entry and all entries below the given entry from the client's F10 menus.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry to remove
-- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client. 
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:DeleteF10Entry(Entry,Client)
  self:T(self.lid.."DeleteF10Entry")
  local Set = self.clientset.Set
  if Client then
    Set = {Client}
  end
  for _,_client in pairs(Set) do
    if _client and _client:IsAlive() then
      local playername = _client:GetPlayerName()
      if self.playertree[playername] then
        local centry = self.playertree[playername][Entry.UUID] -- #CLIENTMENU
        if centry then
          --self:I("Match for "..Entry.UUID)
          centry:Clear()
        end
      end
    end
  end
  return self
end

--- Remove the entry and all entries below the given entry from the generic tree.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry to remove
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:DeleteGenericEntry(Entry)
  self:T(self.lid.."DeleteGenericEntry")
  
  if Entry.Children and #Entry.Children > 0 then
    self:RemoveGenericSubEntries(Entry)
  end
  
  local depth = #Entry.path
  local uuid = Entry.UUID
  
  local tbl = UTILS.DeepCopy(self.menutree)
  
  if tbl[depth] then
    for i=depth,#tbl do
      --self:I("Level = "..i)
      for _id,_uuid in pairs(tbl[i]) do
        self:T(_uuid)
        if string.find(_uuid,uuid,1,true) or _uuid == uuid then
          --self:I("Match for ".._uuid)
          self.menutree[i][_id] = nil
          self.flattree[_uuid] = nil
        end  
      end 
    end
  end
  
  return self
end

--- Remove all entries below the given entry from the generic tree.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry where to start. This entry stays.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:RemoveGenericSubEntries(Entry)
  self:T(self.lid.."RemoveGenericSubEntries")
  
  local depth = #Entry.path + 1
  local uuid = Entry.UUID
  
  local tbl = UTILS.DeepCopy(self.menutree)
  
  if tbl[depth] then
    for i=depth,#tbl do
      self:T("Level = "..i)
      for _id,_uuid in pairs(tbl[i]) do
        self:T(_uuid)
        if string.find(_uuid,uuid,1,true) then
          self:T("Match for ".._uuid)
          self.menutree[i][_id] = nil
          self.flattree[_uuid] = nil
        end  
      end 
    end
  end  
  return self
end


--- Remove all entries below the given entry from the client's F10 menus.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry where to start. This entry stays.
-- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client. In this case the generic structure will not be touched.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:RemoveF10SubEntries(Entry,Client)
  self:T(self.lid.."RemoveSubEntries")
  local Set = self.clientset.Set
  if Client then
    Set = {Client}
  end
  for _,_client in pairs(Set) do
    if _client and _client:IsAlive() then
      local playername = _client:GetPlayerName()
      if self.playertree[playername] then
        local centry = self.playertree[playername][Entry.UUID] -- #CLIENTMENU
        centry:RemoveSubEntries()
      end
    end
  end
  return self
end

----------------------------------------------------------------------------------------------------------------
--
-- End ClientMenu
--
----------------------------------------------------------------------------------------------------------------

