local L = AceLibrary("AceLocale-2.2"):new("Sanity2")
local dewdrop = AceLibrary("Dewdrop-2.0")
local tablet = AceLibrary("Tablet-2.0")
local crayon = AceLibrary("Crayon-2.0")
local debug = AceLibrary("AceDebug-2.0")

Sanity.columns = {
	{
		name 		= L["Cat"],
		key 		= "TypeSort",
		width 		= 35,
		fixed		= true,
		type		= "button",
		inherits	= "SanityItemIcon",
		desc 		= L["Item's category. This includes any custom categories you set."]
	},
	{
		name 		= L["Name"],
		key			= "Name",
		desc 		= L["Item name"]
	},
	{
		name 		= L["Quality"],
		key 		= "Quality",
		nocolumn 	= true,
		desc		= L["Item's quality"]
	},
	{
		name 		= L["Level"],
		nocolumn 	= true,
		minwidth 	= 18,
		key 		= "MinLevel",
		desc		= L["Minimum level required to equip or use this item."]
	},
	{
		name 		= L["Stacks"],
		minwidth 	= 35,
		key 		= "Stacks",
		desc		= L["Number of stacks of this item you possess"]
	},
	{
		name 		= L["Tags"],
		key 		= "Tags",
		minwidth 	= 18,
		hidden		= true,
		desc		= L["Tags you've assigned to this item."]
	},
	{
		name 		= L["Owner"],
		key 		= "Owner",
		desc		= L["Character that owns this item."]
	},
	{
		name 		= L["Location"],
		key 		= "Location",
		minwidth 	= 75,
		desc		= "Where this item is located (bags, bank, etc)."
	}
}

local options = {
    type='group',
    args = {
        show = {
        	type = "execute",
        	desc = L["Toggle the main Sanity window"],
        	name = L["Toggle Sanity"],
        	func = "Toggle",
        	order = 102
        },

        toggleat = {
        	type = "group",
        	name = L["Toggle At..."],
        	desc = L["Cause Sanity to automatically toggle on and off on certain events."],
        	args = {
		        vendortoggle = {
		            type = 'toggle',
		            name = L['Toggle At Vendors'],
		            desc = L['Open Sanity when you speak to a vendor'],
		            get = function()
		            	return Sanity.db.profile.ToggleOnVendor
		            end,
		            set = function(v)
		            	Sanity.db.profile.ToggleOnVendor = v
		            end
		        },
		        banktoggle = {
		            type = 'toggle',
		            name = L['Toggle At Bank'],
		            desc = L['Open Sanity when you speak to a banker'],
		            get = function()
		            	return Sanity.db.profile.ToggleOnBank
		            end,
		            set = function(v)
		            	Sanity.db.profile.ToggleOnBank = v
		            end
		        },
		    		mailtoggle = {
		            type = 'toggle',
		            name = L['Toggle At Mailboxes'],
		            desc = L['Open Sanity when you open a mailbox'],
		            get = function()
		            	return Sanity.db.profile.ToggleOnMail
		            end,
		            set = function(v)
		            	Sanity.db.profile.ToggleOnMail = v
		            end
		        }, 		        
		      }
	      },
	      bagbutton = {
        	type = "group",
        	name = L["Bag Button Options"],
        	desc = L["Options relating to the bag button."],
        	args = {
		        showbag = {
		            type = 'toggle',
		            name = L['Show Bag Button'],
		            desc = L["Show the Sanity bag button."],
		            get = function()
		            	return Sanity.db.profile.ShowBagIcon
		            end,
		            set = function(v)
		            	Sanity.db.profile.ShowBagIcon = v
		            	if v then
		            		SanityBagButton:Show()
		            	else
		            		SanityBagButton:Hide()
		            	end
		            end
		        },        
		        bagscale = {
		            type = 'range',
		            name = L['Bag Icon Scale'],
		            step = 0.05,
		            min = 0.4,
		            max = 5.0,
		            isPercent = true,
		            desc = L["Changes the scale of the Sanity bag icon"],
		            get = function()
		            	return Sanity.db.profile.Bagscale
		            end,
		            set = function(v)
		            	if v ~= Sanity.db.profile.Bagscale then
										SanityBagButton:SetScale(v);
										SanityBagButton:ClearAllPoints();
										SanityBagButton:SetPoint("CENTER", "UIParent", "CENTER");
			            	Sanity.db.profile.Bagscale = v
			            end
		            end
		        }                	
        	}
	      },
	      tooltipoptions = {
        	type = "group",
        	name = L["Tooltip Options"],
        	desc = L["Options relating to tooltips."],
        	args = {
		        searchtips = {
		            type = 'toggle',
		            name = L['Search Tooltips'],
		            desc = L["Includes tooltip data in searches. This lets you perform highly advanced searches, but may slow you down. Turn this off if Sanity is slow, or you don't want the advanced searches."],
		            get = function()
		            	return Sanity.db.profile.SearchTooltips
		            end,
		            set = function(v)
		            	Sanity.db.profile.SearchTooltips = v
		            end
		        },            	
		        show_tooltip_info = {
		        	type = 'toggle',
		        	desc = L["Show which of your characters has how many of an item when you mouse over it"],
		        	name = L["Show Item Tooltip Information"],
		          get = function()
		          	return Sanity.db.profile.ShowCharItemTips
		          end,
		          set = function(v)
		          	Sanity.db.profile.ShowCharItemTips = v
		          end
		        },
		        tip_color = {
		            type = 'color',
		            name = L['Tooltip Info Color'],
		            desc = L["Changes the color of the additional info Sanity adds to the tooltips."],
		            get = function()
		            	return Sanity.db.profile.tooltipInfoColor.r,
		            		Sanity.db.profile.tooltipInfoColor.g,
		            		Sanity.db.profile.tooltipInfoColor.b, 1
		            end,
		            set = function(r,g,b,a)
		            	Sanity.db.profile.tooltipInfoColor.r = r
		            	Sanity.db.profile.tooltipInfoColor.g = g
		            	Sanity.db.profile.tooltipInfoColor.b = b
		            end
		        }, 
		        tip_cat_color = {
		            type = 'color',
		            name = L['Category Info Color'],
		            desc = L["Changes the color of the additional info Sanity adds to the tooltips."],
		            get = function()
		            	return Sanity.db.profile.tooltipCatInfoColor.r,
		            		Sanity.db.profile.tooltipCatInfoColor.g,
		            		Sanity.db.profile.tooltipCatInfoColor.b, 1
		            end,
		            set = function(r,g,b,a)
		            	Sanity.db.profile.tooltipCatInfoColor.r = r
		            	Sanity.db.profile.tooltipCatInfoColor.g = g
		            	Sanity.db.profile.tooltipCatInfoColor.b = b
		            end
		        },  
		        tip_tag_color = {
		            type = 'color',
		            name = L['Tag Info  Color'],
		            desc = L["Changes the color of the additional info Sanity adds to the tooltips."],
		            get = function()
		            	return Sanity.db.profile.tooltipTagInfoColor.r,
		            		Sanity.db.profile.tooltipTagInfoColor.g,
		            		Sanity.db.profile.tooltipTagInfoColor.b, 1
		            end,
		            set = function(r,g,b,a)
		            	Sanity.db.profile.tooltipTagInfoColor.r = r
		            	Sanity.db.profile.tooltipTagInfoColor.g = g
		            	Sanity.db.profile.tooltipTagInfoColor.b = b
		            end
		        },  		        		         		        
        	}
	      },
	      fubaroptions = {
        	type = "group",
        	name = L["FuBar Plugin Options"],
        	desc = L["Options relating to the FuBar plugin."],
        	args = {
		        invertslots = {
		            type = 'toggle',
		            name = L['Show Free Bag Slots'],
		            desc = L["Show the number of slots free rather than the slots used."],
		            get = function()
		            	return Sanity.db.profile.FuBarShowFreeSlots
		            end,
		            set = function(v)
		            	Sanity.db.profile.FuBarShowFreeSlots = v
		            	Sanity:OnTextUpdate()
		            end
		        }
        	}
	      },	      
        advancedoptions = {
        	type = "group",
        	name = L["Advanced Options"],
        	desc = L["Advanced Options"],
        	order = 101,
        	args = {
		        deletesettings = {
		        		type = "execute",
		        		func = "ResetSanity",
		        		name = L["Reset Database"],
		        		desc = L["Resets all of Sanity's settings and reloads your UI."]
		        },
		        usedangerous = {
		            type = 'toggle',
		            name = L['Use Dangerous Item Code'],
		            desc = L["Attempts to pull data on unknown items from the server. However, if the server hasn't seen this item since its last restart, you will be disconnected. This is off by default."],
		            get = function()
		            	return Sanity.db.profile.UseDangerousItems
		            end,
		            set = function(v)
		            	Sanity.db.profile.UseDangerousItems = v
		            end
		        },
        	}
        },
        displayoptions = {
        	type = "group",
        	name = L["Display Options"],
        	desc = L["Modify Sanity's look and feel"],
        	args = {
		        collapsestacks = {
		            type = 'toggle',
		            name = L['Collapse Multiple Stacks'],
		            desc = L['Collapses multiple stacks into a single stack for visual clarity.'],
		            get = function()
		            	return Sanity.db.profile.CollapseStacks
		            end,
		            set = function(v)
		            	Sanity.db.profile.CollapseStacks = v
		            	SanityItemCache:ScanAll()
		            	Sanity.displayListDirty = true
		            	Sanity:Refresh()
		            end
		        },       
		        closeoncombat = {
		            type = 'toggle',
		            name = L['Close On Combat'],
		            desc = L['Closes Sanity when you enter combat. This prevents Sanity from getting locked in your way upon entering combat.'],
		            get = function()
		            	return Sanity.db.profile.CloseOnCombat
		            end,
		            set = function(v)
		            	Sanity.db.profile.CloseOnCombat = v
		            end
		        },
		        usesubtypes = {
		            type = 'toggle',
		            name = L['Use Item Subtypes'],
		            desc = L['Break down item categories with subtypes (plate, mail, junk, etc).'],
		            get = function()
		            	return Sanity.db.profile.UseSubTypes
		            end,
		            set = function(v)
		            	Sanity.db.profile.UseSubTypes = v
		            	SanityItemCache:ScanAll()
		            	Sanity.displayListDirty = true
		            	Sanity:Refresh()
		            end
		        },
			      linkcolor = {
			          type = 'toggle',
			          name = L['Link Coloring'],
			          desc = L['Use item rarity to color links'],
			          get = function()
			          	return Sanity.db.profile.UseColors
			          end,
			          set = function(v)
			          	Sanity.db.profile.UseColors = v
			          end
			      },        	
		        alpha = {
		            type = 'color',
		            name = L['Background Color'],
		            desc = L["Change Sanity's background"],
		            hasAlpha = true,
		            get = function()
		            	return Sanity.db.profile.bg_r,
		            			Sanity.db.profile.bg_g,
		            			Sanity.db.profile.bg_b,
		            			Sanity.db.profile.Alpha
		            end,
		            set = function(r,g,b,a)
		            	Sanity.db.profile.bg_r = r
		            	Sanity.db.profile.bg_g = g
		            	Sanity.db.profile.bg_b = b
		            	Sanity.db.profile.Alpha = a
		            	Sanity:UpdateBackground()
		            end
		        },
		        itemheight = {
		            type = 'range',
		            name = L['Item Height'],
		            min = 15,
		            max = 150,
		            step = 1,
		            isPercent = false,
		            desc = L["Change the height of each item"],
		            get = function()
		            	return Sanity.db.profile.ItemHeight
		            end,
		            set = function(v)
		            	Sanity.db.profile.ItemHeight = v
		            	Sanity:SetupItems()
		            end
		        },        
		        headers = {
		            type = 'toggle',
		            name = L['Show Header'],
		            desc = L['Toggle item headers on and off'],
		            get = function()
		            	return Sanity.db.profile.UseHeaders
		            end,
		            set = function(v)
		            	Sanity.db.profile.UseHeaders = v
		            	Sanity:Refresh()
		            end
		        },                
		        scale = {
		            type = 'range',
		            name = L['Scale'],
		            step = 0.05,
		            min = 0.1,
		            max = 2.0,
		            isPercent = true,
		            desc = L["Changes the scale of the Sanity window"],
		            get = function()
		            	return Sanity.db.profile.Scale
		            end,
		            set = function(v)
		            				if Sanity.db.profile.Scale ~= v then
			            				Sanity.db.profile.Scale = v
		  	          				SanityFrame:SetScale(v)
													SanityFrame:ClearAllPoints();
													SanityFrame:SetPoint("CENTER", "UIParent", "CENTER");
												end
		            			end
		        },			      
        	}
        },
        usebags = {
        	type = "group",
        	name = L["Include Bags"],
        	desc = L["Bags to include in the display"],
        	args = {
			      usebag0 = {
			          type = 'toggle',
			          name = L['Include Backpack'],
			          desc = L["Scan the backpack and include it in Sanity's display."],
			          get = function()
			          	return Sanity.db.profile.ScanBag0
			          end,
			          set = function(v)
			          	Sanity.db.profile.ScanBag0 = v
			          	arg1 = 0
			          	SanityItemCache:BAG_UPDATE()
			          end
			      },
			      usebag1 = {
			          type = 'toggle',
			          name = L['Include Bag 1'],
			          desc = L["Scan Bag #1 and include it in Sanity's display."],
			          get = function()
			          	return Sanity.db.profile.ScanBag1
			          end,
			          set = function(v)
			          	Sanity.db.profile.ScanBag1 = v
			          	arg1 = 1
			          	SanityItemCache:BAG_UPDATE()
			          end
			      },
			      usebag2 = {
			          type = 'toggle',
			          name = L['Include Bag 2'],
			          desc = L["Scan Bag #2 and include it in Sanity's display."],
			          get = function()
			          	return Sanity.db.profile.ScanBag2
			          end,
			          set = function(v)
			          	Sanity.db.profile.ScanBag2 = v
			          	arg1 = 2
			          	SanityItemCache:BAG_UPDATE()
			          end
			      },
			      usebag3 = {
			          type = 'toggle',
			          name = L['Include Bag 3'],
			          desc = L["Scan Bag #3 and include it in Sanity's display."],
			          get = function()
			          	return Sanity.db.profile.ScanBag3
			          end,
			          set = function(v)
			          	Sanity.db.profile.ScanBag3 = v
			          	arg1 = 3
			          	SanityItemCache:BAG_UPDATE()
			          end
			      },
			      usebag4 = {
			          type = 'toggle',
			          name = L['Include Bag 4'],
			          desc = L["Scan Bag #4 and include it in Sanity's display."],
			          get = function()
			          	return Sanity.db.profile.ScanBag4
			          end,
			          set = function(v)
			          	Sanity.db.profile.ScanBag4 = v
			          	arg1 = 4
			          	SanityItemCache:BAG_UPDATE()
			          end
			      },			      			      			      
			      usekeyring = {
			          type = 'toggle',
			          name = L['Include Keyring'],
			          desc = L["Scan the key ring and include it in Sanity's display."],
			          get = function()
			          	return Sanity.db.profile.ScanKeyRing
			          end,
			          set = function(v)
			          	Sanity.db.profile.ScanKeyRing = v
			          	arg1 = KEYRING_CONTAINER
			          	SanityItemCache:BAG_UPDATE()
			          end
			      }                	
        	}
        },
    },
}

Sanity.OnMenuRequest = options
Sanity:RegisterChatCommand({"/sanity", "/s2"}, options, "SANITY2")

Sanity.name = "Sanity"
Sanity.hasIcon = true

function Sanity:OnClick()	
	Sanity:Toggle()
end

function Sanity:OnTextUpdate()
	local bf, bs = SanityItemCache:GetBagData()
	if bs == 0 then bs = 1 end
	local c = ""
	if self.db.profile.FuBarShowFreeSlots then
		bf = bs - bf
	end
	if self.db.profile.FuBarShowFreeSlots then
		c = crayon:GetThresholdHexColor(bf / bs)
	else
		c = crayon:GetThresholdHexColor(1 - (bf / bs))
	end
	-- self:SetIcon("Interface\\Buttons\\Button-Backpack-Up")
	self:SetIcon("Interface\\Icons\\Spell_Holy_PainSupression")
	if (bf) then
		self:SetText("|cff" .. c .. 
			bf .. " |cffffffff/ |cff" .. c .. bs
		)
	else
		self:SetText("Sanity")
	end
end

function Sanity:OnTooltipUpdate()
	local bf, bs = SanityItemCache:GetBagData(UnitName("player"))
	local bnf, bns = SanityItemCache:GetBankData(UnitName("player"))
	
	local r,g,b = crayon:GetThresholdColor(1 - ((bf + bnf) / (bs + bns)))
    local cat = tablet:AddCategory(
        'text', "Bag Usage",
        'columns', 2,
        "hideBlankLine", true,
        'child_textR', r,
        'child_textG', g,
        'child_textB', b
    )
    local bnf, bns = SanityItemCache:GetBankData()
    
    cat:AddLine(
        'text', "Bags: " ..bf .. "/" .. bs
    )
    cat:AddLine(
        'text', "Bank: " .. bnf .. "/" .. bns
    )
    
    if Sanity.db.profile.TooltipTag then
  		local items = Sanity:GetItemsForTag(Sanity.db.profile.TooltipTag)
  		table.sort(items)
	    cat = tablet:AddCategory(
	        'text', Sanity.db.profile.TooltipTag,
	        'columns', 2,
	        'child_textR', 1,
	        'child_textG', 1,
	        'child_textB', 1
			)
			local itemList = {}
			for idx, item in pairs(items) do
				for i, bag in pairs(SanityItemCache.db.realm.chars[UnitName("player")].Bags) do
					for k, v in pairs(bag) do
						if v["Name"] == item then
							if itemList[v["Name"]] then
								itemList[v["Name"]].count = itemList[v["Name"]].count + v["Count"]
							else
								itemList[v["Name"]] = {name = item, count = v["Count"], texture = v["Texture"]}
							end
						end
					end
				end
			end
			for i, v in pairs(items) do
				if itemList[v] then
					cat:AddLine("hasCheck", true, "checkIcon", itemList[v]["texture"], "text", itemList[v]["count"] .. "x " .. itemList[v]["name"], 'checked', true)
				end
			end
    end
    
    tablet:SetHint(L["Click to toggle Sanity"])
    -- as a rule, if you have an OnClick or OnDoubleClick or OnMouseUp or OnMouseDown, you should set a hint.
end

function Sanity:menu(arg1, arg2, arg3, arg4, arg5, arg6)
	if arg1 == nil then	-- level 1
		dewdrop:AddLine("text", Sanity.menuItem["Name"], 
			"isTitle", true,
			"icon", Sanity.menuItem["Texture"]
		)
		dewdrop:AddLine("text", L["Category"], "isTitle", true)
		local cats = Sanity:GetExistingCategories()
		dewdrop:AddLine("text", L["Existing Categories"], "hasArrow", true, "value", "existing_categories", "disabled", #cats == 0)
		dewdrop:AddLine("text", L["New Category"], 
			"hasArrow", true, 
			"hasEditBox", true, 
			"editBoxText", Sanity.menuItem["TypeSort"], 
			"editBoxFunc", function(item, text) Sanity:SetItemCustomCategory(item, text); dewdrop:Close() end, 
			"editBoxArg1", Sanity.menuItem["Name"],
			"tooltipTitle", L["Existing Categories"],
			"tooltipText", L["A list of custom categories you've already put items into. Select an item from this category to set a category for"] .. " " .. Sanity.menuItem["Name"]
		)
		dewdrop:AddLine("text", L["Set To Default"], 
			"func", function(item) Sanity:SetItemCustomCategory(item, nil); dewdrop:Close() end,
			"arg1", Sanity.menuItem["Name"],
			"tooltipTitle", L["Set To Default"],
			"tooltipText", L["Clears any custom category you've set."]
		)
		
		dewdrop:AddLine("text", L["Tags"], "isTitle", true)
		local cats = Sanity:GetTagList()
		dewdrop:AddLine("text", L["Existing Tags"], "hasArrow", true, "value", "existing_tags", "disabled", #cats == 0)
		dewdrop:AddLine("text", L["New Tag"], 
			"hasArrow", true, 
			"hasEditBox", true, 
			"editBoxText", "", 
			"editBoxFunc", function(item, text) Sanity:TagItem(item, text); dewdrop:Close() end, 
			"editBoxArg1", Sanity.menuItem["Name"]
		)
		
	elseif arg1 then
		if arg1 == "existing_categories" then
			local cats = Sanity:GetExistingCategories()
			table.sort(cats)
			for k,v in pairs(cats) do
				dewdrop:AddLine("text", v, "isRadio", true, "checked", Sanity.menuItem["TypeSort"] == v,
					"func", function(item, text) Sanity:SetItemCustomCategory(item, text); dewdrop:Close() end,
					"arg1", Sanity.menuItem["Name"],
					"arg2", v
				)
			end
		elseif arg1 == "existing_tags" then
			local allTags = Sanity:GetTagList()
			table.sort(allTags)
			for k,v in pairs(allTags) do
				local hasTag = Sanity:ItemHasTag(Sanity.menuItem["Name"], v)
				dewdrop:AddLine("text", v, "checked", hasTag,
					"func", function(val, item, text)
						if val then 
							Sanity:TagItem(item, text);
						else
							Sanity:UntagItem(item, text);
						end
					end,
					"arg1", not hasTag,
					"arg2", Sanity.menuItem["Name"],
					"arg3", v
				)
			end
		end
	end
end

function Sanity:searchmenu(arg1, arg2, arg3, arg4, arg5, arg6)
	-- Sanity:Print(tostring(arg1) .. ", " .. tostring(arg2) .. ", " .. tostring(arg3))
	if arg1 == nil then	-- level 1
		local cats = Sanity:GetExistingCategories()
		dewdrop:AddLine("text", L["Search"], "isTitle", true)
		dewdrop:AddLine("text", L["Categories"], "hasArrow", true, "value", "existing_categories", "disabled", #cats == 0)
		local cats = Sanity:GetTagList()
		dewdrop:AddLine("text", L["Tags"], "hasArrow", true, "value", "existing_tags", "disabled", #cats == 0)
		dewdrop:AddLine("text", "Manage", "isTitle", true)
		dewdrop:AddLine("text", L["Tags"], "hasArrow", true, "value", "manage_tags", "disabled", #cats == 0)
		cats = Sanity:GetExistingCategories()
		dewdrop:AddLine("text", "Categories", "hasArrow", true, "value", "manage_cats", "disabled", #cats == 0)
		dewdrop:AddLine("text", L["Characters"], "hasArrow", true, "value", "manage_chars")
	elseif arg2 == "used_on" then
		dewdrop:AddLine("text", L["Untag"], "func", function(v, tag) Sanity:UntagItem(v, tag) end, "arg1", arg1, "arg2", arg3)
	elseif arg2 == "manage_chars" then
		dewdrop:AddLine("text", L["Delete"], "disabled", arg1 == UnitName("player"), "func", function(v)
			StaticPopupDialogs["SANITY_CONFIRM_CHARACTER_DELETE"].text = "Are you sure you want to delete " .. v .. "'s Sanity data?"
			StaticPopupDialogs["SANITY_CONFIRM_CHARACTER_DELETE"].OnAccept = function()
				SanityItemCache:NukeCharacter(v);
				PlaySound("JewelcraftingFinalize");
			end
			StaticPopup_Show("SANITY_CONFIRM_CHARACTER_DELETE")
		end, "arg1", arg1)
	elseif arg3 == "manage_tags" and arg1 == "used_on" then
		local items = Sanity:GetItemsForTag(arg2)
		table.sort(items)
		local count = table.getn(items)
		local ct = 0
		for k,v in pairs(items) do
			dewdrop:AddLine("text", v, "hasArrow", true, "value", v)
			ct = ct + 1
			if ct >= 25 and count > 25 then 
				dewdrop:AddLine("text", (count - ct) .. " more...")
				break
			end
		end
	elseif arg1 and arg2 == "manage_tags" then
		local items = Sanity:GetItemsForTag(arg1)
		local i = L["items"]
		if #items == 1 then i = L["item"] end
		dewdrop:AddLine("text", L["Used on"] .. " " .. #items .. " " .. i, "hasArrow", true, "value", "used_on", "disabled", #items == 0)
		dewdrop:AddLine("text", "Set as tooltip list", "func", function(v, text) Sanity:SetTooltipTag(v) end, "arg1", arg1)
		dewdrop:AddLine("text", "Delete", "func", function(v, text) Sanity:KillTag(v) end, "arg1", arg1)

	elseif arg1 and arg2 == "manage_cats" then
		local items = Sanity:GetItemsForTag(arg1)
		local i = L["items"]
		if #items == 1 then i = L["item"] end
		dewdrop:AddLine("text", "Delete", "func", function(v, text) Sanity:DeleteCategory(v) end, "arg1", arg1)
	elseif arg1 then
		if arg1 == "existing_categories" then
			local cats = Sanity:GetExistingCategories()
			table.sort(cats)
			for k,v in pairs(cats) do
				dewdrop:AddLine("text", v, 
					"func", function(text) SanityEditBox:SetText(text); dewdrop:Close() end,
					"arg1", v
				)
			end
		elseif arg1 == "existing_tags" then
			local allTags = Sanity:GetTagList()
			table.sort(allTags)
			for k,v in pairs(allTags) do
				dewdrop:AddLine("text", v, 
					"func", function(text) SanityEditBox:SetText(text); dewdrop:Close() end,
					"arg1", v
				)
			end
		elseif arg1 == "manage_tags" then
			local allTags = Sanity:GetTagList()
			table.sort(allTags)
			for k,v in pairs(allTags) do
				dewdrop:AddLine("text", v, "hasArrow", true, "value", v)
			end
		elseif arg1 == "manage_cats" then
			local allTags = Sanity:GetExistingCategories()
			table.sort(allTags)
			for k,v in pairs(allTags) do
				dewdrop:AddLine("text", v, "hasArrow", true, "value", v)
			end
		elseif arg1 == "manage_chars" then
			local chars = {}
			for k,v in pairs(Sanity.ItemCache.db.realm.chars) do
				tinsert(chars, k)
			end
			table.sort(chars)
			for k,v in pairs(chars) do
				dewdrop:AddLine("text", v, "hasArrow", true, "value", v)
			end
		end
	end
end

--[[ Functions ]]--

function Sanity:Register()
	Sanity:RegisterChatCommand({"/sanity", "/san"}, options)
end

function Sanity:ToggleOptions(frame)
	if dewdrop:IsOpen() then
		dewdrop:Close()
	else
		dewdrop:Open(frame, 'children', 
			function()
				dewdrop:FeedAceOptionsTable(options)
			end
		)
	end
end

function Sanity:OnItemEnter(item, anchor)
	if not item or (item and item.invalid and not Sanity.db.profile.UseDangerousItems) then return end
	-- if item["Link"] == Sanity.lastTooltipLink then GameTooltip:Show(); return end
	Sanity.lastTooltipLink = item["Link"]
	GameTooltip:Hide()
	GameTooltip:SetOwner(anchor, "ANCHOR_LEFT");
	if item["Owner"] == UnitName("player") then
		if item["Bag"] == -1 or item["Bag"] >= 5 then
			if Sanity.BankIsVisible and item["Bag"] == -1 then
				GameTooltip:SetInventoryItem("player", BankButtonIDToInvSlotID(item["Slot"], nil));
			elseif Sanity.BankIsVisible then
				ContainerFrameItemButton_OnEnter()
			else
				GameTooltip:ClearLines();
				GameTooltip:SetHyperlink(item["Link"])
			end
		elseif item["Bag"] == SanityItemCache.INVENTORY_BAG_ID then
			GameTooltip:SetInventoryItem("player", item["Slot"]);
		elseif item["Bag"] ~= SanityItemCache.MAILBOX_BAG_ID then
			local oldID = this:GetID()
			local pOldID = this:GetParent():GetID()
			this:SetID(item["Slot"])
			this:GetParent():SetID(item["Bag"])
			ContainerFrameItemButton_OnEnter();
			this:SetID(oldID)
			this:GetParent():SetID(pOldID)
		else
			GameTooltip:ClearLines();
			GameTooltip:SetHyperlink(item["Link"])
		end
	else
		GameTooltip:ClearLines();
		GameTooltip:SetHyperlink(item["Link"])
	end
end

function Sanity:OpenItemOptions(element, item)
	Sanity.menuItem = item
	dewdrop:Open(element, 'children', Sanity.menu, 'point', 
		function(parent) 
			return "TOPLEFT", "TOPRIGHT"
		end
	)
end

-----------------------------------------------------------
-- Updates the interface with our updated item list.
-----------------------------------------------------------
function Sanity:UpdateDisplay(list)
	if not SanityFrame:IsVisible() then return; end
	if not list then
		list = Sanity:GetDisplayList()
	end
	Sanity.viewList = list

	local itemsList = list;
	local numEntries = getn(itemsList);
	
	FauxScrollFrame_Update(SanityDisplayFrameScrollFrame, numEntries, Sanity.visibleItems, Sanity.db.profile.ItemHeight);
	
	local offset = FauxScrollFrame_GetOffset(SanityDisplayFrameScrollFrame);
	
	for i = 1, Sanity.visibleItems do
		local button = Sanity.tabletop:GetRow(i)
		
		local index = i + offset;
		if ( index <= numEntries ) then
			if(not button:IsVisible()) then
				button:Show();
			end
			local buttonHeader	= Sanity.tabletop:GetSectionHeader(i)
			
			local item = itemsList[index]
			button:SetAlpha(1)
			button.item = nil	
			button:SetAttribute("unit", nil)
			button:SetAttribute("type2", ATTRIBUTE_NOOP)
			button:SetAttribute("bag", nil)
			button:SetAttribute("slot", nil)
			if item then button:Show() else button:Hide() end
			
			if item["Priority"] == 1 then
				buttonHeader:SetText(itemsList[index]["Header"]);
				buttonHeader:SetWidth(SanityFrame:GetWidth())
				buttonHeader:SetTextColor(Sanity.defaultColor[1], Sanity.defaultColor[2], Sanity.defaultColor[3], 1);
			else
				local buttonName 		= Sanity.tabletop:GetRowField(i, "Name")
				local buttonQty 		= Sanity.tabletop:GetRowField(i, "TypeSortQty")
				local buttonTexture 	= Sanity.tabletop:GetRowField(i, "TypeSort")
				local buttonLocation	= Sanity.tabletop:GetRowField(i, "Location")
				local buttonOwner	 	= Sanity.tabletop:GetRowField(i, "Owner")
				local buttonTags 		= Sanity.tabletop:GetRowField(i, "Tags")
				local buttonStacks 		= Sanity.tabletop:GetRowField(i, "Stacks")

				button.count = item["Count"]
				button.item = item

				if item["Bag"] and not _G["SanityDummyBagFrame" .. item["Bag"]] then
					local f = CreateFrame("Frame", "SanityDummyBagFrame" .. item["Bag"], SanityDisplayFrame)
					f:SetID(item["Bag"])
				end
				
				if item["Slot"] and item["Bag"] ~= SanityItemCache.MAILBOX_BAG_ID then
					button:SetAttribute("unit", "player")
					button:SetAttribute("type2", "item")
					button:SetAttribute("bag", item["Bag"])
					button:SetAttribute("slot", item["Slot"])
					button:SetParent("SanityDummyBagFrame" .. item["Bag"])
					button:SetID(item["Slot"])
				end
				
				buttonName:SetText(item["Name"]);
				if Sanity.db.profile.UseColors then
					if item["Quality"] then
						local c = Sanity.ItemColors[item["Quality"]+1];
						buttonName:SetTextColor(c[1],c[2],c[3],1);
					else
						buttonName:SetTextColor(1, 0, 0, 1);
					end
				else
					buttonName:SetTextColor(Sanity.defaultColor[1], Sanity.defaultColor[2], Sanity.defaultColor[3], 1);
				end
				
				
				buttonQty:SetText(item["Count"]);
				buttonTexture:SetNormalTexture(item["Texture"]);
				buttonOwner:SetText(item["Owner"])
				buttonLocation:SetText(item["Location"])
				buttonTags:SetText(item["Tags"])
				buttonStacks:SetText(item["Stacks"])

				buttonTexture:GetNormalTexture():SetVertexColor(1,1,1,1)
				if item and item["Link"] and ((item["Bag"] >= 0 and item["Bag"] <= 4) or item["Bag"] == KEYRING_CONTAINER) and not IsUsableItem(item["Link"]) then
					buttonTexture:GetNormalTexture():SetVertexColor(1,0,0,1)
				end

				if not SanityItemCache:ItemIsUsable(item) then
					button:SetAlpha(0.75)
					-- buttonTexture:GetNormalTexture():SetVertexColor(0.8,1,0.8,1)
				end
				
			end
			
		else
			button:Hide();
		end
	end
	
	local character = Sanity.character
	if Sanity.allCharacters then
		character = UnitName("player")
	end         
	local filled_slots, bag_slots = SanityItemCache:GetBagData(character)
	local div_slots = bag_slots + 1
	
	SanityFrameBagSlots:SetText(L["Bags"] .. ": " .. filled_slots .. "/" .. bag_slots)
	SanityFrameBagSlots:SetTextColor(tonumber(filled_slots) / tonumber(div_slots), 1 - (tonumber(filled_slots) / tonumber(div_slots)), 0, 1)

	filled_slots, bag_slots = SanityItemCache:GetBankData(character)
	div_slots = filled_slots + 1
		
	SanityFrameBankSlots:SetText(L["Bank"] .. ": " .. filled_slots .. "/" .. bag_slots)
	SanityFrameBankSlots:SetTextColor(
		tonumber(filled_slots) / tonumber(div_slots), 
		1 - (tonumber(filled_slots) / tonumber(div_slots)), 
		0, 
		1)
end

function Sanity:SetupCategoryBox()
	local cats = Sanity:GetExistingCategories()
	local tags = Sanity:GetTagList()
	local tList = {}
	for k, t in pairs(cats) do
		if t then
			tinsert(tList, {t, "Category"})
		end
	end
	for k, t in pairs(tags) do
		if t then
			tinsert(tList, {t, "Tag"})
		end
	end

	table.sort(tList, function (a,b) return a[1] < b[1] end)
	for i = 1, 100 do
		local f = _G["SanityCategoryItem" .. i]
		if f then
			f:Hide()
		end
	end
	for k,i in pairs(tList) do
		local f = _G["SanityCategoryItem" .. k]
		if not f then
			f = CreateFrame("Button", "SanityCategoryItem" .. k, SanityCategoriesScrollFrameChild, "SanityCategoryItemTemplate")
			if k == 1 then
				f:SetPoint("TOPLEFT", SanityCategoriesFrame, "TOPLEFT", 5, -6)
			else
				f:SetPoint("TOPLEFT", _G["SanityCategoryItem" .. (k-1)], "BOTTOMLEFT", 0, 0)
			end
			f:SetPoint("RIGHT", SanityCategoriesScrollFrameChild, "RIGHT", 0, 0)
		end
		f.dataType = i[2]
		f:Show()
		f:SetText(i[1])
		f:SetScript("OnClick", function() SanityEditBox:SetText(i[1]) end)
	end
end

function Sanity:ShowLastItemTagMenu()
	dewdrop:Close()
	if not Sanity.lastFocusName or Sanity.lastFocus ~= GetMouseFocus() then
		return
	end
	Sanity.menuItem = {
		["Name"] = Sanity.lastFocusName,
		["Texture"] = Sanity.lastFocusTexture,
		["TypeSort"] = Sanity:GetCategoryFor(Sanity.lastFocusName) or ""
	}
	dewdrop:Open(Sanity.lastFocus, 'children', Sanity.menu, 'point', 
		function(parent) 
			local x,y = GetCursorPosition()
			x = x / UIParent:GetEffectiveScale()
			y = y / UIParent:GetEffectiveScale()
			local xr = "LEFT"
			local yr = "TOP"
			local px = "RIGHT"
			local py = "TOP"
			if x > (UIParent:GetWidth() / 2) then
				xr = "RIGHT"
				px = "LEFT"
			end
			if y < (UIParent:GetHeight() / 2) then
				yr = "BOTTOM"
				py = "BOTTOM"
			end
			return (yr .. xr), (py .. px)
		end
	)
end

StaticPopupDialogs["SANITY_CONFIRM_CHARACTER_DELETE"] = {
	text = L["Are you sure you want to delete <char>?"],
	button1 = TEXT(YES),
	button2 = TEXT(NO),
	timeout = 0,
	showAlert = 1,
	hideOnEscape = 1,
};

StaticPopupDialogs["SANITY_CONFIRM_DATABASE_WIPE"] = {
	text = L["Are you sure you want to reset your Sanity settings?"],
	button1 = TEXT(YES),
	button2 = TEXT(NO),
	timeout = 0,
	showAlert = 1,
	hideOnEscape = 1,
};

StaticPopupDialogs["SANITY_CONFIRM_DATABASE_WIPE"].text = L["Are you sure you want to delete all of Sanity's saved settings and data?"]
StaticPopupDialogs["SANITY_CONFIRM_DATABASE_WIPE"].OnAccept = function()
	Sanity:ResetDB()
	SanityItemCache:ResetDB();
	PlaySound("JewelcraftingFinalize");
	ReloadUI()
end
