--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| 	Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]


local PLUGIN = PLUGIN
local PANEL = {}

local boxPattern = Material("willardnetworks/tabmenu/crafting/box_pattern.png", "noclamp")

-- Shared frame painting function between two VGUI registrations
local function PaintFrames(self, w, h, bCustom)
	local value = 100
	if bCustom then value = 200 end
	if isnumber(bCustom) then value = bCustom end
	local color
	if !isnumber(bCustom) then
		color = Color(0, 0, 0, value)
	else
		color = Color(25, 25, 25, value)
	end

	surface.SetDrawColor(color)
	surface.DrawRect(0, 0, w, h)

	if bCustom then
		surface.SetDrawColor(Color(255, 255, 255, 1))
		surface.SetMaterial(boxPattern)
		surface.DrawTexturedRectUV(0, 0, w, h, 0, 0, w / SScaleMin(414 / 3), h / SScaleMin(677 / 3))
	end

	surface.SetDrawColor(Color(111, 111, 136, 255 / 100 * 30))
	surface.DrawOutlinedRect(0, 0, w, h)
end

function PANEL:Init()
	ix.gui.logs = self

	local titlePushDown = SScaleMin(30 / 3)
	local topPushDown = SScaleMin(150 / 3)
	local scale780 = SScaleMin(780 / 3)
	local scale120 = SScaleMin(120 / 3)

	self:SetWide(ScrW() - (topPushDown * 2))

	local sizeXtitle, sizeYtitle = self:GetWide(), scale120
	local sizeXcontent, sizeYcontent = self:GetWide(), scale780

	self.titlePanel = self:Add("Panel")
	self.titlePanel:SetSize(sizeXtitle, sizeYtitle)
	self.titlePanel:SetPos(self:GetWide() * 0.5 - self.titlePanel:GetWide() * 0.5)
	self.titlePanel.noRemove = true

	self:CreateTitleText()

	self.contentFrame = self:Add("Panel")
	self.contentFrame:SetSize(sizeXcontent, sizeYcontent)
	self.contentFrame:SetPos(self:GetWide() * 0.5 - self.contentFrame:GetWide() * 0.5, titlePushDown)
	self.contentFrame.noRemove = true
	self.contentFrame.Paint = function(panel, w, h)
		PaintFrames(panel, w, h, true)
	end

	self:SetTall(scale120 + scale780 + titlePushDown)
	self:Center()
	self.columnWidth = SScaleMin(150 / 3)

	self.requestedLogTypes = {}
	self.requestedLogs = {}

	self.page = 1

	netstream.Start("ixRequestLogTypes")

	self:Rebuild()
end

function PANEL:CreateTitleText()
	local logsTitleIcon = self.titlePanel:Add("DImage")
	logsTitleIcon:SetImage("willardnetworks/tabmenu/charmenu/licenses.png")
	logsTitleIcon:SetSize(SScaleMin(23 / 3), SScaleMin(17 / 3))

	self.logsTitle = self.titlePanel:Add("DLabel")
	self.logsTitle:SetFont("TitlesFontNoClamp")
	self.logsTitle:SetText("Logs")
	self.logsTitle:SizeToContents()
	self.logsTitle:SetPos(SScaleMin(33 / 3), SScaleMin(17 / 3) * 0.5 - self.logsTitle:GetTall() * 0.5)
end

function PANEL:Rebuild()
	self.contentFrame:Clear()
	  self.buttonsList = {}

	self.leftSide = self.contentFrame:Add("Panel")
	self.leftSide:Dock(LEFT)
	self.leftSide:SetWide(self.contentFrame:GetWide() * 0.20)

	self.rightSide = self.contentFrame:Add("Panel")
	self.rightSide:Dock(RIGHT)
	self.rightSide:SetWide(self.contentFrame:GetWide() * 0.80)
	self.rightSide.Paint = function() end

	self.logs = self.rightSide:Add("DListView")
	self.logs:Dock(FILL)
	self.logs:DockMargin(4, 4, 4, 4)
	self.logs:AddColumn("ID")
	self.logs:AddColumn("Heure")
	self.logs:AddColumn("Steam ID")
	self.logs:AddColumn("Texte")
	self.logs:SetHeaderHeight(SScaleMin(16 / 3))
	self.logs:SetDataHeight(SScaleMin(17 / 3))

	self.logs.Paint = function() end

	for _, v in pairs(self.logs:GetChildren()) do
		if v:GetName() != "DListView_Column" then continue end
		for _, v2 in pairs(v:GetChildren()) do
			if v2:GetName() != "DButton" then continue end
			local text = v2:GetText()
			if (text == "Steam ID" or text == "Heure" or text == "ID") then
				v:SetFixedWidth(self.columnWidth)
			end
		end
	end

	self.logs.OnRowRightClick = function(list, lineId, line)
		local dmenu = DermaMenu()
		dmenu:MakePopup()
		dmenu:SetPos(input.GetCursorPos())

		local record = line.record

		if (record) then
			dmenu:AddOption("Copier dans le presse-papiers", function()
				SetClipboardText("["..os.date("%Y-%m-%d %X", record.datetime).."] "..record.text)
			end)

			if (record.steamid) then
				dmenu:AddOption("Copier SteamID dans le presse-papiers", function()
					SetClipboardText(util.SteamIDFrom64(record.steamid))
				end)

				dmenu:AddOption("Copier SteamID64 dans le presse-papiers", function()
					SetClipboardText(record.steamid)
				end)
			end

			if (record.pos_x) then
				local pos = Vector(record.pos_x, record.pos_y, record.pos_z)

				if (CAMI.PlayerHasAccess(LocalPlayer(), "Helix - Tp", nil)) then
					dmenu:AddOption("Téléporter", function()
						netstream.Start("ixLogTeleport", pos)
					end)
				end

				dmenu:AddOption("Marquer", function()
					PLUGIN:LogMark(pos, record)
				end)
			end
		end

		for _, v in pairs(dmenu:GetChildren()[1]:GetChildren()) do
			v:SetFont("MenuFontNoClamp")
		end
	end

  self:FillLogs()

	self:CreatePagination()
  self:CreateLeftSideButtons()
end

function PANEL:FillLogs(bPage)
  self.logs:Clear()

	local logsData = self:GetCache(self.page) or self.requestedLogs

	if (logsData) then
		if (istable(logsData)and !table.IsEmpty(logsData)) then
			for _, v in pairs(logsData) do
				local e = "UNKNOWN"
				v.id, v.datetime, v.steamid, v.text = v.id or e, v.datetime or e, v.steamid or e, v.text or e

				local line = self.logs:AddLine(v.id, os.date("%Y-%m-%d %X", v.datetime), util.SteamIDFrom64(v.steamid), v.text)
				line.record = v
				line.type = v.log_type
			end

			self:SetCache(self.page, table.Copy(logsData))
		elseif (isnumber(logsData)) then
			self.logs:AddLine("Vous devez attendre "..logsData.." seconde(s) avant la prochaine recherche.")
		end
	else
		self.logs:AddLine("Aucun logs trouvés !")
	end

	if (bPage) then
		self:UpdatePage(true)
	end

	for k, v2 in pairs(self.logs:GetLines()) do
		for k2, v3 in pairs(v2:GetChildren()) do
			v3:SetFont("MenuFontNoClamp")
		end
	end

	for k3, v4 in pairs(self.logs.Columns) do
		for k4, v5 in pairs(v4:GetChildren()) do
			v5:SetFont("MenuFontNoClamp")
		end
	end

	for _, v in ipairs(self.logs.Lines) do
		v.Paint = function(panel, width, height)
			if (panel:IsSelected()) then
				SKIN.tex.Input.ListBox.Hovered(0, 0, width, height)
			elseif (panel.Hovered) then
				surface.SetDrawColor(34, 58, 112)
				surface.DrawRect(0, 0, width, height)
			elseif (panel.m_bAlt) then
				SKIN.tex.Input.ListBox.EvenLine(0, 0, width, height)
			end

			if self.highlightDeathsKnockouts:GetChecked() then
				if v.type and v.type != "chat" and v:GetColumnText( 4 ):find("knocked") then
					surface.SetDrawColor(255, 218, 185, 10)
					surface.DrawRect(0, 0, width, height)
				end

				if v:GetColumnText( 4 ):find("died") or v:GetColumnText( 4 ):find("death") or v:GetColumnText( 4 ):find("killed") then
					surface.SetDrawColor(255, 0, 0, 10)
					surface.DrawRect(0, 0, width, height)
				end
			end
		end

		for _, v2 in ipairs(v.Columns) do
			v2:SetTextColor(Color(255, 255, 255))
		end
	end
end

-- Helper paint function for outlined rectangles
local function PaintStandard(self, w, h, alpha)
	surface.SetDrawColor(Color(0, 0, 0, alpha))
	surface.DrawRect(0, 0, w, h)

	surface.SetDrawColor(Color(111, 111, 136, 255 / 100 * 30))
	surface.DrawOutlinedRect(0, 0, w, h)
end

function PANEL:CreateLeftSideButtons()
	local function search(pnl)
		local curTime = CurTime()

		if (pnl.nextClick and pnl.nextClick >= curTime) then
			LocalPlayer():Notify("Veuillez patienter avant de lancer une nouvelle recherche !")
			return
		end

		self:SetCache()

		surface.PlaySound("helix/ui/press.wav")

		self:RequestLogs()

		pnl.nextClick = curTime + 3
	end
  self.afterTextEntry = self.leftSide:Add("DTextEntry")
  self:CreateTextEntry(self.afterTextEntry, true, 32, false, false, false, "Temps après")
  self.afterTextEntry:SetTooltip("Les événements se sont déroulés après x temps. Exemple de temps : 5y2d7w = 5 ans, 2 jours et 7 semaines")
  self.afterTextEntry:SetEnterAllowed(true)
  self.afterTextEntry.OnEnter = search

	self.afterTextEntry:SetValue(ix.option.Get("logDefaultTime"))

  self.beforeTextEntry = self.leftSide:Add("DTextEntry")
  self:CreateTextEntry(self.beforeTextEntry, true, 32, false, false, false, "Temps avant")
  self.beforeTextEntry:SetTooltip("Les événements qui se sont produits avant x longtemps auparavant. Exemple de temps : 5y2d7w = 5 ans, 2 jours et 7 semaines")
  self.beforeTextEntry:SetEnterAllowed(true)
  self.beforeTextEntry.OnEnter = search

	self.descCheckBox = self.leftSide:Add("DCheckBoxLabel")
	self.descCheckBox:SetText("Inversion de l'ordre chronologique")
	self.descCheckBox:Dock(TOP)
	self.descCheckBox:SetFont("MenuFontNoClamp")
	self.descCheckBox:SetChecked(true)
	self.descCheckBox:DockMargin(2, 2, 2, 2)

	self.descCheckBox.PerformLayout = function(panel)
		local x = panel.m_iIndent or 0

		panel.Button:SetSize(SScaleMin(15 / 3), SScaleMin(15 / 3))
		panel.Button:SetPos(x, math.floor((panel:GetTall() - panel.Button:GetTall()) / 2))

		panel.Label:SizeToContents()
		panel.Label:SetPos(x + panel.Button:GetWide() + SScaleMin(9 / 3), 0)
	end

	self.highlightDeathsKnockouts = self.leftSide:Add("DCheckBoxLabel")
	self.highlightDeathsKnockouts:SetText("Mettre en évidence les morts / ko")
	self.highlightDeathsKnockouts:Dock(TOP)
	self.highlightDeathsKnockouts:SetFont("MenuFontNoClamp")
	self.highlightDeathsKnockouts:SetChecked(true)
	self.highlightDeathsKnockouts:DockMargin(2, 2, 2, 2)

	self.highlightDeathsKnockouts.PerformLayout = function(panel)
		local x = panel.m_iIndent or 0

		panel.Button:SetSize(SScaleMin(15 / 3), SScaleMin(15 / 3))
		panel.Button:SetPos(x, math.floor((panel:GetTall() - panel.Button:GetTall()) / 2))

		panel.Label:SizeToContents()
		panel.Label:SetPos(x + panel.Button:GetWide() + SScaleMin(9 / 3), 0)
	end

  self.steamidTextEntry = self.leftSide:Add("DTextEntry")
  self:CreateTextEntry(self.steamidTextEntry, true, 32, false, false, false, "SteamID")
  self.steamidTextEntry:SetTooltip("Événements commis par le joueur avec ce SteamID")
  self.steamidTextEntry:SetEnterAllowed(true)
  self.steamidTextEntry.OnEnter = search

  self.distanceTextEntry = self.leftSide:Add("DTextEntry")
  self:CreateTextEntry(self.distanceTextEntry, true, 32, false, false, false, "Distance")
  self.distanceTextEntry:SetTooltip("Événements sur la distance x de votre position actuelle. Laissez vide pour le global")
  self.distanceTextEntry:SetEnterAllowed(true)
  self.distanceTextEntry.OnEnter = search

  self.textTextEntry = self.leftSide:Add("DTextEntry")
  self:CreateTextEntry(self.textTextEntry, true, 32, false, false, false, "Nom")
  self.textTextEntry:SetTooltip("Recherche avec le nom")
  self.textTextEntry:SetEnterAllowed(true)
  self.textTextEntry.OnEnter = search

  self.mapTextEntry = self.leftSide:Add("DTextEntry")
  self:CreateTextEntry(self.mapTextEntry, true, 32, false, false, false, "Map")
  self.mapTextEntry:SetTooltip("Événement sur la carte spécifique. Laissez vide pour l'actuelle")
  self.mapTextEntry:SetEnterAllowed(true)
  self.mapTextEntry.OnEnter = search

  if (!table.IsEmpty(self.requestedLogTypes)) then
	self.logTypeCombo = self.leftSide:Add("DComboBox")
	self.logTypeCombo:SetValue("Type")
	self.logTypeCombo:SetTall(SScaleMin(32 / 3))
	self.logTypeCombo:Dock(TOP)
	self.logTypeCombo:SetFont("MenuFontNoClamp")

	self.logTypeCombo.Think = function(comboBox)
		if (comboBox:IsMenuOpen()) then
			comboBox.Menu:SetMaxHeight(ScrH() * 0.4)
		end
	end

	local logTypes = self.requestedLogTypes

	self.logTypeCombo:AddChoice("raw")
	for _, v in pairs(logTypes) do
		self.logTypeCombo:AddChoice(v)
	end
  end

  local searchButton = self.leftSide:Add("DButton")
  searchButton:Dock(BOTTOM)
	searchButton:SetText("Rechercher")
	searchButton:SetFont("MenuFontNoClamp")
	searchButton:SetTall(SScaleMin(32 / 3))
	searchButton:DockMargin(4, 4, 4, 4)
	searchButton:SetContentAlignment(5)

  searchButton.Paint = function(panel, w, h)
		PaintStandard(panel, w, h, 100)
  end

  searchButton.DoClick = search
end

function PANEL:RequestLogs()
	local data = {
		before = ix.util.GetStringTime(self.beforeTextEntry:GetValue()),
		after = ix.util.GetStringTime(self.afterTextEntry:GetValue()),
		steamid = self.steamidTextEntry:GetValue(),
		distance = tonumber(self.distanceTextEntry:GetValue()),
		text = self.textTextEntry:GetValue(),
		logType = self.logTypeCombo:GetSelected(),
		map = self.mapTextEntry:GetValue(),
		logsPerPage = 25,
		currentPage = self.page,
		desc = self.descCheckBox:GetChecked()
	}

	netstream.Start("ixRequestLogs", data)
end

function PANEL:CreatePagination()
	local paginationBg = self.rightSide:Add("DPanel")
	paginationBg:Dock(BOTTOM)
	paginationBg:DockMargin(4, 4, 4, 4)
	paginationBg:SetTall(SScaleMin(32 / 3))

	self.firstPage = paginationBg:Add("DButton")
	self.firstPage:Dock(LEFT)
	self.firstPage:SetText("RETOURNER A LA 1ERE PAGE")
	self.firstPage:SetTextColor(color_white)
	self.firstPage:SetFont("MenuFontNoClamp")
	self.firstPage:SizeToContents()
	self.firstPage:SetWide(self.firstPage:GetWide() + SScaleMin(20 / 3))
	self.firstPage:DockMargin(4, 4, 4, 4)
	self.firstPage.DoClick = function(btn)
		local curTime = CurTime()

		if (btn.nextClick and btn.nextClick >= curTime) then return end
		surface.PlaySound("helix/ui/press.wav")

		self.page = 1

		self:UpdatePage()

		btn.nextClick = curTime + 1
	end

	self.pagePrev = paginationBg:Add("DButton")
	self.pagePrev:Dock(LEFT)
	self.pagePrev:SetText("<")
	self.pagePrev:SetTextColor(color_white)
	self.pagePrev:SetFont("MenuFontNoClamp")
	self.pagePrev:DockMargin(4, 4, 4, 4)
	self.pagePrev.DoClick = function(btn)
		local curTime = CurTime()

		if (btn.nextClick and btn.nextClick >= curTime) then return end
		surface.PlaySound("helix/ui/press.wav")

		self.page = self.page - 1

		self:UpdatePage()

		btn.nextClick = curTime + 1
	end

	self.pageLabel = paginationBg:Add("DLabel")
	self.pageLabel:SetText("Page #"..self.page)
	self.pageLabel:SetFont("MenuFontNoClamp")
	self.pageLabel:SetContentAlignment(5)
	self.pageLabel:Dock(FILL)

	self.pageNext = paginationBg:Add("DButton")
	self.pageNext:Dock(RIGHT)
	self.pageNext:SetText(">")
	self.pageNext:SetFont("MenuFontNoClamp")
	self.pageNext:SetTextColor(color_white)
	self.pageNext:DockMargin(4, 4, 4, 4)
	self.pageNext.DoClick = function(btn)
		local curTime = CurTime()

		if (btn.nextClick and btn.nextClick >= curTime) then return end
		surface.PlaySound("helix/ui/press.wav")

		self.page = self.page + 1

		self:UpdatePage()

		btn.nextClick = curTime + 1
	end

	self:UpdatePage(true)

	-- Page field
	self.pageTextEntry = paginationBg:Add("DTextEntry")
	self.pageTextEntry:Dock(RIGHT)
	self.pageTextEntry:SetFont("MenuFontNoClamp")
	self.pageTextEntry:SetNumeric(true)
	self.pageTextEntry:SetTall(SScaleMin(32 / 3))
	self.pageTextEntry:DockMargin(4, 4, 4, 4)
	self.pageTextEntry:SetWide(SScaleMin(100 / 3))

	-- Goto page x button
	local gotoPage = paginationBg:Add("DButton")
	gotoPage:Dock(RIGHT)
	gotoPage:SetText("GOTO PAGE")
	gotoPage:SetFont("MenuFontNoClamp")
	gotoPage:SetTextColor(color_white)
	gotoPage:DockMargin(4, 4, 4, 4)
	gotoPage:SetWide(SScaleMin(100 / 3))
	gotoPage.DoClick = function(btn)
		local curTime = CurTime()

		if (btn.nextClick and btn.nextClick >= curTime) then return end
		surface.PlaySound("helix/ui/press.wav")

		local page = tonumber(self.pageTextEntry:GetValue())

		if (page and page > 0) then
			self.page = page

			self:UpdatePage()
		end

		btn.nextClick = curTime + 1
	end
end

function PANEL:UpdatePage(bNoRequest)
	self.pagePrev:SetDisabled(self.page == 1)
	self.pageNext:SetDisabled(table.Count(self.logs:GetLines()) < 25)
	self.pageLabel:SetText("Page #"..self.page)

	if (!bNoRequest) then
		if (self:GetCache(self.page)) then
			self:FillLogs(true)
		else
			self:RequestLogs()
		end
	end
end

function PANEL:CreateTextEntry(parent, bDockTop, height, bMultiline, bScrollbar, bEnter, placeholderText)
  parent:SetPlaceholderText(placeholderText)
	parent:Dock(TOP)
	parent:SetTall(SScaleMin(height / 3))
	parent:SetMultiline(bMultiline)
	parent:SetVerticalScrollbarEnabled(bScrollbar)
	parent:SetEnterAllowed(bEnter)
	parent:SetTextColor(Color(200, 200, 200, 255))
	parent:SetCursorColor(Color(200, 200, 200, 255))
	parent:SetFont("MenuFontNoClamp")
	parent:SetPlaceholderColor(Color(200, 200, 200, 200))

	if bDockTop then
		parent:DockMargin(2, 2, 2, 2)
	end

	parent.Paint = function(panel, w, h)
		if bMultiline then
			surface.SetDrawColor(Color(25, 25, 25, 255))
		else
			surface.SetDrawColor(Color(0, 0, 0, 100))
		end

		surface.DrawRect(0, 0, w, h)

		surface.SetDrawColor(Color(111, 111, 136, 255 / 100 * 30))
		surface.DrawOutlinedRect(0, 0, w, h)

		if (panel.GetPlaceholderText and panel.GetPlaceholderColor and panel:GetPlaceholderText() and panel:GetPlaceholderText():Trim() != "" and panel:GetPlaceholderColor() and (!panel:GetText() or panel:GetText() == "")) then
			local oldText = panel:GetText()
			local str = panel:GetPlaceholderText()
			if (str:StartWith("#")) then str = str:utf8sub(2) end
			str = language.GetPhrase(str)

			panel:SetText(str)
			panel:DrawTextEntryText(panel:GetPlaceholderColor(), panel:GetHighlightColor(), panel:GetCursorColor())
			panel:SetText(oldText)

			return
		end

		panel:DrawTextEntryText(panel:GetTextColor(), panel:GetHighlightColor(), panel:GetCursorColor())
	end
end

function PANEL:GetCache(page)
	local client = LocalPlayer()
	client.logCache = client.logCache or {}
	return client.logCache[page]
end

function PANEL:SetCache(page, cache)
	local client = LocalPlayer()
	client.logCache = client.logCache or {}

	if (page) then
		client.logCache[page] = cache
	else
		client.logCache = {}
	end
end

vgui.Register("ixLogs", PANEL, "EditablePanel")
