local addonName = ...
local addon = _G[addonName]

local L = LibStub("AceLocale-3.0"):GetLocale(addonName)
local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable()

local WHITE				= "|cFFFFFFFF"
local TEAL				= "|cFF00FF9A"
local YELLOW			= "|cFFFFFF00"
local GREEN				= "|cFF00FF00"
local RECIPE_GREY		= "|cFF808080"
local RECIPE_GREEN	= "|cFF40C040"
local RECIPE_ORANGE	= "|cFFFF8040"

local view

local RecipeColors = { RECIPE_ORANGE, YELLOW, RECIPE_GREEN, RECIPE_GREY }
local RecipeColorNames = { BI["Orange"], BI["Yellow"], BI["Green"], L["Grey"] }

local ns = addon.TradeSkills.Recipes		-- ns = namespace

local function GetCurrentProfessionTable()
	local character = addon.Tabs.Characters:GetCurrent()
	return DataStore:GetProfession(character, addon.TradeSkills.CurrentProfession)		-- current profession
end

local function GetLinkByLine(index)
	local profession = GetCurrentProfessionTable()
	local _, _, spellID = DataStore:GetCraftLineInfo(profession, index)
	
	return ns:GetLink(spellID, addon.TradeSkills.CurrentProfession)
end

-- drop down menus
local function DDM_AddButton(text, value, func)
	local info = UIDropDownMenu_CreateInfo()
	
	info.text = text
	info.value = value
	info.func = func
	info.checked = nil; 
	info.icon = nil; 
	UIDropDownMenu_AddButton(info, 1); 
end

local function OnColorChange(self)
	UIDropDownMenu_SetSelectedValue(AltoholicFrameRecipesInfo_SelectColor, self.value);
	ns:BuildView()
	ns:Update()
end

function ns:DropDownColor_Initialize()
	local ts = Altoholic.TradeSkills
	if not ts.CurrentProfession then
		DDM_AddButton(L["Any"], 0, OnColorChange)
		return
	end
	
	local character = Altoholic.Tabs.Characters:GetCurrent()
	local profession = DataStore:GetProfession(character, ts.CurrentProfession)
	local orange, yellow, green, grey = DataStore:GetNumRecipesByColor(profession)
	
	DDM_AddButton(format("%s %s(%s)", L["Any"], GREEN, orange+yellow+green+grey ), 0, OnColorChange)
	DDM_AddButton(format("%s %s(%s)", RecipeColors[1] .. RecipeColorNames[1], GREEN, orange ), 1, OnColorChange)
	DDM_AddButton(format("%s %s(%s)", RecipeColors[2] .. RecipeColorNames[2], GREEN, yellow ), 2, OnColorChange)
	DDM_AddButton(format("%s %s(%s)", RecipeColors[3] .. RecipeColorNames[3], GREEN, green ), 3, OnColorChange)
	DDM_AddButton(format("%s %s(%s)", RecipeColors[4] .. RecipeColorNames[4], GREEN, grey ), 4, OnColorChange)
end

local function OnSubClassChange(self)
	UIDropDownMenu_SetSelectedValue(AltoholicFrameRecipesInfo_SelectSubclass, self.value);
	ns:BuildView()
	ns:Update()
end

function ns:DropDownSubclass_Initialize()
	DDM_AddButton(ALL_SUBCLASSES, ALL_SUBCLASSES, OnSubClassChange)
	
	local ts = Altoholic.TradeSkills
	if not ts.CurrentProfession then return end
	
	local character = Altoholic.Tabs.Characters:GetCurrent()
	local profession = DataStore:GetProfession(character, ts.CurrentProfession)
		
	for index = 1, DataStore:GetNumCraftLines(profession) do
		local isHeader, _, name = DataStore:GetCraftLineInfo(profession, index)
		
		if isHeader then
			DDM_AddButton(name, name, OnSubClassChange)
		end
	end
end

local function OnInvSlotChange(self)
	UIDropDownMenu_SetSelectedValue(AltoholicFrameRecipesInfo_SelectInvSlot, self.value);
	ns:BuildView()
	ns:Update()
end

function ns:DropDownInvSlot_Initialize()
	DDM_AddButton(ALL_INVENTORY_SLOTS, ALL_INVENTORY_SLOTS, OnInvSlotChange)

	local ts = Altoholic.TradeSkills
	if not ts.CurrentProfession then return end
	
	local invSlots = {}
	local character = Altoholic.Tabs.Characters:GetCurrent()
	local profession = DataStore:GetProfession(character, ts.CurrentProfession)
		
	for index = 1, DataStore:GetNumCraftLines(profession) do
		local isHeader, _, spellID = DataStore:GetCraftLineInfo(profession, index)
		
		if not isHeader then		-- NON header !!
			local itemID = DataStore:GetCraftInfo(spellID)
			
			if itemID then
				local _, _, _, _, _, itemType, _, _, itemEquipLoc = GetItemInfo(itemID)
				
				if itemEquipLoc and strlen(itemEquipLoc) > 0 then
					local slot = Altoholic.Equipment:GetInventoryTypeName(itemEquipLoc)
					if slot then
						invSlots[slot] = itemEquipLoc
					end
				end
			end
		end
	end
	
	for k, v in pairs(invSlots) do		-- add all the slots found
		DDM_AddButton(k, v, OnInvSlotChange)
	end

	--NONEQUIPSLOT = "Created Items"; -- Items created by enchanting
	DDM_AddButton(NONEQUIPSLOT, NONEQUIPSLOT, OnInvSlotChange)
end


function ns:BuildView()
	view = view or {}
	wipe(view)
		
	local ts = addon.TradeSkills
	local character = addon.Tabs.Characters:GetCurrent()
	local profession = DataStore:GetProfession(character, ts.CurrentProfession)
	if not profession then return end
	
	local selectedColor = UIDropDownMenu_GetSelectedValue(AltoholicFrameRecipesInfo_SelectColor)
	local selectedClass = UIDropDownMenu_GetSelectedValue(AltoholicFrameRecipesInfo_SelectSubclass)
	local selectedSlot = UIDropDownMenu_GetSelectedValue(AltoholicFrameRecipesInfo_SelectInvSlot)
	
	local hideCategory		-- hide or show the current header ?
	local hideLine			-- hide or show the current line ?
	
	for index = 1, DataStore:GetNumCraftLines(profession) do
		local isHeader, color, info = DataStore:GetCraftLineInfo(profession, index)

		if isHeader then
			hideCategory = false
			if selectedClass ~= ALL_SUBCLASSES and selectedClass ~= info then
				hideCategory = true	-- hide if a specific subclass is selected AND we're not on it
			end

			if not hideCategory then
				table.insert(view, { id = index, isCollapsed = false } )
			end
		else		-- data line
			if not hideCategory then
				hideLine = false
				if selectedColor ~= 0 and selectedColor ~= color then
					hideLine = true
				elseif selectedSlot ~= ALL_INVENTORY_SLOTS then
					if info then	-- on a data line, info contains the itemID and is numeric
						local itemID = DataStore:GetCraftInfo(info)
						if itemID then
							local _, _, _, _, _, itemType, _, _, itemEquipLoc = GetItemInfo(itemID)

							if itemType == BI["Armor"] or itemType == BI["Weapon"] then
								if itemEquipLoc and strlen(itemEquipLoc) > 0 then
									if selectedSlot ~= itemEquipLoc then
										hideLine = true
									end
								end
							else	-- not a weapon or armor ? then test if it's a generic "Created item"
								if selectedSlot ~= NONEQUIPSLOT then
									hideLine = true
								end
							end
						else		-- enchants, like socket bracker, might not have an item id, so hide the line
							hideLine = true
						end
					else
						if selectedSlot ~= NONEQUIPSLOT then
							hideLine = true
						end
					end
				end
				
				if not hideLine then
					table.insert(view, index)
				end
			end
		end
	end

	-- going from last to first, if two headers follow one another, it means that the smallest index is an empty category, so delete it
	for i = (#view - 1), 1, -1 do
		if type(view[i]) == "table" and type(view[i+1]) == "table" then
			table.remove(view, i)
		end
	end
	
	-- to avoid testing for exceptions in the previous loop, deal with the only shortcoming here (if the last entry is a table, it's an empty category, delete it)
	if type(view[#view]) == "table" then
		table.remove(view)
	end
end

function ns:Update()
	local currentProfession = addon.TradeSkills.CurrentProfession
	
	local VisibleLines = 14
	local frame = "AltoholicFrameRecipes"
	local entry = frame.."Entry"
	
	local character = addon.Tabs.Characters:GetCurrent()
	local profession = DataStore:GetProfession(character, currentProfession)
	
	AltoholicFrameRecipesInfo:Show()
	AltoholicTabCharactersStatus:SetText("")

	local curRank, maxRank = DataStore:GetSkillInfo(character, currentProfession)

	AltoholicFrameRecipesInfo_NumRecipes:SetText(
		format("%s" ..TEAL .. " %d/%d", currentProfession, curRank or 0, maxRank or 0 )
	)
	
	local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] );
	local DisplayedCount = 0
	local VisibleCount = 0
	local DrawGroup = true
	local i=1
	
	local isHeader
	local isCollapsed
	
	for index, s in pairs(view) do
		if type(s) == "table" then
			isHeader = true
			isCollapsed = s.isCollapsed
		else
			isHeader = nil
		end
		
		if (offset > 0) or (DisplayedCount >= VisibleLines) then		-- if the line will not be visible
			if isHeader then													-- then keep track of counters
				if isCollapsed == false then
					DrawGroup = true
				else
					DrawGroup = false
				end
				VisibleCount = VisibleCount + 1
				offset = offset - 1		-- no further control, nevermind if it goes negative
			elseif DrawGroup then
				VisibleCount = VisibleCount + 1
				offset = offset - 1		-- no further control, nevermind if it goes negative
			end
		else		-- line will be displayed
			if isHeader then
				if isCollapsed == false then
					_G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); 
					DrawGroup = true
				else
					_G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
					DrawGroup = false
				end
				_G[entry..i.."Collapse"]:Show()
				_G[entry..i.."Craft"]:Hide()
				
				local _, _, name = DataStore:GetCraftLineInfo(profession, s.id)
				_G[entry..i.."RecipeLinkNormalText"]:SetText(TEAL .. name)
				_G[entry..i.."RecipeLink"]:SetID(0)
				_G[entry..i.."RecipeLink"]:SetPoint("TOPLEFT", 25, 0)

				for j=1, 8 do
					_G[ entry..i .. "Item" .. j ]:Hide()
				end
				
				_G[ entry..i ]:SetID(index)
				_G[ entry..i ]:Show()
				i = i + 1
				VisibleCount = VisibleCount + 1
				DisplayedCount = DisplayedCount + 1
				
			elseif DrawGroup then
				_G[entry..i.."Collapse"]:Hide()

				local _, color, spellID = DataStore:GetCraftLineInfo(profession, s)
				local itemID, reagents = DataStore:GetCraftInfo(spellID)
				
				if itemID then
					Altoholic:SetItemButtonTexture(entry..i.."Craft", GetItemIcon(itemID), 18, 18);
					_G[entry..i.."Craft"]:SetID(itemID)
					_G[entry..i.."Craft"]:Show()
				else
					_G[entry..i.."Craft"]:Hide()
				end
				
				if spellID then
					_G[entry..i.."RecipeLinkNormalText"]:SetText(ns:GetLink(spellID, currentProfession, RecipeColors[color]))
				else
					-- this should NEVER happen, like NEVER-EVER-ER !!
					_G[entry..i.."RecipeLinkNormalText"]:SetText(L["N/A"])
				end
				_G[entry..i.."RecipeLink"]:SetID(s)
				_G[entry..i.."RecipeLink"]:SetPoint("TOPLEFT", 32, 0)

				local j = 1
				
				if reagents then
					-- "2996x2;2318x1;2320x1"
					for reagent in reagents:gmatch("([^;]+)") do
						local itemName = entry..i .. "Item" .. j;
						local reagentID, reagentCount = strsplit("x", reagent)
						reagentID = tonumber(reagentID)
						
						if reagentID then
							reagentCount = tonumber(reagentCount)
							
							_G[itemName]:SetID(reagentID)
							Altoholic:SetItemButtonTexture(itemName, GetItemIcon(reagentID), 18, 18);

							local itemCount = _G[itemName .. "Count"]
							itemCount:SetText(reagentCount);
							itemCount:Show();
						
							_G[ itemName ]:Show()
							j = j + 1
						else
							_G[ itemName ]:Hide()
						end				
					end
				end
				
				while j <= 8 do
					_G[ entry..i .. "Item" .. j ]:Hide()
					j = j + 1
				end
					
				_G[ entry..i ]:SetID(index)
				_G[ entry..i ]:Show()
				i = i + 1
				VisibleCount = VisibleCount + 1
				DisplayedCount = DisplayedCount + 1
			end
		end
	end 

	while i <= VisibleLines do
		_G[ entry..i ]:SetID(0)
		_G[ entry..i ]:Hide()
		i = i + 1
	end
	
	if VisibleCount == 0 then
		AltoholicTabCharactersStatus:SetText(format("%s: %s", currentProfession, L["No data"]))
	end
	
	FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleCount, VisibleLines, 18);
end

function ns:GetLink(spellID, profession, color)
	local name = GetSpellInfo(spellID)
	color = color or "|cffffd000"
	return format("%s|Henchant:%s|h[%s: %s]|h|r", color, spellID, profession, name)
end

function ns:ResetDropDownMenus()
	UIDropDownMenu_SetSelectedValue(AltoholicFrameRecipesInfo_SelectColor, 0);
	UIDropDownMenu_SetText(AltoholicFrameRecipesInfo_SelectColor, L["Any"])
	UIDropDownMenu_SetSelectedValue(AltoholicFrameRecipesInfo_SelectSubclass, ALL_SUBCLASSES);
	UIDropDownMenu_SetText(AltoholicFrameRecipesInfo_SelectSubclass, ALL_SUBCLASSES)
	UIDropDownMenu_SetSelectedValue(AltoholicFrameRecipesInfo_SelectInvSlot, ALL_INVENTORY_SLOTS);
	UIDropDownMenu_SetText(AltoholicFrameRecipesInfo_SelectInvSlot, ALL_INVENTORY_SLOTS)
end

function ns:ToggleAll(frame)
	-- expand or collapse all sections of the currently displayed alt /tradeskill
	if not frame.isCollapsed then
		frame.isCollapsed = true
		frame:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
	else
		frame.isCollapsed = nil
		frame:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); 
	end

	for _, s in pairs(view) do
		if type(s) == "table" then		-- it's a header
			s.isCollapsed = (frame.isCollapsed) or false
		end
	end
	
	ns:Update()
end

function ns:RecipeLink_OnEnter(frame)
	local id = frame:GetID()
	if id == 0 then return end

	local link = GetLinkByLine(id)
	
	if link then
		GameTooltip:ClearLines();
		GameTooltip:SetOwner(frame, "ANCHOR_RIGHT");
		GameTooltip:SetHyperlink(link);
		GameTooltip:AddLine(" ",1,1,1);
		GameTooltip:Show();
	end
end

function ns:RecipeLink_OnClick(frame, button)
	if ( button == "LeftButton" ) and ( IsShiftKeyDown() ) then
		if ( ChatFrameEditBox:IsShown() ) then
			local id = frame:GetID()
			if id == 0 then return end

			local link = GetLinkByLine(id)
			if link then
				ChatFrameEditBox:Insert(link);
			end
		end
	end
end

function ns:Collapse_OnClick(frame, button)
	local id = frame:GetParent():GetID()
	if id ~= 0 then
		local s = view[id]
		if s.isCollapsed ~= nil then
			if s.isCollapsed == true then
				s.isCollapsed = false
			else
				s.isCollapsed = true
			end
		end
	end
	ns:Update()
end

function ns:Link_OnClick(frame, button)
	if ( button ~= "LeftButton" ) then
		return
	end
	
	if addon:GetCurrentRealm() ~= GetRealmName() then
		addon:Print(L["Cannot link another realm's tradeskill"])
		return
	end

	local character = addon.Tabs.Characters:GetCurrent()
	local profession = DataStore:GetProfession(character, addon.TradeSkills.CurrentProfession)
	local link = profession.FullLink

	if not link then
		addon:Print(L["Invalid tradeskill link"])
		return
	end
	
	if ( ChatFrameEditBox:IsShown() ) then
		ChatFrameEditBox:Insert(addon:GetCurrentCharacter() .. ": " .. link);
	end
end
