if SERVER then return end
LuaUserData.RegisterType("Barotrauma.VisualSlot")
LuaUserData.RegisterType("Microsoft.Xna.Framework.Color")


SortContainerKey = {}
--SortContainerKey.ActivationKey = Keys.M
SortContainerKey.DefaultRecursive = true
SortContainerKey.DefaultTreatContainersAsTheirFirstItem = false
SortContainerKey.Highlight = Color.Yellow
SortContainerKey.Visible = Color.White

local Patches = {}
local Path = ...

local Localization = dofile(Path .. "/Lua/Languages/english.lua")
if GameSettings.CurrentConfig.Language.ToString() == "Simplified Chinese" then 
    Localization = dofile(Path .. "/Lua/Languages/simplifiedchinese.lua") end
if GameSettings.CurrentConfig.Language.ToString() == "Russian" then
    Localization = dofile(Path .. "/Lua/Languages/russian.lua") end

local function t_clear(t) for k in pairs(t) do t[k] = nil end return t end

local function GetComponent(item, name)
    name = name:sub(29)
    for _, component in ipairs(item.Components) do
        if component.Name == name then
            return component
        end
    end
end

local function UpdateRecursive(container,uiElem)
    Patches[container].recursive = not Patches[container].recursive
        if uiElem.CanBeFocused then
            uiElem.Color = Patches[container].recursive == true
                and SortContainerKey.Highlight
                or SortContainerKey.Visible
        end
end

local function UpdateTreatContainersAsTheirFirstItemButton(container, uiElem)
    Patches[container].TreatContainersAsTheirFirstItem = 
    not Patches[container].TreatContainersAsTheirFirstItem
        if uiElem.CanBeFocused then
            uiElem.Color = Patches[container].TreatContainersAsTheirFirstItem == true
                and SortContainerKey.Highlight
                or SortContainerKey.Visible
        end
end

local function setuiElemWhite(uiElem)
  uiElem.Color = SortContainerKey.Visible
end

local function Swap(itemcontainer,index1,index2)
  local items1 = itemcontainer.OwnInventory.GetItemsAt(index1)
  local items2 = itemcontainer.OwnInventory.GetItemsAt(index2)
  
  for item in items1 do 
    if itemcontainer.OwnInventory.FindIndex(item) ~= index2 then
      itemcontainer.OwnInventory.TryPutItem(item, index2, true, false, Character.Controlled) 
    end
  end
  for item in items2 do
    if itemcontainer.OwnInventory.FindIndex(item) ~= index1 then
      itemcontainer.OwnInventory.TryPutItem(item, index1, true, false, Character.Controlled) 
    end
  end
end


local function SortContainer(itemcontainer, recursive, TreatContainersAsTheirFirstItem, sortby)
  if recursive == nil then recursive = false end
  if TreatContainersAsTheirFirstItem == nil then TreatContainersAsTheirFirstItem = true end
  if sortby == nil then sortby = "Name" end
  
  local debugcount = 0
  local debugcount3 = 0
  
  local swapcount = 1
  local previousitem = itemcontainer.OwnInventory.FirstOrDefault()
  local previousitemindex = itemcontainer.OwnInventory.FindIndex(previousitem)
  local swaptarget = itemcontainer.OwnInventory.FirstOrDefault()
  local previousswaptarget = itemcontainer.OwnInventory.FirstOrDefault()
  while swapcount > 0 do
    swapcount = 0
    debugcount3 = 0
    previousitem = itemcontainer.OwnInventory.FirstOrDefault()
    previousitemindex = itemcontainer.OwnInventory.FindIndex(previousitem)
    swaptarget = itemcontainer.OwnInventory.FirstOrDefault()
    previousswaptarget = itemcontainer.OwnInventory.FirstOrDefault()
    
    for i = previousitemindex,itemcontainer.OwnInventory.Capacity do
      debugcount3 = debugcount3 + 1
      item = itemcontainer.OwnInventory.GetItemAt(i)
      if item == nil then goto EndOfForLoop end
      
      swaptarget = item
      previousswaptarget = previousitem
      if TreatContainersAsTheirFirstItem then
        if item.OwnInventory and not item.OwnInventory.IsEmpty() then
          swaptarget = item.OwnInventory.FirstOrDefault()
        end
        if previousitem.OwnInventory and not previousitem.OwnInventory.IsEmpty() then
          previousswaptarget = previousitem.OwnInventory.FirstOrDefault()
        end
      end
      
      if sortby == "Name" and swaptarget.Name < previousswaptarget.Name then 
        Swap(itemcontainer, itemcontainer.OwnInventory.FindIndex(item),
        itemcontainer.OwnInventory.FindIndex(previousitem))
        swapcount = swapcount + 1
      elseif sortby == "Category" and swaptarget.Prefab.Category < previousswaptarget.Prefab.Category then
        Swap(itemcontainer, itemcontainer.OwnInventory.FindIndex(item),
        itemcontainer.OwnInventory.FindIndex(previousitem))
        swapcount = swapcount + 1
      else
        previousitem = item
      end
      
      if recursive and item.OwnInventory then SortContainer(item, recursive, TreatContainersAsTheirFirstItem, sortby) end
      ::EndOfForLoop::
      if debugcount3 > 100 then print("SortContainerKey.Lua Debug Infinite Loop Error") return end
    end
    
    debugcount = debugcount + 1
    if debugcount > 100 then print("SortContainerKey.Lua Debug Infinite Loop Error") return end
  end
end

local function MergeStacks(itemcontainer, recursive, TreatContainersAsTheirFirstItem)
  if recursive == nil then recursive = true end
  if TreatContainersAsTheirFirstItem == nil then TreatContainersAsTheirFirstItem = true end
  local debCount1 = 0
  local debCount2 = 0
  local startindex = 0
  
  if recursive then
      for item in itemcontainer.OwnInventory.AllItemsMod do
          if item.OwnInventory and not item.OwnInventory.IsEmpty() then
              MergeStacks(item, recursive, TreatContainersAsTheirFirstItem)
          end
      end
  end
  
  for j = itemcontainer.OwnInventory.Capacity - 1, 0, -1 do
      items = itemcontainer.OwnInventory.GetItemsAt(j)
      if items[1] == nil then goto endJLoop end

      debCount1 = 0
      startindex = itemcontainer.OwnInventory.FindIndex(items[1]) - 1
      if TreatContainersAsTheirFirstItem and items[1].OwnInventory and
      not items[1].OwnInventory.IsEmpty() then 
          items = items[1].OwnInventory.GetItemsAt(
          items[1].OwnInventory.FindIndex(
          items[1].OwnInventory.FirstOrDefault()))
          startindex = itemcontainer.OwnInventory.Capacity - 1
      end
      for i = startindex, 0, -1 do
          if itemcontainer.OwnInventory.GetItemAt(i) and
          itemcontainer.OwnInventory.GetItemAt(i).Prefab.Identifier == 
          items[1].Prefab.Identifier and not items[1].OwnInventory then
              for item in items do
                  itemcontainer.OwnInventory.TryPutItem(item, i, false, true, Character.Controlled)
              end
          end
          debCount1 = debCount1 + 1 if debCount1 > 100 then 
          print("SortContainerKey.Lua Debug Infinite Loop Error") end
      end
      ::endJLoop::
  debCount2 = debCount2 + 1 if debCount2 > 100 then 
  print("SortContainerKey.Lua Debug Infinite Loop Error") end
  end
end

local function PatchContainerUI(container)
  Patches[container] = {
      recursive = not SortContainerKey.DefaultRecursive,
      TreatContainersAsTheirFirstItem = not SortContainerKey.DefaultTreatContainersAsTheirFirstItem,
      searcher = dofile(Path .. "/Lua/Searcher.lua")
  }

  local fabFrame = GUI.Frame(GUI.RectTransform(Vector2(1, 0.15), container.GuiFrame.RectTransform), "DialogBox")
  fabFrame.RectTransform.RelativeOffset = Vector2(0, -0.15)
  local fabLayout = GUI.LayoutGroup(GUI.RectTransform(Vector2.One * 0.95, fabFrame.RectTransform, GUI.Anchor.Center),true)
  local layoutCategories = GUI.LayoutGroup(GUI.RectTransform(Vector2(0.6, 0.4), fabLayout.RectTransform), true)
  local paddinglayout = GUI.LayoutGroup(GUI.RectTransform(Vector2(0.1, 0.4), fabLayout.RectTransform), true)
  local layoutSearchbar = GUI.LayoutGroup(GUI.RectTransform(Vector2(0.3, 0.4), fabLayout.RectTransform), true)
  
  local sortAlphabeticalButton = GUI.Button(
        GUI.RectTransform(
            Vector2(GUI.GUI.Scale * 38 / layoutCategories.Rect.Width, 2.5),
            layoutCategories.RectTransform
        ),
        "",
        GUI.Alignment.Center,
        "CategoryButton.Structure"
  )
  sortAlphabeticalButton.ToolTip = Localization.AlphbeticalToolTip
  sortAlphabeticalButton.OnClicked = function()
      SortContainer(Character.Controlled.SelectedItem, 
      Patches[container].recursive, 
      Patches[container].TreatContainersAsTheirFirstItem, 
      "Name")
  end
  
  local sortCategoricalButton = GUI.Button(
        GUI.RectTransform(
            Vector2(GUI.GUI.Scale * 38 / layoutCategories.Rect.Width, 2.5),
            layoutCategories.RectTransform
        ),
        "",
        GUI.Alignment.Center,
        "CategoryButton.All"
  )
  sortCategoricalButton.ToolTip = Localization.CategoricalToolTip
  sortCategoricalButton.OnClicked = function()
      SortContainer(Character.Controlled.SelectedItem, 
      Patches[container].recursive, 
      Patches[container].TreatContainersAsTheirFirstItem, 
      "Category")
  end
  
  local MergeStacksButton = GUI.Button(
        GUI.RectTransform(
            Vector2(GUI.GUI.Scale * 38 / layoutCategories.Rect.Width, 2.5),
            layoutCategories.RectTransform
        ),
        "",
        GUI.Alignment.Center,
        "CategoryButton.ItemAssembly"
  )
  MergeStacksButton.ToolTip = Localization.MergeToolTip
  MergeStacksButton.OnClicked = function()
      MergeStacks(Character.Controlled.SelectedItem, 
      Patches[container].recursive, 
      Patches[container].TreatContainersAsTheirFirstItem)
  end

  local recursiveButton = GUI.Button(
        GUI.RectTransform(
            Vector2((GUI.GUI.Scale * 38) / layoutCategories.Rect.Width, 2.5),
            layoutCategories.RectTransform
        ),
        "",
        GUI.Alignment.Center,
        "CategoryButton.Misc"
  )
  recursiveButton.ToolTip = Localization.Recursive
  recursiveButton.OnClicked = function()
      UpdateRecursive(container, recursiveButton)
  end
  
  local treatContainersAsTheirFirstItemButton = GUI.Button(
        GUI.RectTransform(
            Vector2(GUI.GUI.Scale * 38 / layoutCategories.Rect.Width, 2.5),
            layoutCategories.RectTransform
        ),
        "",
        GUI.Alignment.Center,
        "CategoryButton.Decorative"
  )
  treatContainersAsTheirFirstItemButton.ToolTip = Localization.TreatContainers
  treatContainersAsTheirFirstItemButton.OnClicked = function()
      UpdateTreatContainersAsTheirFirstItemButton(container, treatContainersAsTheirFirstItemButton)
  end
  
  local searchboxRectT = GUI.RectTransform(Vector2(1.0, 1.0), layoutSearchbar.RectTransform)
  local num = (fabLayout.Rect.Height - 30) / 2 / layoutSearchbar.Rect.Height
  searchboxRectT.RelativeOffset = Vector2(0, num)
  Patches[container].searchTextBox = GUI.TextBox(searchboxRectT)
  
  
  UpdateRecursive(container, recursiveButton)
  UpdateTreatContainersAsTheirFirstItemButton(container, treatContainersAsTheirFirstItemButton)
  setuiElemWhite(sortAlphabeticalButton)
  setuiElemWhite(MergeStacksButton)
  setuiElemWhite(sortCategoricalButton)
end



--local once = false
--Hook.Add("keyUpdate", "SortContainerKey", function()
--    if not PlayerInput.KeyDown(SortContainerKey.ActivationKey) then once = false return end
--    if once then return end
--    if Character.DisableControls then return end
--    if Character.Controlled == nil then return end
--    
--    if Character.Controlled.SelectedItem and Character.Controlled.SelectedItem.OwnInventory then
--      SortContainer(Character.Controlled.SelectedItem)
--    end
--    
--    local rightHand = Character.Controlled.Inventory.GetItemInLimbSlot(InvSlotType.RightHand)
--    local leftHand = Character.Controlled.Inventory.GetItemInLimbSlot(InvSlotType.LeftHand)
--    
--    if rightHand and rightHand.OwnInventory then
--        SortContainer(rightHand)
--    end
--    if leftHand and leftHand.OwnInventory then
--       SortContainer(leftHand)
--    end
--    
--    once = true
--end)

local function sr(query)
    Patches[GetComponent(Character.Controlled.SelectedItem, "Barotrauma.Items.Components.ItemContainer")]
    .searcher.Search(Character.Controlled.SelectedItem.OwnInventory, query)
end

Hook.Add("roundEnd", "SortContainerUIEND", function()
    t_clear(Patches)
end)

Hook.Add("item.created", "SortContainerUI", function(item)
    local container = GetComponent(item, "Barotrauma.Items.Components.ItemContainer")
    if container ~= nil then
        PatchContainerUI(container)
    end
end)

Hook.Add("think", "searchblinking", function()
    if Character.Controlled == nil or
    Character.Controlled.SelectedItem == nil or
    Character.Controlled.SelectedItem.OwnInventory == nil or
    Patches[GetComponent(Character.Controlled.SelectedItem, "Barotrauma.Items.Components.ItemContainer")] == nil
    then return end
    
    local container = GetComponent(Character.Controlled.SelectedItem, "Barotrauma.Items.Components.ItemContainer")
    local searcher = Patches[container].searcher
    
    searcher.timepoint1 = Timer.GetTime()
    if searcher.timepoint1 - searcher.timepoint2 > 1.0 then
        searcher.timepoint2 = searcher.timepoint1
        if Patches[container].searchTextBox.Text ~= "" then
            sr(Patches[container].searchTextBox.Text)
        else
            sr("asdfasdfasdfasdfasdf")
        end
        searcher.blink(Character.Controlled.SelectedItem.OwnInventory)
    end
    
end)

local function getClientLanguage()
    for _,client in Client.ClientList do
        if client then return client.Language end
    end
end







