-- ==================================================================================================================== --
--															--
--	File			LineGraph.lua										--
--															--
--															--
--	Author			Zarnivoop, Luckycire(maintainer)		| Version	   :	  7.0.0 |	--
--										| Curse-Project-ID :	 	|	--
--										| License	   :	  MIT/X |	--
--															--
--											| Basis, thx	|		--
--															--
--															--
--				Baltha						| Version	   :	 11.2.0 |	--
--										| Curse-Project-ID :	1188318 |	--
--										| License	   :	  MIT/X |	--
--															--
--											| Revision	|		--
--															--
--															--
--	Path ( Revision )	"..\World of Warcraft\_retail_\Interface\AddOns\Skada\Misc\Changelog\ChangeLog.txt"	--
--															--
-- ==================================================================================================================== --


local _, Skada	  = ...


local L		  = LibStub("AceLocale-3.0"):GetLocale("Skada", false)
local mod	  = Skada:NewModule("LineGraph")


local libwindow	  = LibStub("LibWindow-1.1")
local libgraph    = LibStub("LibGraph-2.0")
local media	  = LibStub("LibSharedMedia-3.0")


local emptyLines  = string.rep("\n", 2)
local blankChars  = string.rep(" " , 6)


local hue
local goldenRatio = 0.618033988749895
local saturation  = 0.5
local value	  = 0.95


mod.name	  = L["Line graph"]
mod.description   = emptyLines .. blankChars .. "\124cFF00FF00" .. L["Line graph"] .. "\n" .. blankChars ..  "|cffffffff" .. L["Line graph; this can be visually customized."]


Skada:AddDisplaySystem("line", mod)




function mod:OnInitialize()

	self.db = LibStub("AceDB-3.0"):New("SkadaGraphsDB")
end




--  ==============
--  | Line Graph |
--  ==============
function mod:Create(win)

	if not win.frame then

		hue = math.random()


		win.lineGraphCache = {}
		win.colorcache     = {}


		win.num = 0


		--  ================================
		--  | Line Graph: backdrop (frame) |
		--  ================================
		local backdropFrameInfo =

				{

					bgFile	 = media:Fetch("background", "Solid"),
				 	tile	 = false,
				 	edgeSize = 0,
				 	insets	 = { left = 0, right = 0, top = 0, bottom = 0 },
				}


		--  =====================
		--  | Line Graph: frame |
		--  =====================
		win.frame     = CreateFrame("Frame", win.db.name .. "LineChartFrame", UIParent, "BackdropTemplate")
		win.frame.win = win


		win.frame:SetMovable(true)
		win.frame:SetClampedToScreen(true)
		win.frame:Size(550, 200)

		win.frame:SetBackdrop(backdropFrameInfo)


		if self.db.global.graphbgcolor then

			win.frame:SetBackdropColor(self.db.global.graphbgcolor.r or 0, self.db.global.graphbgcolor.g or 0, self.db.global.graphbgcolor.b or 0, self.db.global.graphbgcolor.a or 0.83)
		else

			self.db.global.graphbgcolor = { r, g, b, a }
			win.frame:SetBackdropColor(0, 0, 0, 0.83)
		end


		win.frame:SetPoint("TOPLEFT", UIParent, "CENTER", 0, 0)
		win.frame:EnableMouse()


		win.frame:SetScript("OnMousedown",

						function(f, button)

							if button == "RightButton" then win:RightClick() end
						end

				   )


		--  ============================
		--  | Line Graph: legend frame |
		--  ============================
		win.frame.legendframe = CreateFrame("Frame", nil, win.frame)


		win.frame.legendframe:SetWidth(345)

		win.frame.legendframe:SetPoint("TOPRIGHT"   , win.frame, "TOPRIGHT"   , -10, -20)
		win.frame.legendframe:SetPoint("BOTTOMRIGHT", win.frame, "BOTTOMRIGHT", -10,  20)


		win.frame.legendframe.AddLegend     = Skada.AddLegend
		win.frame.legendframe.ClearLegends  = Skada.ClearLegends


		win.frame.legendframe.ClickLegend   = function(id, label, button)

								Skada.ClickRow(win.frame, win, id, label, button)
						      end


		win.frame.legendframe.EnterLegend   = function(id, label)

								Skada.EnterRow(win.frame, win, id, label)
						      end


		win.frame.legendframe.LeaveLegend   = function(id, label)

								Skada.LeaveRow(win.frame, win, id, label)
						      end


		win.frame.legendframe.AdjustLegends = Skada.AdjustLegends


		Skada.SetupLegendScrolling(win.frame.legendframe)


		win.frame.MakeResizable		    = Skada.MakeResizable
		win.frame.OnResizingInProgress	    = function(self)

								win:UpdateDisplay()
								win.frame.legendframe:AdjustLegends()
						      end


		win.frame.OnResizingDone 	    = function(self)

								win.db.width  = win.frame:GetWidth()
							 	win.db.height = win.frame:GetHeight()
						      end


		win.frame:MakeResizable()
		win.frame:SetResizeBounds(484, 198)


		--  ========================================
		--  | Line Graph: backdrop (button header) |
		--  ========================================
		local backdropButtonInfo =

				{

					bgFile	 = media:Fetch("statusbar", "Aluminium"),
				 	tile	 = false,
				 	edgeSize = 0,
				 	insets	 = { left = 0, right = 0, top = 0, bottom = 0 },
				}


		--  =============================
		--  | Line Graph: button header |
		--  =============================
		win.header = CreateFrame("Button", nil, win.frame, "BackdropTemplate")


		win.header:SetHeight(24)
		win.header:SetPoint("BOTTOMLEFT" , win.frame, "TOPLEFT" , 0, 0)
		win.header:SetPoint("BOTTOMRIGHT", win.frame, "TOPRIGHT", 0, 0)


		win.header:SetScript("OnMouseDown",

						function()

							win.frame:StartMoving()
						end

				       )


		win.header:SetScript("OnMouseUp",

						function()

							win.frame:StopMovingOrSizing()
							libwindow.SavePosition(win.frame)
						end

				       )


		win.header:SetBackdrop(backdropButtonInfo)


		if self.db.global.graphheaderbg then

			win.header:SetBackdropColor(self.db.global.graphheaderbg.r or 0.1, self.db.global.graphheaderbg.g or 0.1, self.db.global.graphheaderbg.b or 0.3, self.db.global.graphheaderbg.a or 0.8)
		else

			self.db.global.graphheaderbg = { r, g, b, a }
			win.header:SetBackdropColor(0.1, 0.1, 0.3, 0.8)
		end


		win.header:SetText(win.db.name)


		--  ====================
		--  | Line Graph: font |
		--  ====================
		local titleFont = CreateFont("TitleFont")


		titleFont:SetFont(media:Fetch('font', win.db.barfont), win.db.barfontsize, win.db.barfontflags)


		win.header:SetNormalFontObject(titleFont)


		win.header.AddButton     = Skada.AddButton
		win.header.AdjustButtons = Skada.AdjustButtons


		if not(self.db.global.enableheader) then self.db.global.enableheader = true end


		local size = min(win.frame:GetWidth() - 140, win.frame:GetHeight())
		local g = libgraph:CreateGraphLine("LineGraph", win.frame, "TOPLEFT", "TOPLEFT", 0, 0, size, size)


		g:SetGridColor( {   0,   0,   0, 0.0 } )
		g:SetAxisDrawing(true,true)
		g:SetAxisColor( { 1.0, 1.0, 1.0, 1.0 } )
		g:SetYLabels(true, false)
		g:SetAutoScale(false)


		win.chart = g


		--  =======================
		--  | Line Graph: buttons |
		--  =======================
		Skada:MenuButton(win, mod, reportButton, function() Skada:ShowPopup(win)        end, 20,  15, "Interface\\Buttons\\UI-StopButton"	  , "Interface\\Buttons\\UI-StopButton")
		Skada:MenuButton(win, mod, reportButton, function() Skada:OpenReportWindow(win) end, 20,   0, "Interface\\Buttons\\UI-GuildButton-MOTD-Up", "Interface\\Buttons\\UI-GuildButton-MOTD-Up")
		Skada:MenuButton(win, mod, menuButton  , function() Skada:OpenMenu(win)         end, 20, -15, "Interface\\Buttons\\UI-OptionsButton"	  , "Interface\\Buttons\\UI-OptionsButton")
	end


	win.frame:Show()


	libwindow.RegisterConfig(win.frame, win.db)
	libwindow.RestorePosition(win.frame)
end




function mod:Destroy(win)

	wipe(win.colorcache)


	win.colorcache	   = nil
	hue		   = math.random()


	win.frame.legendframe:ClearLegends()
	win.frame:Hide()


	win.frame	   = nil
	win.chart	   = nil
	win.header	   = nil
	win.lineGraphCache = nil
	win.num		   = nil
end




function mod:Wipe(win)

	win.chart:ResetData()
	wipe(win.lineGraphCache)


	win.num = 0
	win.frame.legendframe:ClearLegends()
end




function mod:SetTitle(win, title)

	win.header:SetText(title)
end




function mod:Update(win)

	if not InCombatLockdown() then collectgarbage("collect") end
	if not(self.db.global.graphRealTimeValues) then self.db.global.graphRealTimeValues = "RealTime" end


	if self.db.global.graphmaxpoints and self.db.global.graphmaxpoints >= 10 then

		maxPoints = self.db.global.graphmaxpoints
	else

		self.db.global.graphmaxpoints = maxPoints
	end


	for i, data in ipairs(win.dataset) do

		if data.id and not data.ignore then

			local color


			if win.colorcache[data.id] then

				color = win.colorcache[data.id]
			else

				hue   = hue + goldenRatio
				hue   = hue - (math.floor(hue))

				color = Skada.GenerateColor(hue, saturation, value)


				win.colorcache[data.id] = color
			end

			if(self.db.global.graphshowtotal or (not self.db.global.graphshowtotal and data.label  ~= "Total")) then

				if win.lineGraphCache[data.id] then

					table.insert(win.lineGraphCache[data.id].values, { x = win.num, y = data.value })


					if #win.lineGraphCache[data.id].values > maxPoints then table.remove(win.lineGraphCache[data.id].values, 1) end
				else

					local color


					if win.colorcache[data.id] then

						color = win.colorcache[data.id]
					else

						hue			= hue + goldenRatio
						hue			= hue - (math.floor(hue))

						color			= Skada.GenerateColor(hue, saturation, value)
						win.colorcache[data.id] = color
					end


					win.lineGraphCache[data.id] = { num = win.num, values = { x = win.num, y = data.value }, color = color }
				end
			end


			if data.id ~= nil and data.valuetext ~= nil then

				data.spellid = (tostring(data.spellid  ) or  0)
				data.label   = data.label .. "|" .. data.valuetext .. "|" .. data.spellid


				win.frame.legendframe:AddLegend(data.id, data.label, color)
			end
		end
	end


	win.frame.legendframe:AdjustLegends()
	win.chart:ResetData()


	local min_x, max_x = 0, maxPoints
	local min_y, max_y = 0, 0

	local count1	   = 0
	local count2	   = 0

	local cache	   = {}


	for id, data in pairs(win.lineGraphCache) do

		count1 = count1 + 1


		if count1 > 5 then break end


		local points		= {}
		local y_points_tmpTable = {}


		local calculatedValueY


		for i, value in ipairs(data.values) do

			if (self.db.global.graphRealTimeValues == "RealTime") then

				calculatedValueY = data.values[i].y - data.values[max(1, i - 1)].y
			else

				calculatedValueY = value.y
			end


			if calculatedValueY >= 0 then table.insert(points, { maxPoints, calculatedValueY }) end


			for idx, valuePoint in ipairs(points) do points[idx][1] = points[idx][1] - 1 end


			if #points > maxPoints then table.remove(points, 1) end
		end


		count2 = count2 + 1


		for k, val in ipairs(points) do table.insert(y_points_tmpTable, points[k][2]) end


		table.sort(y_points_tmpTable)


		if y_points_tmpTable[#y_points_tmpTable] and y_points_tmpTable[#y_points_tmpTable] > 0 then

			if max_y > y_points_tmpTable[#y_points_tmpTable] then

				if count2 > maxPoints then max_y = y_points_tmpTable[#y_points_tmpTable] end
			else

				max_y = y_points_tmpTable[#y_points_tmpTable]
			end
		end


		y_points_tmpTable = nil

		
		table.insert(cache, { p = points, c = data.color })
	end


	win.chart.NeedsUpdate = true

	win.chart:SetXAxis(max(0, min_x), max(1, max_x))
	win.chart:SetYAxis(max(0, min_y), max(1, max_y))

	win.chart:SetGridSpacing(max(1, math.floor(max_x / 4)), max(1, math.floor(max_y / 4)))


	for i, stuff in ipairs(cache) do win.chart:AddDataSeries(stuff.p, stuff.c) end


	win.chart:OnUpdate()
	win.num = win.num + 1
end




function mod:Show(win)

	win.frame:Show()
end




function mod:Hide(win)

	win.frame:Hide()
end




function mod:IsShown(win)

	return win.frame:IsShown()
end




function mod:ApplySettings(win)

	if win.db.barslocked then

		win.header:EnableMouse(false)
		win.frame.resizebutton:Hide()
	else

		win.header:EnableMouse(true)
		win.frame.resizebutton:Show()
	end


	if self.db.global.enableheader then

		win.header:Show()
	else

		win.header:Hide()
	end


	if self.db.global.graphbgcolor then

		if not self.db.global.graphbgcolor.r then self.db.global.graphbgcolor.r =    0 end
		if not self.db.global.graphbgcolor.g then self.db.global.graphbgcolor.g =    0 end
		if not self.db.global.graphbgcolor.b then self.db.global.graphbgcolor.b =    0 end
		if not self.db.global.graphbgcolor.a then self.db.global.graphbgcolor.a = 0.83 end


		win.frame:SetBackdropColor(self.db.global.graphbgcolor.r or 0, self.db.global.graphbgcolor.g or 0, self.db.global.graphbgcolor.b or 0, self.db.global.graphbgcolor.a or 0.83)
	end


	if self.db.global.graphheaderbg then

		if not self.db.global.graphheaderbg.r then self.db.global.graphheaderbg.r = 0.1 end
		if not self.db.global.graphheaderbg.g then self.db.global.graphheaderbg.g = 0.1 end
		if not self.db.global.graphheaderbg.b then self.db.global.graphheaderbg.b = 0.3 end
		if not self.db.global.graphheaderbg.a then self.db.global.graphheaderbg.a = 0.8 end


		win.header:SetBackdropColor(self.db.global.graphheaderbg.r or 0.1, self.db.global.graphheaderbg.g or 0.1, self.db.global.graphheaderbg.b or 0.3, self.db.global.graphheaderbg.a or 0.8)
	end


	if self.db.global.graphmaxpoints and self.db.global.graphmaxpoints >= 10 then

		maxPoints = self.db.global.graphmaxpoints
	else

		self.db.global.graphmaxpoints = maxPoints
	end

	
	local lineFontHeader = CreateFont("TitleFont")


	if not self.db.global.graphheaderfont	   then self.db.global.graphheaderfont      = "Accidental Presidency" end
	if not self.db.global.graphheaderfontsize  then self.db.global.graphheaderfontsize  = 12		      end
	if not self.db.global.graphheaderfontflags then self.db.global.graphheaderfontflags = ""		      end


	lineFontHeader:SetFont(media:Fetch('font', self.db.global.graphheaderfont), self.db.global.graphheaderfontsize, self.db.global.graphheaderfontflags)


	win.header:SetNormalFontObject(lineFontHeader)
end




function mod:AddDisplayOptions(win, options)

	local db	= self.db


   options.graphoptions =

			{

			   type = "group",
			   name = L["Graph"],
			  order = 1,

			   args =

				{
		
			    lineoptions =

					{

						   type = "description",
						   name = "\124cnNORMAL_FONT_COLOR:" .. L["Options: line graph"]  .. " " ..  "|cffffffff" .. win.db.name .. emptyLines,
						  order = 0,

					},

			   enableheader =

					{

						   type = "toggle",
						   name = L["Enable header"],
						   desc = L["Enables/disables the header bar."],
						    get = function()

								  return db.global.enableheader
							  end,
						    set = function(win, showtotal)

								  db.global.enableheader = not db.global.enableheader
								  Skada:ApplySettings()
							  end,
						  order = 1,

					},

			       headerbg =

					{

						   type = "color",
						   name = L["Background color"],
						   desc = L["Choose the background color for the header."],
					       hasAlpha = true,
						    get = function(i)

								  return db.global.graphheaderbg.r, db.global.graphheaderbg.g, db.global.graphheaderbg.b, db.global.graphheaderbg.a
							  end,
						    set = function(i, r,g,b,a)

								  db.global.graphheaderbg = { ["r"] = r, ["g"] = g, ["b"] = b, ["a"] = a }
								  Skada:ApplySettings()
							  end,

						  order = 2,

					},

				graphbg =

					{

						   type = "color",
						   name = L["Background color"],
						   desc = L["Choose the background color for the graph."],
					       hasAlpha = true,
						    get = function(i)

								  return db.global.graphbgcolor.r, db.global.graphbgcolor.g, db.global.graphbgcolor.b, db.global.graphbgcolor.a
							  end,


						    set = function(i, r,g,b,a)

								  db.global.graphbgcolor = {["r"] = r, ["g"] = g, ["b"] = b, ["a"] = a}
								  Skada:ApplySettings()
							  end,
						  order = 3,

					},

			 graphmaxpoints =

					{

						   type = "range",
						   name = L["Graph max points"],
						   desc = L["Select a number of points for the graph."],
						    min = 10,
						    max = 120,
						   step = 1,
						    get = function()

								  return db.global.graphmaxpoints
							  end,
						    set = function(win, maxpoints)

								  db.global.graphmaxpoints = maxpoints
								  Skada:ApplySettings()
							  end,
						  order = 4,

					},

			graphheaderfont =

					{
						   type = 'select',
					  dialogControl = 'LSM30_Font',
						   name = L["Font"],
						   desc = L["The font used by the header."],
						 values = AceGUIWidgetLSMlists.font,
						    get = function()

								  return db.global.graphheaderfont or 12
							  end,
						    set = function(win,key)

								  db.global.graphheaderfont = key
								  Skada:ApplySettings()
							  end,
						  order = 5,

					},

		    graphheaderfontsize =

					{

						   type = "range",
						   name = L["Font size"],
						   desc = L["The font size used by the header."],
						    min = 12,
						    max = 40,
						   step = 1,
						    get = function()

								  return db.global.graphheaderfontsize
							  end,
						    set = function(win, size)

								  db.global.graphheaderfontsize = size
								  Skada:ApplySettings()
							  end,
						  order = 6,

					},

		   graphheaderfontflags =

					{

						   type = 'select',
						   name = L["Font flags"],
						   desc = L["Sets the font flags for the header."],
						 values = { [""] = L["None"], ["OUTLINE"] = L["Outline"], ["THICKOUTLINE"] = L["Thick outline"],["MONOCHROME"] = L["Monochrome"], ["OUTLINEMONOCHROME"] = L["Outlined monochrome"] },
						    get = function()

								  return db.global.graphheaderfontflags
							  end,
						    set = function(win,key)

								  db.global.graphheaderfontflags = key
								  Skada:ApplySettings()
							  end,
						  order = 7,

					},

		    graphRealTimeValues =

					{

						   type = 'select',
						   name = L["Select data type"],
						   desc = L["Select the type of data to record."],
						 values = {["RealTime"] = "RealTime", ["Total"] = "Total"},
						    get = function()

								  return db.global.graphRealTimeValues
							  end,
						    set = function(win, key)

								  db.global.graphRealTimeValues = key
								  Skada:ApplySettings()
							  end,
						  order = 8,

					},

			 graphshowtotal =

					{
						   type = "toggle",
						   name = L["Show total"],
						   desc = L["Show total data when applicable."],
						    get = function()

								  return db.global.graphshowtotal
							  end,
						    set = function(win, showtotal)

								  db.global.graphshowtotal = not db.global.graphshowtotal
								  Skada:ApplySettings()
							  end,
						  order = 9,
					},
				}
			}
end