-- AI Research Grid Addon for Elder Scrolls Online
-- Author: Stormknight/LCAmethyst/CrazyDutchGuy

local _
AIRG = {}

AIRG.name = "AIResearchGrid"
AIRG.version = "1.3.4"
AIRG.initialised = false
AIRG.processing = false

-- Set-up the defaults options for saved variables.
AIRG.defaults = {
    data        = {},
    styles      = {},
    showMotifs = true,
}

AIRG.gridAlignments = {
	grid_base_height = 636,
	grid_base_width = 760,
	styleGrid = {
		num_styles = 30,
		height = 120,
		width = 605,
		icon_height = 30,
		icon_width = 30,
		left_align = 160,
		top_align = 15,
		row_length = 15,
		icon_box_height = 37,
		icon_box_width = 37,
	},
}

function AIRG.Initialise(eventCode, addOnName)
	-- Only initialize our own addon
	if (AIRG.name ~= addOnName) then return end

    -- Language text
    AIRG.InitialiseLanguage()

    -- Load the saved variables
    AIRG.vars = ZO_SavedVars:NewAccountWide("AIRG_SavedVariables", 2, nil, AIRG.defaults)

    -- Register Keybinding
    ZO_CreateStringId("SI_BINDING_NAME_TOGGLE_AIRG", "Toggle AI Research Grid")

	-- Set-up some variables we'll want to refer to.
    AIRG.craftNames = {}
    AIRG.craftNames[CRAFTING_TYPE_BLACKSMITHING]    = "BLACKSMITHING"
    AIRG.craftNames[CRAFTING_TYPE_CLOTHIER]         = "CLOTHING"
    AIRG.craftNames[CRAFTING_TYPE_WOODWORKING]      = "WOODWORKING"
    AIRG.playerName = GetUnitName("player")
    AIRG.curCharacter = GetUnitName("player")       -- Default the display to the current character

    AIRG.AssignGridTraits()
    AIRG.AssignStyleLookups()

    -- Query data for THIS character and populate the data matrix with fresh data.
    --AIRG.PopulateMatrix()

    -- Query data for THIS character for STYLES
    --AIRG.PopulateStyleData()

    -- UI set-up. Create frames, position labels & buttons etc.
    AIRG.initUI()


    -- REGISTER for events that aren't initialise.
    EVENT_MANAGER:RegisterForEvent("AIRG", EVENT_SMITHING_TRAIT_RESEARCH_STARTED, AIRG.ResearchStarted)
    EVENT_MANAGER:RegisterForEvent("AIRG", EVENT_SMITHING_TRAIT_RESEARCH_COMPLETED, AIRG.ResearchCompleted)

    EVENT_MANAGER:RegisterForEvent("AIRG", EVENT_STYLE_LEARNED, AIRG.StyleLearned)

    EVENT_MANAGER:RegisterForEvent("AIRG", EVENT_PLAYER_ACTIVATED, AIRG.PlayerActivated)

    -- Create the configuration/settings menu.
    AIRG.CreateConfigMenu()

    AIRG.initialised = true
end -- AIRG.Initialise

EVENT_MANAGER:RegisterForEvent("AIRG", EVENT_ADD_ON_LOADED, AIRG.Initialise)


-- SLASH COMMAND FUNCTIONALITY
function AIRGslash(extra)
    AIRG.ToggleMainWindow()
end -- AIRGslash


SLASH_COMMANDS["/airg"] = AIRGslash

function AIRG.PlayerActivated()
        -- somehow somewhere it sometimes happens that the data is not correct completely for whatever reason
        -- so we force a reload of the current character data when we are actually loaded into the world.
    	AIRG.PopulateMatrix()
	AIRG.PopulateStyleData()
end

function AIRG.ToggleMainWindow()
    if (AIResearchGrid:IsHidden()) then
        AIRG.OnCraftSelected()              -- Redisplay data for the current profession
        SetGameCameraUIMode(true)	        -- Enable mouse pointer
        AIResearchGrid:SetHidden(false)     -- Display the addon
        AIRG.OnCharacterSelect()
    else
        SetGameCameraUIMode(false)	        -- Enable mouse pointer
        AIResearchGrid:SetHidden(true)      -- Display the addon
    end
end -- AIRG.ToggleMainWindow

-- Invoked by EVENT_SMITHING_TRAIT_RESEARCH_STARTED
-- (integer eventCode, integer craftingSkillType, luaindex researchLineIndex, luaindex traitIndex)
function AIRG.ResearchStarted(eventCode, craftingSkillType, researchLineIndex, traitIndex)
    AIRG.PopulateMatrix()
    -- TO DO: If it's visible, invoke a redisplay
    AIRG.OnCraftSelected()              -- Redisplay data for the current profession
end -- AIRG.ResearchStarted

-- Invoked by EVENT_SMITHING_TRAIT_RESEARCH_COMPLETED
-- (integer eventCode, integer craftingSkillType, luaindex researchLineIndex, luaindex traitIndex)
function AIRG.ResearchCompleted()
    AIRG.PopulateMatrix()
    -- TO DO: If it's visible, invoke a redisplay
    AIRG.OnCraftSelected()              -- Redisplay data for the current profession
end -- AIRG.ResearchEnded

function AIRG.StyleLearned(eventCode, styleIndex)
    AIRG.PopulateStyleData()
    AIRG.DisplayStyles()
end -- AIRG.StyleLearned

-- Invoked from AIRG.Initialise but lengthy so in it's own function to not clutter Initialise
function AIRG.initUI()
    -- Some local variable declaration
    local i, j      -- used in for loops
    local thisTrait, tType, tDesc, rowNum, charName
    -- Initialise a table to hold all the lua generated components
    AIRG.UI = {}
    -- Set the main window title
    AIRG.UI.WindowTitle = WINDOW_MANAGER:CreateControl("AIResearchGridWindowTitle", AIResearchGrid, CT_LABEL)
    AIRG.UI.WindowTitle:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 0, 0)
    AIRG.UI.WindowTitle:SetFont("ZoFontAnnounceMedium")
    AIRG.UI.WindowTitle:SetHorizontalAlignment(TEXT_ALIGN_LEFT)
    AIRG.UI.WindowTitle:SetText("|c8080ffAI|r RESEARCH GRID")
    -- Set the main window subtitle
    AIRG.UI.WindowSubTitle = WINDOW_MANAGER:CreateControl("AIResearchGridWindowSubTitle", AIResearchGrid, CT_LABEL)
    AIRG.UI.WindowSubTitle:SetAnchor(LEFT, AIRG.UI.WindowTitle, RIGHT, 10, 0)
    AIRG.UI.WindowSubTitle:SetFont("ZoFontAnnounceMedium")
    AIRG.UI.WindowSubTitle:SetHorizontalAlignment(TEXT_ALIGN_LEFT)
    AIRG.UI.WindowSubTitle:SetColor(0, 1, 0, 1);    -- green
    AIRG.UI.WindowSubTitle:SetText("")
    -- Nice little line under the main title
    AIRG.UI.TopDivider = WINDOW_MANAGER:CreateControl("AIResearchGridTopDivider", AIResearchGrid, CT_TEXTURE)
    AIRG.UI.TopDivider:SetDimensions(760, 5)
    AIRG.UI.TopDivider:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 0, 32)
    AIRG.UI.TopDivider:SetTexture("/esoui/art/quest/questjournal_divider.dds")
    -- Nice little line under the grid
    AIRG.UI.BottomDivider = WINDOW_MANAGER:CreateControl("AIResearchGridBottomDivider", AIResearchGrid, CT_TEXTURE)
    AIRG.UI.BottomDivider:SetDimensions(760, 5)
    AIRG.UI.BottomDivider:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 0, 636)
    AIRG.UI.BottomDivider:SetTexture("/esoui/art/quest/questjournal_divider.dds")
    AIRG.UI.BottomDivider:SetHidden(not AIRG.vars.showMotifs)
    -- CREATE BUTTON FOR CLOSE ADDON AT TOP_RIGHT
    AIRG.UI.btnCloseAddonFrame = WINDOW_MANAGER:CreateControl("AIResearchGridButtonCloseAddon", AIResearchGrid, CT_BUTTON)
    AIRG.UI.btnCloseAddonFrame:SetDimensions(28, 28)
    AIRG.UI.btnCloseAddonFrame:SetAnchor(TOPRIGHT, AIResearchGrid, TOPRIGHT, 0 , 0)
    AIRG.UI.btnCloseAddonFrame:SetState(BSTATE_NORMAL)
    AIRG.UI.btnCloseAddonFrame:SetMouseOverBlendMode(0)
--    AIRG.UI.btnCloseAddonFrame:SetHidden(false)
    AIRG.UI.btnCloseAddonFrame:SetEnabled(true)
--    AIRG.UI.btnCloseAddonFrame:SetClickSound(SOUNDS.WOODWORKER_EXTRACTED_BOOSTER)
    AIRG.UI.btnCloseAddonFrame:SetNormalTexture("/esoui/art/buttons/clearslot_down.dds")
    AIRG.UI.btnCloseAddonFrame:SetMouseOverTexture("/esoui/art/buttons/clearslot_up.dds")
    AIRG.UI.btnCloseAddonFrame:SetHandler("OnClicked", function(self) AIRG.ToggleMainWindow() end)
    -- CREATE the DROPDOWN BOX for CHARACTER SELECT
    -- Uses code based on example from Seerah
    AIRG.UI.charDropdown = WINDOW_MANAGER:CreateControlFromVirtual("AIResearchGridDropdownCharacter", AIResearchGrid, "ZO_StatsDropdownRow")
    AIRG.UI.charDropdown:SetAnchor(TOPRIGHT, AIResearchGrid, TOPRIGHT, -32, 0)
    AIRG.UI.charDropdown:GetNamedChild("Dropdown"):SetWidth(200)
    AIRG.UI.charDropdown.dropdown:SetSelectedItem(AIRG.curCharacter)  -- Set the current character as selected
    local function OnItemSelect(_, choiceText, choice)  --this is the callback function for when an item gets selected in the dropdown
        AIRG.OnCharacterSelect(choiceText)
    end
    for charName, _ in pairs(AIRG.vars.data) do
        local entry = AIRG.UI.charDropdown.dropdown:CreateItemEntry(charName, OnItemSelect)
        AIRG.UI.charDropdown.dropdown:AddItem(entry)
    end
    -- PEOPLE ICON NEXT TO THE DROPDOWN BOX
--    AIRG.UI.PeopleIcon = WINDOW_MANAGER:CreateControl("AIResearchGridPeopleIcon", AIResearchGrid, CT_TEXTURE)
--    AIRG.UI.PeopleIcon:SetDimensions(40, 32)
--    AIRG.UI.PeopleIcon:SetAnchor(TOPRIGHT, AIRG.UI.charDropdown, TOPLEFT, 0, 0)
--    AIRG.UI.PeopleIcon:SetTexture("/esoui/art/contacts/tabicon_friends_down.dds")
    -- CREATE BUTTON FOR PROFESSION: BLACKSMITHING
    AIRG.UI.btnBlacksmithing = WINDOW_MANAGER:CreateControl("AIResearchGridButtonBlacksmithing", AIResearchGrid, CT_BUTTON)
    AIRG.UI.btnBlacksmithing:SetDimensions(48, 48)
    AIRG.UI.btnBlacksmithing:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 8 , 44)
    AIRG.UI.btnBlacksmithing:SetState(BSTATE_NORMAL)
    AIRG.UI.btnBlacksmithing:SetMouseOverBlendMode(0)
    AIRG.UI.btnBlacksmithing:SetHidden(false)
    AIRG.UI.btnBlacksmithing:SetEnabled(true)
    AIRG.UI.btnBlacksmithing:SetClickSound(SOUNDS.WOODWORKER_EXTRACTED_BOOSTER)
    AIRG.UI.btnBlacksmithing:SetNormalTexture("/esoui/art/icons/ability_smith_007.dds")
    AIRG.UI.btnBlacksmithing:SetMouseOverTexture("ESOUI/art/buttons/generic_highlight.dds")
    AIRG.UI.btnBlacksmithing:SetHandler("OnClicked", function(self) AIRG:OnCraftSelected(CRAFTING_TYPE_BLACKSMITHING) end)
    -- CREATE BUTTON FOR PROFESSION: WOODWORKING
    AIRG.UI.btnWoodworking = WINDOW_MANAGER:CreateControl("AIResearchGridButtonWoodworking", AIResearchGrid, CT_BUTTON)
    AIRG.UI.btnWoodworking:SetDimensions(48, 48)
    AIRG.UI.btnWoodworking:SetAnchor(TOPLEFT, AIRG.UI.btnBlacksmithing, TOPRIGHT, 12 , 0)
    AIRG.UI.btnWoodworking:SetState(BSTATE_NORMAL)
    AIRG.UI.btnWoodworking:SetMouseOverBlendMode(0)
    AIRG.UI.btnWoodworking:SetHidden(false)
    AIRG.UI.btnWoodworking:SetEnabled(true)
    AIRG.UI.btnWoodworking:SetClickSound(SOUNDS.BLACKSMITH_EXTRACTED_BOOSTER)
    AIRG.UI.btnWoodworking:SetNormalTexture("/esoui/art/icons/ability_tradecraft_009.dds")
    AIRG.UI.btnWoodworking:SetMouseOverTexture("ESOUI/art/buttons/generic_highlight.dds")
    AIRG.UI.btnWoodworking:SetHandler("OnClicked", function(self) AIRG:OnCraftSelected(CRAFTING_TYPE_WOODWORKING) end)
    -- CREATE BUTTON FOR PROFESSION: CLOTHING
    AIRG.UI.btnClothing = WINDOW_MANAGER:CreateControl("AIResearchGridButtonClothing", AIResearchGrid, CT_BUTTON)
    AIRG.UI.btnClothing:SetDimensions(48, 48)
    AIRG.UI.btnClothing:SetAnchor(TOPLEFT, AIRG.UI.btnWoodworking, TOPRIGHT, 12 , 0)
    AIRG.UI.btnClothing:SetState(BSTATE_NORMAL)
    AIRG.UI.btnClothing:SetMouseOverBlendMode(0)
    AIRG.UI.btnClothing:SetHidden(false)
    AIRG.UI.btnClothing:SetEnabled(true)
    AIRG.UI.btnClothing:SetClickSound(SOUNDS.CLOTHIER_EXTRACTED_BOOSTER)
    AIRG.UI.btnClothing:SetNormalTexture("/esoui/art/icons/ability_tradecraft_008.dds")
    AIRG.UI.btnClothing:SetMouseOverTexture("ESOUI/art/buttons/generic_highlight.dds")
    AIRG.UI.btnClothing:SetHandler("OnClicked", function(self) AIRG:OnCraftSelected(CRAFTING_TYPE_CLOTHIER) end)

    -- BUILD THE TRAIT LABELS ON THE LEFT-SIDE using built-in language strings
    AIRG.UI.rowLabels = {}
    for thisTrait, j in pairs(AIRG.gridTraits) do
        AIRG.UI.rowLabels[j] = WINDOW_MANAGER:CreateControl("AIResearchGridRowLabel" .. tostring(j), AIResearchGrid, CT_LABEL)
        AIRG.UI.rowLabels[j]:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 5, 28*j + 70)
        AIRG.UI.rowLabels[j]:SetText(GetString("SI_ITEMTRAITTYPE",thisTrait))       -- This is the text displayed on the screen as it's a label
        AIRG.UI.rowLabels[j]:SetDimensions(180, 24)
        AIRG.UI.rowLabels[j]:SetFont("ZoFontGame")
        AIRG.UI.rowLabels[j]:SetHorizontalAlignment(TEXT_ALIGN_RIGHT)
        AIRG.UI.rowLabels[j]:SetVerticalAlignment(TEXT_ALIGN_CENTER)
        AIRG.UI.rowLabels[j]:SetMouseEnabled(true)
        AIRG.UI.rowLabels[j]:SetHandler("OnMouseEnter", function (self)
                            ZO_Tooltips_ShowTextTooltip(self, TOP, self.tooltipText)
                        end)
        AIRG.UI.rowLabels[j]:SetHandler("OnMouseExit", function (self)
                            ZO_Tooltips_HideTextTooltip()
                        end)
    end
    -- Now add tooltip text to the row labels.
    -- The tooltip functionality is automatic as part of the label control.
    for j = 1, 9 do
        tType, tDesc, _ = GetSmithingResearchLineTraitInfo(CRAFTING_TYPE_BLACKSMITHING,1,j) -- weapons
        rowNum = AIRG.gridTraits[tType]
        AIRG.UI.rowLabels[rowNum].tooltipText = tDesc
        tType, tDesc, _ = GetSmithingResearchLineTraitInfo(CRAFTING_TYPE_BLACKSMITHING,9,j) -- armour
        rowNum = AIRG.gridTraits[tType]
        AIRG.UI.rowLabels[rowNum].tooltipText = tDesc
    end
    -- BUILD THE COLUMNS & GRID
    -- Determine the maximum number of item types across all three professions. This is currently always 14
    AIRG.maxColumns= math.max(GetNumSmithingResearchLines(CRAFTING_TYPE_BLACKSMITHING),
            GetNumSmithingResearchLines(CRAFTING_TYPE_CLOTHIER),
            GetNumSmithingResearchLines(CRAFTING_TYPE_WOODWORKING))
    AIRG.UI.columnButtons = {}
    AIRG.UI.gridButtons = {}
    AIRG.UI.columnFooters = {}
    for i = 1, AIRG.maxColumns do
        -- BUILD THE COLUMN BUTTONS
        AIRG.UI.columnButtons[i] = WINDOW_MANAGER:CreateControl("AIResearchGridHeaderButton" .. tostring(i), AIResearchGrid, CT_BUTTON)
        AIRG.UI.columnButtons[i]:SetDimensions(36, 36)
        AIRG.UI.columnButtons[i]:SetState(BSTATE_NORMAL)
        AIRG.UI.columnButtons[i]:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 40*i + 150, 55)
        AIRG.UI.columnButtons[i]:SetHidden(true)
        AIRG.UI.columnButtons[i]:SetEnabled(true)
        AIRG.UI.columnButtons[i]:SetMouseOverTexture("ESOUI/art/buttons/generic_highlight.dds")
        AIRG.UI.columnButtons[i].text = i
        AIRG.UI.columnButtons[i]:SetHandler("OnMouseEnter", function (self)
                                                ZO_Tooltips_ShowTextTooltip(self, TOP, self.text)
                                            end)
        AIRG.UI.columnButtons[i]:SetHandler("OnMouseExit", function (self)
                                                ZO_Tooltips_HideTextTooltip()
                                            end)
        -- BUILD THE GRID
        -- There are a total of 18 traits possible. 9 armour and 9 weapon (Infused, Training and Nirnhoned on both)
        AIRG.UI.gridButtons[i] = {}
        for j = 1, 18 do
            AIRG.UI.gridButtons[i][j] = WINDOW_MANAGER:CreateControl("AIResearchGridGridButton" .. tostring(i) .. "x" .. tostring(j), AIResearchGrid, CT_TEXTURE)
            AIRG.UI.gridButtons[i][j]:SetDimensions(24, 24)
            AIRG.UI.gridButtons[i][j]:SetAnchor(TOP, AIRG.UI.columnButtons[i], BOTTOM, 0, 28*j -20)
            AIRG.UI.gridButtons[i][j]:SetTexture("/esoui/art/buttons/swatchframe_down.dds")
            AIRG.UI.gridButtons[i][j]:SetColor(1, 1, 1, 0.4)
            AIRG.UI.gridButtons[i][j]:SetHidden(false)
            AIRG.UI.gridButtons[i][j]:SetMouseEnabled(false)
            -- Following tooltip code uses ideas contributed by Krysstof
            AIRG.UI.gridButtons[i][j]:SetHandler("OnMouseEnter", function (self)
                        if (self.tooltipText > 0) then      -- Check the item is being researched and has a timestamp
					        local tRemaining = tonumber(self.tooltipText) - GetTimeStamp()
                            local tFormatted = FormatTimeSeconds(tRemaining, TIME_FORMAT_STYLE_DESCRIPTIVE_SHORT, TIME_FORMAT_PRECISION_SECONDS, TIME_FORMAT_DIRECTION_DESCENDING)
					        ZO_Tooltips_ShowTextTooltip(self, RIGHT, tFormatted)
    						-- loop with "registerforupdate" once per second
    						EVENT_MANAGER:RegisterForUpdate(self.name, 1000, function()
    						        local tRemaining = tonumber(self.tooltipText) - GetTimeStamp()
                                    local tFormatted = FormatTimeSeconds(tRemaining, TIME_FORMAT_STYLE_DESCRIPTIVE_SHORT, TIME_FORMAT_PRECISION_SECONDS, TIME_FORMAT_DIRECTION_DESCENDING)
    						        ZO_Tooltips_ShowTextTooltip(self, RIGHT, tFormatted)
    						    end)
    				    end
					end)
            AIRG.UI.gridButtons[i][j]:SetHandler("OnMouseExit", function (self)
						-- unregister the update event or it keeps on displaying
						EVENT_MANAGER:UnregisterForUpdate(self.name)
						ZO_Tooltips_HideTextTooltip()
					end)
        end
        -- BUILD THE COLUMN FOOTERS
        AIRG.UI.columnFooters[i] = WINDOW_MANAGER:CreateControl("AIResearchGridColumnFooterLabel" .. tostring(i), AIResearchGrid, CT_LABEL)
        AIRG.UI.columnFooters[i]:SetAnchor(TOP, AIRG.UI.columnButtons[i], BOTTOM, 0, 516)
        AIRG.UI.columnFooters[i]:SetDimensions(36, 24)
        AIRG.UI.columnFooters[i]:SetFont("ZoFontGame")
        AIRG.UI.columnFooters[i]:SetHorizontalAlignment(TEXT_ALIGN_CENTER)
        AIRG.UI.columnFooters[i]:SetVerticalAlignment(TEXT_ALIGN_CENTER)
        AIRG.UI.columnFooters[i]:SetColor(1, 1, 0.4, 1);    -- faded yellow
    end
    -- BUILD LABEL FOR COLUMN FOOTER "TRAIT LINE"
    AIRG.UI.columnFooterTitle = WINDOW_MANAGER:CreateControl("AIResearchGridColumnFooterTitleLabel", AIResearchGrid, CT_LABEL)
    AIRG.UI.columnFooterTitle:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 5, 606)
    AIRG.UI.columnFooterTitle:SetDimensions(180, 24)
    AIRG.UI.columnFooterTitle:SetFont("ZoFontGame")
    AIRG.UI.columnFooterTitle:SetHorizontalAlignment(TEXT_ALIGN_RIGHT)
    AIRG.UI.columnFooterTitle:SetVerticalAlignment(TEXT_ALIGN_CENTER)
    AIRG.UI.columnFooterTitle:SetColor(1, 1, 0.4, 1);       -- faded yellow
--    AIRG.UI.columnFooterTitle:SetText(GetString(SI_SMITHING_RESEARCH_LINE_HEADER))
    AIRG.UI.columnFooterTitle:SetText(GetString(SI_CRAFTING_COMPONENT_TOOLTIP_TRAITS))

    -- BUILD THE MOTIF ICONS ACROSS THE BOTTOM
    -- Note that for now, we're just setting up 15 icons and stuff is configured manually
    -- but we can fix it later. It's not like it's going to have an overhead on processing. :)
    -- It's set-up inside a container frame to make hiding or showing the whole lot simpler.
    AIRG.UI.motifSection = WINDOW_MANAGER:CreateControl("AIResearchMotifSection", AIResearchGrid, CT_CONTROL)
    AIRG.UI.motifSection:SetDimensions(AIRG.gridAlignments.grid_base_width, AIRG.gridAlignments.styleGrid.height)
    AIRG.UI.motifSection:SetAnchor(BOTTOMLEFT, AIResearchGrid, BOTTOMLEFT, 0, 0)
    AIRG.UI.motifSection:SetHidden(not AIRG.vars.showMotifs)
    AIResearchGrid:SetHeight(AIRG.vars.showMotifs and AIRG.gridAlignments.grid_base_height + AIRG.gridAlignments.styleGrid.height or AIRG.gridAlignments.grid_base_height)
    AIRG.UI.motifButtons = {}
	local currentColumn = 0
	local currentRow = 0
    for i = 1, AIRG.gridAlignments.styleGrid.num_styles do
		currentColumn = currentColumn + 1
        AIRG.UI.motifButtons[i] = WINDOW_MANAGER:CreateControl("AIResearchGridMotifButton" .. tostring(i), AIRG.UI.motifSection, CT_TEXTURE)
        AIRG.UI.motifButtons[i]:SetDimensions(AIRG.gridAlignments.styleGrid.icon_width, AIRG.gridAlignments.styleGrid.icon_height)
		if currentColumn > AIRG.gridAlignments.styleGrid.row_length then
			currentRow = currentRow + 1
			currentColumn = currentColumn - AIRG.gridAlignments.styleGrid.row_length
		end
		local yVal = AIRG.gridAlignments.styleGrid.top_align + (AIRG.gridAlignments.styleGrid.icon_box_height * currentRow)
		local xVal = AIRG.gridAlignments.styleGrid.icon_box_width * currentColumn + AIRG.gridAlignments.styleGrid.left_align
        AIRG.UI.motifButtons[i]:SetAnchor(TOPLEFT, AIRG.UI.motifSection, TOPLEFT, xVal, yVal)
        AIRG.UI.motifButtons[i]:SetTexture(AIRG.styleLookupIcons[i] .. "up.dds")
        AIRG.UI.motifButtons[i]:SetMouseEnabled(true)
        j = AIRG.styleLookupValue[i]
        tDesc ,_,_,_,_ = GetSmithingStyleItemInfo( AIRG.styleLookupItem[i] )
        AIRG.UI.motifButtons[i].tooltipText = zo_strformat("<<t:1>>\n<<t:2>>", GetString("SI_ITEMSTYLE",j), tDesc)
        AIRG.UI.motifButtons[i]:SetHandler("OnMouseEnter", function (self)
                                                ZO_Tooltips_ShowTextTooltip(self, TOP, self.tooltipText)
                                            end)
        AIRG.UI.motifButtons[i]:SetHandler("OnMouseExit", function (self)
                                                ZO_Tooltips_HideTextTooltip()
                                            end)
    end
    -- BUILD LABEL FOR STYLES
    AIRG.UI.StyleLabel = WINDOW_MANAGER:CreateControl("AIResearchStylelabel", AIRG.UI.motifSection, CT_LABEL)
    AIRG.UI.StyleLabel:SetAnchor(TOPLEFT, AIRG.UI.motifSection, TOPLEFT, 5, 14)
    AIRG.UI.StyleLabel:SetText(GetString(SI_SMITHING_HEADER_STYLE))
    AIRG.UI.StyleLabel:SetDimensions(180, 24)
    AIRG.UI.StyleLabel:SetFont("ZoFontGame")
    AIRG.UI.StyleLabel:SetHorizontalAlignment(TEXT_ALIGN_RIGHT)
end -- AIRG.initUI

-- User has clicked on one of the profession buttons
-- or we just want to refresh the display with current data
function AIRG.OnCraftSelected(_,thisCraft)
    if (thisCraft == nil) then
        if (AIRG.curCraft == nil) then
            return
        else
            thisCraft = AIRG.curCraft
        end
    end
    AIRG.UI.WindowSubTitle:SetText(AIRG.craftNames[thisCraft])
    local i,j
    local tType,tDesc,tKnown,tRemain,rowNum,traitCount
    local maxLines = GetNumSmithingResearchLines(thisCraft) -- the number of columns for this profession
    AIRG.curCraft = thisCraft
    for i = 1, AIRG.maxColumns do
        -- "blank" the grid
        for j = 1, 18 do
            AIRG.UI.gridButtons[i][j]:SetColor(1, 1, 1, 0.4)
            AIRG.UI.gridButtons[i][j]:SetTexture("/esoui/art/buttons/swatchframe_down.dds")
            AIRG.UI.gridButtons[i][j]:SetMouseEnabled(false)    -- effectively disable tooltip for this grid item.
        end
        if (i > maxLines) then
            AIRG.UI.columnButtons[i]:SetHidden(true)
            AIRG.UI.columnFooters[i]:SetText("")
        else
            local name, icon, _, _ = GetSmithingResearchLineInfo(thisCraft, i)  -- Get info on that specific item
            AIRG.UI.columnButtons[i]:SetNormalTexture(icon)
            AIRG.UI.columnButtons[i]:SetHidden(false)
            AIRG.UI.columnButtons[i].text = name

            traitCount = 0
            for rowNum,tKnown in pairs(AIRG.vars.data[AIRG.curCharacter][thisCraft][i]) do
                AIRG.UI.gridButtons[i][rowNum].tooltipText = tKnown
                if (tKnown == -1) then       -- Trait is known
                    AIRG.UI.gridButtons[i][rowNum]:SetColor(0.2, 1, 0.2, 1)   -- Green
                    AIRG.UI.gridButtons[i][rowNum]:SetTexture("/esoui/art/loot/loot_finesseitem.dds")
                    traitCount = traitCount + 1
                elseif (tKnown > 0) then   -- Trait is being researched
                    AIRG.UI.gridButtons[i][rowNum]:SetTexture("ESOUI/art/tutorial/timer_icon.dds")
                    if (tKnown < GetTimeStamp()) then   -- This is on another character and the timer has completed.
                        AIRG.UI.gridButtons[i][rowNum]:SetColor(0.2, 1, 0.2, 1)   -- Green
                        traitCount = traitCount + 1
                    else
                        AIRG.UI.gridButtons[i][rowNum]:SetColor(0.5, 0.5, 1, 1)   -- Blue
                        AIRG.UI.gridButtons[i][rowNum]:SetMouseEnabled(true)
                    end
                else                        -- Trait is NOT known
                    AIRG.UI.gridButtons[i][rowNum]:SetColor(1, 0.2, 0.2, 1)   -- Red
                    AIRG.UI.gridButtons[i][rowNum]:SetTexture("ESOUI/art/buttons/decline_up.dds")
                end
            end
            if (traitCount > 0) then
                AIRG.UI.columnFooters[i]:SetText(traitCount)
            else
                AIRG.UI.columnFooters[i]:SetText("")
            end
        end
    end
end -- AIRG:OnCraftSelected

-- Invoked when the user selected a character from the dropdown box
function AIRG.OnCharacterSelect(charName)
    if (charName == nil) then
    else
        AIRG.curCharacter = charName
    end
    AIRG.DisplayStyles()
    AIRG.OnCraftSelected()
end -- AIRG.OnCharacterSelect

-- Deletes data for the named character from the saved data and removes them from the dropdown box.
function AIRG.DeleteCharacter(charName)
    -- Can't delete the current character
    if (charName == AIRG.playerName) then
        d(AIRG.L["DeleteFalse"])
    else
        if (AIRG.vars.data[charName] ~= nil) then
            AIRG.vars.data[charName] = nil
            d(AIRG.L["DeleteTrue"] .. charName)
        end
        if (AIRG.vars.styles[charName] ~= nil) then
            AIRG.vars.styles[charName] = nil
        end
    end
end -- AIRG.DeleteCharacter

-- This function cycles through all three professions and populates the data matrix for THIS character.
-- This is carried out when the addon loasd to ensure the current character data is up-to-date.
-- The "if" logic in this function guesses at which profession should be default to display as the one with most research in.
function AIRG.PopulateMatrix()
    local curCount = 0
    local thisCount
    AIRG.vars.data[AIRG.playerName] = {}    -- create a table for this character's matrix
    thisCount = AIRG.CreateDataMatrix(CRAFTING_TYPE_BLACKSMITHING)
    if (thisCount > curCount) then
        AIRG.curCraft = CRAFTING_TYPE_BLACKSMITHING
        curCount = thisCount
    end
    thisCount = AIRG.CreateDataMatrix(CRAFTING_TYPE_CLOTHIER)
    if (thisCount > curCount) then
        AIRG.curCraft = CRAFTING_TYPE_CLOTHIER
        curCount = thisCount
    end
    thisCount = AIRG.CreateDataMatrix(CRAFTING_TYPE_WOODWORKING)
    if (thisCount > curCount) then
        AIRG.curCraft = CRAFTING_TYPE_WOODWORKING
        curCount = thisCount
    end

	if (AIRG.curCraft == nil) then
		AIRG.curCraft = CRAFTING_TYPE_BLACKSMITHING
	end
end -- AIRG.PopulateMatrix

-- Lookup the style data for the current character and send it to saved vars.
function AIRG.PopulateStyleData()
    AIRG.vars.styles[AIRG.playerName] = {}    -- create a table for this character's matrix
    local i, j
    for i = 1, AIRG.gridAlignments.styleGrid.num_styles do
        j = AIRG.styleLookupItem[i]
        AIRG.vars.styles[AIRG.playerName][i] = IsSmithingStyleKnown(j, 1) --patternIndex set to 1, temporary workaround for changes introduced in Update 4
    end
end -- AIRG.PopulateStyleData

-- Set the icon highlights for the currently selected character
function AIRG.DisplayStyles()
    local i
    if (AIRG.vars.styles[AIRG.curCharacter] == nil) then
        for i = 1, 30 do
            AIRG.UI.motifButtons[i]:SetTexture(AIRG.styleLookupIcons[i] .. "up.dds")
            AIRG.UI.motifButtons[i]:SetColor(1, 1, 1, 0.7)   -- grey
        end
    else
        for i = 1, 30 do
            if (AIRG.vars.styles[AIRG.curCharacter][i]) then
                AIRG.UI.motifButtons[i]:SetTexture(AIRG.styleLookupIcons[i] .. "down.dds")
                AIRG.UI.motifButtons[i]:SetColor(0.7, 1, 0.7, 1)   -- Green
            else
                AIRG.UI.motifButtons[i]:SetTexture(AIRG.styleLookupIcons[i] .. "up.dds")
                AIRG.UI.motifButtons[i]:SetColor(1, 1, 1, 0.7)   -- grey
            end
        end
    end
end -- AIRG.DisplayStyles()

-- Look up all the data on this profession and commit to saved variables for this character.
-- TO DO: At some point, get clever with storing the timestamp for when research will be complete
function AIRG.CreateDataMatrix(thisCraft)
    local i, j
    local tType, tKnown, tRemain, rowNum, tTargetStamp
    local rCount = 0
    local maxLines = GetNumSmithingResearchLines(thisCraft)     -- the number of columns for this profession
    AIRG.vars.data[AIRG.playerName][thisCraft] = {}             -- create a table for this profession
    -- Cycle through items for this profession
    for i = 1, maxLines do
        AIRG.vars.data[AIRG.playerName][thisCraft][i] = {}      -- create a table for this item
        -- Cycle through the traits for this item
        for j = 1, 9 do
            tType,_,tKnown = GetSmithingResearchLineTraitInfo(thisCraft,i,j)
            _,tRemain = GetSmithingResearchLineTraitTimes(thisCraft,i,j)
            rowNum = AIRG.gridTraits[tType]

            if (tKnown) then
                AIRG.vars.data[AIRG.playerName][thisCraft][i][rowNum] = -1       -- this trait is known
                rCount = rCount + 1
            else
                if (tRemain) then
                    tTargetStamp = GetTimeStamp() + tRemain
                    AIRG.vars.data[AIRG.playerName][thisCraft][i][rowNum] = tTargetStamp   -- this trait is being currently researched
                    -- The value we are setting this to is the timestamp for when the research will be complete.
                else
                    AIRG.vars.data[AIRG.playerName][thisCraft][i][rowNum] = 0   -- this trait is NOT known
                end
            end
        end
    end
    return rCount       -- the total number of traits already researched in this profession
end -- AIRG.CreateDataMatrix

function AIRG.AssignGridTraits()
    -- Translates the traitType to the correct ROW of the grid
    AIRG.gridTraits = {}
    AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_POWERED] = 1
    AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_CHARGED] = 2
    AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_PRECISE] = 3
    AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_INFUSED] = 4
    AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_DEFENDING] = 5
    AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_TRAINING] = 6
    AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_SHARPENED] = 7
    AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_WEIGHTED] = 8
    AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_NIRNHONED] = 9
    AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_STURDY] = 10
    AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_IMPENETRABLE] = 11
    AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_REINFORCED] = 12
    AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_WELL_FITTED] = 13
    AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_TRAINING] = 14
    AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_INFUSED] = 15
    AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_EXPLORATION] = 16
    AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_DIVINES] = 17
    AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_NIRNHONED] = 18
end -- AIRG.AssignGridTraits

function AIRG.AssignStyleLookups()
    -- Lookup the correct icon for the style
    AIRG.styleLookupIcons = {}
    AIRG.styleLookupIcons[1] = "ESOUI/art/charactercreate/charactercreate_altmericon_"
    AIRG.styleLookupIcons[2] = "ESOUI/art/charactercreate/charactercreate_argonianicon_"
    AIRG.styleLookupIcons[3] = "ESOUI/art/charactercreate/charactercreate_bosmericon_"
    AIRG.styleLookupIcons[4] = "ESOUI/art/charactercreate/charactercreate_bretonicon_"
    AIRG.styleLookupIcons[5] = "ESOUI/art/charactercreate/charactercreate_dunmericon_"
    AIRG.styleLookupIcons[6] = "ESOUI/art/charactercreate/charactercreate_khajiiticon_"
    AIRG.styleLookupIcons[7] = "ESOUI/art/charactercreate/charactercreate_nordicon_"
    AIRG.styleLookupIcons[8] = "ESOUI/art/charactercreate/charactercreate_orcicon_"
    AIRG.styleLookupIcons[9] = "ESOUI/art/charactercreate/charactercreate_redguardicon_"
    AIRG.styleLookupIcons[10] = "ESOUI/art/charactercreate/charactercreate_imperialicon_"
    AIRG.styleLookupIcons[11] = "ESOUI/art/progression/progression_indexicon_weapons_"
    AIRG.styleLookupIcons[12] = "ESOUI/art/progression/progression_indexicon_weapons_"
    AIRG.styleLookupIcons[13] = "ESOUI/art/progression/progression_indexicon_weapons_"
    AIRG.styleLookupIcons[14] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[15] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[16] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[17] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[18] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[19] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[20] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[21] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[22] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[23] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[24] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[25] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[26] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[27] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[28] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[29] = "ESOUI/art/progression/progression_indexicon_weapons_"
	AIRG.styleLookupIcons[30] = "ESOUI/art/progression/progression_indexicon_weapons_"
    -- Translate the icon position to the in-game type. Used for text look-up
    AIRG.styleLookupValue = {}
    AIRG.styleLookupValue[1] = ITEMSTYLE_RACIAL_HIGH_ELF
    AIRG.styleLookupValue[2] = ITEMSTYLE_RACIAL_ARGONIAN
    AIRG.styleLookupValue[3] = ITEMSTYLE_RACIAL_WOOD_ELF
    AIRG.styleLookupValue[4] = ITEMSTYLE_RACIAL_BRETON
    AIRG.styleLookupValue[5] = ITEMSTYLE_RACIAL_DARK_ELF
    AIRG.styleLookupValue[6] = ITEMSTYLE_RACIAL_KHAJIIT
    AIRG.styleLookupValue[7] = ITEMSTYLE_RACIAL_NORD
    AIRG.styleLookupValue[8] = ITEMSTYLE_RACIAL_ORC
    AIRG.styleLookupValue[9] = ITEMSTYLE_RACIAL_REDGUARD
    AIRG.styleLookupValue[10] = ITEMSTYLE_RACIAL_IMPERIAL
    AIRG.styleLookupValue[11] = ITEMSTYLE_AREA_ANCIENT_ELF
    AIRG.styleLookupValue[12] = ITEMSTYLE_AREA_REACH
    AIRG.styleLookupValue[13] = ITEMSTYLE_ENEMY_PRIMITIVE
    AIRG.styleLookupValue[14] = ITEMSTYLE_ENEMY_DAEDRIC
	AIRG.styleLookupValue[15] = ITEMSTYLE_AREA_DWEMER
	AIRG.styleLookupValue[16] = ITEMSTYLE_GLASS
	AIRG.styleLookupValue[17] = ITEMSTYLE_AREA_XIVKYN
	AIRG.styleLookupValue[18] = ITEMSTYLE_AREA_AKAVIRI
	AIRG.styleLookupValue[19] = ITEMSTYLE_UNDAUNTED
	AIRG.styleLookupValue[20] = ITEMSTYLE_AREA_ANCIENT_ORC
	AIRG.styleLookupValue[21] = ITEMSTYLE_DEITY_TRINIMAC
	AIRG.styleLookupValue[22] = ITEMSTYLE_DEITY_MALACATH
	AIRG.styleLookupValue[23] = ITEMSTYLE_ORG_OUTLAW
	AIRG.styleLookupValue[24] = ITEMSTYLE_ALLIANCE_ALDMERI
	AIRG.styleLookupValue[25] = ITEMSTYLE_ALLIANCE_DAGGERFALL
	AIRG.styleLookupValue[26] = ITEMSTYLE_ALLIANCE_EBONHEART
	AIRG.styleLookupValue[27] = ITEMSTYLE_AREA_SOUL_SHRIVEN
	AIRG.styleLookupValue[28] = ITEMSTYLE_ORG_ABAHS_WATCH
	AIRG.styleLookupValue[29] = ITEMSTYLE_ORG_THIEVES_GUILD
	AIRG.styleLookupValue[30] = ITEMSTYLE_ORG_ASSASSINS
    -- This is a bit of a hack, but only because of the way ESO uses Style Items with different index to styles.
    AIRG.styleLookupItem = {}
    AIRG.styleLookupItem[1] = 8     -- Altmer       		= Adamantite
    AIRG.styleLookupItem[2] = 7     -- Argonian     		= Flint
    AIRG.styleLookupItem[3] = 9     -- Bosmer       		= Bone
    AIRG.styleLookupItem[4] = 2     -- Breton       		= Molybdenum
    AIRG.styleLookupItem[5] = 5     -- Dunmer       		= Obsidian
    AIRG.styleLookupItem[6] = 10    -- Khajit       		= Moonstone
    AIRG.styleLookupItem[7] = 6     -- Nord         		= Corundum
    AIRG.styleLookupItem[8] = 4     -- Orc          		= Manganese
    AIRG.styleLookupItem[9] = 3     -- Redguard     		= Starmetal
    AIRG.styleLookupItem[10] = 35   -- Imperial     		= Nickel
    AIRG.styleLookupItem[11] = 16   -- Ancient Elf  		= Palladium
    AIRG.styleLookupItem[12] = 18   -- Barbarian    		= Copper
    AIRG.styleLookupItem[13] = 20   -- Primal       		= Argentum
    AIRG.styleLookupItem[14] = 21   -- Daedric      		= Daedra Heart
	AIRG.styleLookupItem[15] = 15   -- Dwemer       		= Dwemer Frame
	AIRG.styleLookupItem[16] = 29   -- Glass     			= Malachite
	AIRG.styleLookupItem[17] = 30   -- Xivkyn  				= Charcoal of Remorse
	AIRG.styleLookupItem[18] = 34   -- Akaviri      		= Gold Scale
	AIRG.styleLookupItem[19] = 27   -- Mercenary    		= Laurels
	AIRG.styleLookupItem[20] = 23   -- Ancient Orc  		= Casserite
	AIRG.styleLookupItem[21] = 22   -- Trinimac     		= Auric Tusk
	AIRG.styleLookupItem[22] = 14   -- Malacath     		= Potash
	AIRG.styleLookupItem[23] = 48   -- Outlaw      			= Rogue's Soot
	AIRG.styleLookupItem[24] = 26   -- Aldmeri Dominion     = Eagle Feather
	AIRG.styleLookupItem[25] = 24   -- Daggerfall Covenant  = Lion Fang
	AIRG.styleLookupItem[26] = 25   -- Ebonheart Pact      	= Dragon Scute
	AIRG.styleLookupItem[27] = 31   -- Soul Shriven      	= Azure Plasm
	AIRG.styleLookupItem[28] = 42   -- Abah's Watch      	= Polished Shilling
	AIRG.styleLookupItem[29] = 12   -- Thieves' Guild      	= Fine Chalk
	AIRG.styleLookupItem[30] = 47   -- Assassin's League    = Tainted Blood
end -- AIRG.AssignStyleLookups

-- EOF