-- Shopkeeper UI Functions File
-- Last Updated August 26, 2014
-- Written August 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
-- Released under terms in license accompanying this file.
-- Distribution without license is prohibited!

-- Handle the OnMoveStop event for the windows
function Shopkeeper:OnWindowMoveStop(windowMoved)
  local settingsToUse = Shopkeeper:ActiveSettings()

  if windowMoved == ShopkeeperWindow then
    settingsToUse.winLeft = ShopkeeperWindow:GetLeft()
    settingsToUse.winTop = ShopkeeperWindow:GetTop()
  elseif windowMoved == ShopkeeperMiniWindow then
    settingsToUse.miniWinLeft = ShopkeeperMiniWindow:GetLeft()
    settingsToUse.miniWinTop = ShopkeeperMiniWindow:GetTop()
  else
    settingsToUse.statsWinLeft = ShopkeeperStatsWindow:GetLeft()
    settingsToUse.statsWinTop = ShopkeeperStatsWindow:GetTop()
  end
end

-- Restore the window positions from saved vars
function Shopkeeper:RestoreWindowPosition()
  local settingsToUse = Shopkeeper:ActiveSettings()

  ShopkeeperWindow:ClearAnchors()
  ShopkeeperStatsWindow:ClearAnchors()
  ShopkeeperMiniWindow:ClearAnchors()

  ShopkeeperWindow:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, settingsToUse.winLeft, settingsToUse.winTop)
  ShopkeeperStatsWindow:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, settingsToUse.statsWinLeft, settingsToUse.statsWinTop)
  ShopkeeperMiniWindow:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, settingsToUse.miniWinLeft, settingsToUse.miniWinTop)
end

-- Handle the changing of window font settings
function Shopkeeper:UpdateFonts()
  local LMP = LibStub("LibMediaProvider-1.0")
  if LMP then
    local font = LMP:Fetch('font', Shopkeeper:ActiveSettings().windowFont)
    local fontString = font .. "|%d"
    local mainButtonLabel = 16
    local mainTitle = 26
    local mainHeader = 18
    local miniButtonLabel = 12
    local miniTitle = 20
    local miniHeader = 14

    -- Main Window
    ShopkeeperWindowSearchBox:SetFont(string.format(fontString, mainButtonLabel))
    ShopkeeperWindowTitle:SetFont(string.format(fontString, mainTitle))
    ShopkeeperWindowBuyer:SetFont(string.format(fontString, mainHeader))
    ShopkeeperWindowGuild:SetFont(string.format(fontString, mainHeader))
    ShopkeeperWindowItemName:SetFont(string.format(fontString, mainHeader))
    ShopkeeperWindowSellTime:SetFont(string.format(fontString, mainHeader))
    ShopkeeperWindowPrice:SetFont(string.format(fontString, mainHeader))
    ShopkeeperSwitchViewButton:SetFont(string.format(fontString, mainButtonLabel))
    ShopkeeperPriceSwitchButton:SetFont(string.format(fontString, mainButtonLabel))
    ShopkeeperResetButton:SetFont(string.format(fontString, mainButtonLabel))
    ShopkeeperRefreshButton:SetFont(string.format(fontString, mainButtonLabel))

    -- Mini Window
    ShopkeeperMiniWindowSearchBox:SetFont(string.format(fontString, miniButtonLabel))
    ShopkeeperMiniWindowTitle:SetFont(string.format(fontString, miniTitle))
    ShopkeeperMiniWindowGuild:SetFont(string.format(fontString, miniHeader))
    ShopkeeperMiniWindowItemName:SetFont(string.format(fontString, miniHeader))
    ShopkeeperMiniWindowSellTime:SetFont(string.format(fontString, miniHeader))
    ShopkeeperMiniWindowPrice:SetFont(string.format(fontString, miniHeader))
    ShopkeeperMiniSwitchViewButton:SetFont(string.format(fontString, miniButtonLabel))
    ShopkeeperMiniPriceSwitchButton:SetFont(string.format(fontString, miniButtonLabel))
    ShopkeeperMiniResetButton:SetFont(string.format(fontString, miniButtonLabel))
    ShopkeeperMiniRefreshButton:SetFont(string.format(fontString, miniButtonLabel))

    -- Stats Window
    ShopkeeperStatsWindowTitle:SetFont(string.format(fontString, mainTitle))
    ShopkeeperStatsWindowGuildChooserLabel:SetFont(string.format(fontString, mainHeader))
    ShopkeeperStatsGuildChooser.m_comboBox:SetFont(string.format(fontString, mainHeader))
    ShopkeeperStatsWindowItemsSoldLabel:SetFont(string.format(fontString, mainHeader))
    ShopkeeperStatsWindowTotalGoldLabel:SetFont(string.format(fontString, mainHeader))
    ShopkeeperStatsWindowBiggestSaleLabel:SetFont(string.format(fontString, mainHeader))
    ShopkeeperStatsWindowSliderSettingLabel:SetFont(string.format(fontString, mainHeader))
    ShopkeeperStatsWindowSliderLabel:SetFont(string.format(fontString, mainButtonLabel))

    -- Rows for inside main/mini windows
    for i = 1, #self.DataRows do
      local dataRow = self.DataRows[i]
      dataRow:GetNamedChild("Buyer"):SetFont(string.format(fontString, mainButtonLabel))
      dataRow:GetNamedChild("Guild"):SetFont(string.format(fontString, mainButtonLabel))
      dataRow:GetNamedChild("ItemName"):SetFont(string.format(fontString, mainButtonLabel))
      dataRow:GetNamedChild("Quantity"):SetFont(string.format(fontString, mainButtonLabel))
      dataRow:GetNamedChild("SellTime"):SetFont(string.format(fontString, mainButtonLabel))
      dataRow:GetNamedChild("Price"):SetFont(string.format(fontString, mainButtonLabel))
      if i <= #self.MiniDataRows then
        local miniDataRow = self.MiniDataRows[i]
        miniDataRow:GetNamedChild("Guild"):SetFont(string.format(fontString, miniButtonLabel))
        miniDataRow:GetNamedChild("ItemName"):SetFont(string.format(fontString, miniButtonLabel))
        miniDataRow:GetNamedChild("Quantity"):SetFont(string.format(fontString, miniButtonLabel))
        miniDataRow:GetNamedChild("SellTime"):SetFont(string.format(fontString, miniButtonLabel))
        miniDataRow:GetNamedChild("Price"):SetFont(string.format(fontString, miniButtonLabel))
      end
    end
  end
end

-- Display item tooltips
function Shopkeeper.ShowToolTip(itemName, itemButton)
  InitializeTooltip(ItemTooltip, itemButton)
  ItemTooltip:SetLink(itemName)
end

-- Clear a given row (1-indexed)'s data
function Shopkeeper:ClearDataRow(index)
  if index < 1 or index > 15 then
    return
  end

  local dataRow = self.DataRows[index]
  dataRow:GetNamedChild("Buyer"):SetText("")
  dataRow:GetNamedChild("Buyer"):SetHandler("OnMouseDoubleClick", nil)
  dataRow:GetNamedChild("Guild"):SetText("")
  dataRow:GetNamedChild("ItemIcon"):SetTexture(nil)
  dataRow:GetNamedChild("ItemIcon"):SetHidden(true)
  local itemCell = dataRow:GetNamedChild("ItemName")
  itemCell:SetText("")
  itemCell:SetHandler("OnMouseDoubleClick", nil)
  itemCell:SetHandler("OnMouseEnter", nil)
  dataRow:GetNamedChild("Quantity"):SetText("")
  dataRow:GetNamedChild("SellTime"):SetText("")
  dataRow:GetNamedChild("Price"):SetText("")
end

-- Clear a given mini row (1-indexed)'s data
function Shopkeeper:ClearMiniDataRow(index)
  if index < 1 or index > 8 then
    return
  end

  local dataRow = self.MiniDataRows[index]
  dataRow:GetNamedChild("Guild"):SetText("")
  dataRow:GetNamedChild("ItemIcon"):SetTexture(nil)
  dataRow:GetNamedChild("ItemIcon"):SetHidden(true)
  local itemCell = dataRow:GetNamedChild("ItemName")
  itemCell:SetText("")
  itemCell:SetHandler("OnMouseDoubleClick", nil)
  itemCell:SetHandler("OnMouseEnter", nil)
  dataRow:GetNamedChild("Quantity"):SetText("")
  dataRow:GetNamedChild("SellTime"):SetText("")
  dataRow:GetNamedChild("Price"):SetText("")
end

-- Fill out a row with the given data
function Shopkeeper:SetDataRow(index, buyer, guild, itemName, icon, quantity, sellTime, price, seller, kioskSale)
  if index < 1 or index > 15 then return end

  local dataRow = self.DataRows[index]

  -- Some extra stuff for the Buyer cell to handle double-click and color changes
  -- Plus add a marker if buyer is not in-guild (kiosk sale)
  local buyerCell = dataRow:GetNamedChild("Buyer")
  local buyerString = buyer
  if kioskSale then
    buyerString = "|t16:16:/EsoUI/Art/icons/item_generic_coinbag.dds|t" .. buyerString
  end
  buyerCell:SetText(buyerString)
  -- If the seller is the player, color the buyer green.  Otherwise, blue.
  local acctName = GetDisplayName()
  if seller == acctName then
    buyerCell:SetNormalFontColor(0.18, 0.77, 0.05, 1)
    buyerCell:SetPressedFontColor(0.18, 0.77, 0.05, 1)
    buyerCell:SetMouseOverFontColor(0.32, 0.90, 0.18, 1)
  else
    buyerCell:SetNormalFontColor(0.21, 0.54, 0.94, 1)
    buyerCell:SetPressedFontColor(0.21, 0.54, 0.94, 1)
    buyerCell:SetMouseOverFontColor(0.34, 0.67, 1, 1)
  end
  buyerCell:SetHandler("OnMouseDoubleClick", function()
    if SCENE_MANAGER.currentScene.name == "mailSend" then
      ZO_MailSendToField:SetText("")
      ZO_MailSendToField:SetText(ZO_MailSendToField:GetText() .. buyer)
    else
      ZO_ChatWindowTextEntryEditBox:SetText("/w " .. buyer .. " " .. ZO_ChatWindowTextEntryEditBox:GetText())
    end
  end)
  local buyerCellLabel = buyerCell:GetLabelControl()
  buyerCellLabel:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)

  -- Guild cell
  dataRow:GetNamedChild("Guild"):SetText(guild)
  local guildCellLabel = dataRow:GetNamedChild("Guild"):GetLabelControl()
  guildCellLabel:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)

  -- Item Icon
  dataRow:GetNamedChild("ItemIcon"):SetHidden(false)
  dataRow:GetNamedChild("ItemIcon"):SetTexture(icon)

  -- Item name cell
  local itemCell = dataRow:GetNamedChild("ItemName")
  itemCell:SetText(zo_strformat("<<t:1>>", itemName))
  -- Insert the item link into the chat box, with a quick substitution so brackets show up
  itemCell:SetHandler("OnMouseDoubleClick", function()
    ZO_ChatWindowTextEntryEditBox:SetText(ZO_ChatWindowTextEntryEditBox:GetText() .. string.gsub(itemName, "|H0", "|H1"))
  end)
  itemCell:SetHandler("OnMouseEnter", function() self.ShowToolTip(itemName, itemCell) end)
  itemCell:SetHandler("OnMouseExit", function() ClearTooltip(ItemTooltip) end)
  local itemCellLabel = itemCell:GetLabelControl()
  itemCellLabel:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)

  -- Quantity cell
  dataRow:GetNamedChild("Quantity"):SetText("x" .. quantity)

  -- Sale time cell
  dataRow:GetNamedChild("SellTime"):SetText(sellTime)

  -- Handle the setting of whether or not to show pre-cut sale prices
  -- math.floor(number + 0.5) is a quick shorthand way to round for
  -- positive values.
  local dispPrice = price
  local settingsToUse = Shopkeeper:ActiveSettings()
  if settingsToUse.showFullPrice then
    if settingsToUse.showUnitPrice and quantity > 0 then
      dispPrice = math.floor((dispPrice / quantity) + 0.5)
    end
  else
    local cutPrice = price * (1 - (GetTradingHouseCutPercentage() / 100))
    if settingsToUse.showUnitPrice and quantity > 0 then
      cutPrice = cutPrice / quantity
    end
    dispPrice = math.floor(cutPrice + 0.5)
  end

  -- Insert thousands separators for the price
  local stringPrice = self.LocalizedNumber(dispPrice)

  -- Finally, set the price
  dataRow:GetNamedChild("Price"):SetText(stringPrice .. " |t16:16:EsoUI/Art/currency/currency_gold.dds|t")
end

-- Fill out a row with the given data
function Shopkeeper:SetMiniDataRow(index, guild, itemName, icon, quantity, sellTime, price, seller)
  if index < 1 or index > 8 then return end

  local dataRow = self.MiniDataRows[index]

  -- Guild cell
  dataRow:GetNamedChild("Guild"):SetText(guild)
  local guildCellLabel = dataRow:GetNamedChild("Guild"):GetLabelControl()
  guildCellLabel:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)

  -- Item Icon
  dataRow:GetNamedChild("ItemIcon"):SetHidden(false)
  dataRow:GetNamedChild("ItemIcon"):SetTexture(icon)

  -- Item name cell
  local itemCell = dataRow:GetNamedChild("ItemName")
  itemCell:SetText(zo_strformat("<<t:1>>", itemName))
  -- Insert the item link into the chat box, with a quick substitution so brackets show up
  itemCell:SetHandler("OnMouseDoubleClick", function()
    ZO_ChatWindowTextEntryEditBox:SetText(ZO_ChatWindowTextEntryEditBox:GetText() .. string.gsub(itemName, "|H0", "|H1"))
  end)
  itemCell:SetHandler("OnMouseEnter", function() self.ShowToolTip(itemName, itemCell) end)
  itemCell:SetHandler("OnMouseExit", function() ClearTooltip(ItemTooltip) end)
  local itemCellLabel = itemCell:GetLabelControl()
  itemCellLabel:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)

  -- Quantity cell
  dataRow:GetNamedChild("Quantity"):SetText("x" .. quantity)

  -- Sale time cell
  dataRow:GetNamedChild("SellTime"):SetText(sellTime)

  -- Handle the setting of whether or not to show pre-cut sale prices
  -- math.floor(number + 0.5) is a quick shorthand way to round for
  -- positive values.
  local dispPrice = price
  local settingsToUse = Shopkeeper:ActiveSettings()
  if settingsToUse.showFullPrice then
    if settingsToUse.showUnitPrice and quantity > 0 then
      dispPrice = math.floor((dispPrice / quantity) + 0.5)
    end
  else
    local cutPrice = price * (1 - (GetTradingHouseCutPercentage() / 100))
    if settingsToUse.showUnitPrice and quantity > 0 then
      cutPrice = cutPrice / quantity
    end
    dispPrice = math.floor(cutPrice + 0.5)
  end

  -- Insert thousands separators for the price
  local stringPrice = self.LocalizedNumber(dispPrice)

  -- Finally, set the price
  dataRow:GetNamedChild("Price"):SetText(stringPrice .. " |t16:16:EsoUI/Art/currency/currency_gold.dds|t")
end

-- Build the data rows based on the position of the slider
function Shopkeeper:DisplayRows()
  if Shopkeeper:ActiveSettings().viewSize == "full" then
    local startIndex = ShopkeeperWindowSlider:GetValue()
    if startIndex + #self.DataRows > #self.SearchTable then
      startIndex = #self.SearchTable - #self.DataRows
    end

    if startIndex < 1 then startIndex = 0 end

    -- Hide the slider if there's less than a full page of results
    ShopkeeperWindowSlider:SetHidden(#self.SearchTable < 16)

    -- Now that we know where to start in the table, fill out rows with the next
    -- (currently) 15 items in the scan results table.
    for i = 1, #self.DataRows do
      local rowIndex = i + startIndex
      if rowIndex > #self.SearchTable then
        self:ClearDataRow(i)
        ShopkeeperWindowSlider:SetHidden(true)
      else
        local scanResult = self.SearchTable[rowIndex]
        -- Older data won't have kiosk info
        local kioskSale = nil
        if #scanResult > 8 then kioskSale = scanResult[9] end
        self:SetDataRow(i, scanResult[1], scanResult[2], scanResult[3], scanResult[4], scanResult[5], self.TextTimeSince(scanResult[6], false), scanResult[7], scanResult[8], kioskSale)
      end
    end

    -- Scale the slider's range to the number of items we have minus the number of rows
    local sliderMax = 0
    local tableToUse = self.SearchTable
    if #tableToUse > 15 then sliderMax = (#tableToUse - 15) end
    ShopkeeperWindowSlider:SetMinMax(0, sliderMax)

  -- Mini size
  else
    local startIndex = ShopkeeperMiniWindowSlider:GetValue()
    if startIndex + #self.MiniDataRows > #self.SearchTable then
      startIndex = #self.SearchTable - #self.MiniDataRows
    end

    if startIndex < 1 then startIndex = 0 end

    -- Hide the slider if there's less than a full page of results
    ShopkeeperMiniWindowSlider:SetHidden(#self.SearchTable < 9)

    -- Now that we know where to start in the table, fill out rows with the next
    -- (currently) 8 items in the scan results table.
    for i = 1, #self.MiniDataRows do
      local rowIndex = i + startIndex
      if rowIndex > #self.SearchTable then
        self:ClearMiniDataRow(i)
        ShopkeeperMiniWindowSlider:SetHidden(true)
      else
        local scanResult = self.SearchTable[rowIndex]
        self:SetMiniDataRow(i, scanResult[2], scanResult[3], scanResult[4], scanResult[5], self.TextTimeSince(scanResult[6], false), scanResult[7], scanResult[8])
      end
    end

    -- Scale the slider's range to the number of items we have minus the number of rows
    local sliderMax = 0
    if #self.SearchTable > 8 then sliderMax = (#self.SearchTable - 8) end
    ShopkeeperMiniWindowSlider:SetMinMax(0, sliderMax)
  end

  -- If the stats window is open, update it also
  if not ShopkeeperStatsWindow:IsHidden() then
    local guildDropdown = ZO_ComboBox_ObjectFromContainer(ShopkeeperStatsGuildChooser)
    local selectedGuild = guildDropdown:GetSelectedItem()
    if selectedGuild == GetString(SK_STATS_ALL_GUILDS) then selectedGuild = "SK_STATS_TOTAL" end
    self:UpdateStatsWindow(selectedGuild)
  end
end

-- Update all the fields of the stats window based on the response from SalesStats()
function Shopkeeper:UpdateStatsWindow(guildName)
  local sliderLevel = ShopkeeperStatsWindowSlider:GetValue()
  self.newStats = self:SalesStats(sliderLevel)

  -- Hide the slider if there's less than a day of data
  -- and set the slider's range for the new day range returned
  ShopkeeperStatsWindowSliderLabel:SetHidden(false)
  ShopkeeperStatsWindowSlider:SetHidden(false)
  if self.newStats['totalDays'] == nil or self.newStats['totalDays'] < 2 then
    ShopkeeperStatsWindowSlider:SetHidden(true)
    ShopkeeperStatsWindowSliderLabel:SetHidden(true)
    sliderLevel = 0
  elseif sliderLevel > (self.newStats['totalDays'] - 1) then
    sliderLevel = 0
  end
  ShopkeeperStatsWindowSlider:SetMinMax(0, (self.newStats['totalDays'] - 1))

  -- Set the time range label appropriately
  if sliderLevel == 0 then
    ShopkeeperStatsWindowSliderSettingLabel:SetText(GetString(SK_STATS_TIME_ALL))
  else
    ShopkeeperStatsWindowSliderSettingLabel:SetText(zo_strformat(GetString(SK_STATS_TIME_SOME), sliderLevel))
  end

  -- Grab which guild is selected
  local guildSelected = GetString(SK_STATS_ALL_GUILDS)
  if guildName ~= "SK_STATS_TOTAL" then guildSelected = guildName end
  local guildDropdown = ZO_ComboBox_ObjectFromContainer(ShopkeeperStatsGuildChooser)
  guildDropdown:SetSelectedItem(guildSelected)

  -- And set the rest of the stats window up with data from the appropriate
  -- guild (or overall data)
  ShopkeeperStatsWindowItemsSoldLabel:SetText(string.format(GetString(SK_STATS_ITEMS_SOLD), self.LocalizedNumber(self.newStats['numSold'][guildName]), self.newStats['kioskPercent'][guildName]))
  ShopkeeperStatsWindowTotalGoldLabel:SetText(string.format(GetString(SK_STATS_TOTAL_GOLD), self.LocalizedNumber(self.newStats['totalGold'][guildName]), self.LocalizedNumber(self.newStats['avgGold'][guildName])))
  ShopkeeperStatsWindowBiggestSaleLabel:SetText(string.format(GetString(SK_STATS_BIGGEST), zo_strformat("<<t:1>>", self.newStats['biggestSale'][guildName][2]), self.LocalizedNumber(self.newStats['biggestSale'][guildName][1])))
end

-- Switches the main window between full and half size.  Really this is hiding one
-- and showing the other, but close enough ;)  Also makes the scene adjustments
-- necessary to maintain the desired mail/trading house behaviors.
function Shopkeeper:ToggleViewMode()
  local settingsToUse = Shopkeeper:ActiveSettings()
  if settingsToUse.viewSize == "full" then
    settingsToUse.viewSize = "half"
    ShopkeeperMiniWindowSearchBox:SetText(ShopkeeperWindowSearchBox:GetText())
    ShopkeeperWindow:SetHidden(true)
    self:DisplayRows()
    ShopkeeperMiniWindow:SetHidden(false)

    if settingsToUse.openWithMail then
      MAIL_INBOX_SCENE:RemoveFragment(self.uiFragment)
      MAIL_SEND_SCENE:RemoveFragment(self.uiFragment)
      MAIL_INBOX_SCENE:AddFragment(self.miniUiFragment)
      MAIL_SEND_SCENE:AddFragment(self.miniUiFragment)
    end

    if settingsToUse.openWithStore then
      TRADING_HOUSE_SCENE:RemoveFragment(self.uiFragment)
      TRADING_HOUSE_SCENE:AddFragment(self.miniUiFragment)
    end
  else
    settingsToUse.viewSize = "full"
    ShopkeeperWindowSearchBox:SetText(ShopkeeperMiniWindowSearchBox:GetText())
    ShopkeeperMiniWindow:SetHidden(true)
    self:DisplayRows()
    ShopkeeperWindow:SetHidden(false)

    if settingsToUse.openWithMail then
      MAIL_INBOX_SCENE:RemoveFragment(self.miniUiFragment)
      MAIL_SEND_SCENE:RemoveFragment(self.miniUiFragment)
      MAIL_INBOX_SCENE:AddFragment(self.uiFragment)
      MAIL_SEND_SCENE:AddFragment(self.uiFragment)
    end

    if settingsToUse.openWithStore then
      TRADING_HOUSE_SCENE:RemoveFragment(self.miniUiFragment)
      TRADING_HOUSE_SCENE:AddFragment(self.uiFragment)
    end
  end
end

-- Set the visibility status of the main window to the opposite of its current status
function Shopkeeper.ToggleShopkeeperWindow()
  if Shopkeeper:ActiveSettings().viewSize == "full" then
    ShopkeeperMiniWindow:SetHidden(true)
    if ShopkeeperWindow:IsHidden() then
      Shopkeeper:DisplayRows()
      SetGameCameraUIMode(true)
    end

    ShopkeeperWindow:SetHidden(not ShopkeeperWindow:IsHidden())
  else
    ShopkeeperWindow:SetHidden(true)
    if ShopkeeperMiniWindow:IsHidden() then
      Shopkeeper:DisplayRows()
      SetGameCameraUIMode(true)
    end

    ShopkeeperMiniWindow:SetHidden(not ShopkeeperMiniWindow:IsHidden())
  end
end

-- Set the visibility status of the stats window to the opposite of its current status
function Shopkeeper.ToggleShopkeeperStatsWindow()
  if ShopkeeperStatsWindow:IsHidden() then Shopkeeper:UpdateStatsWindow("SK_STATS_TOTAL") end
  ShopkeeperStatsWindow:SetHidden(not ShopkeeperStatsWindow:IsHidden())
end

-- Switch between all sales and your sales
function Shopkeeper:SwitchViewMode()
  if self.viewMode == "self" then
    ShopkeeperSwitchViewButton:SetText(GetString(SK_VIEW_YOUR_SALES))
    ShopkeeperWindowTitle:SetText("Shopkeeper - " .. GetString(SK_ALL_SALES_TITLE))
    ShopkeeperMiniSwitchViewButton:SetText(GetString(SK_VIEW_YOUR_SALES))
    ShopkeeperMiniWindowTitle:SetText("Shopkeeper - " .. GetString(SK_ALL_SALES_TITLE))
    self.viewMode = "all"
  else
    ShopkeeperSwitchViewButton:SetText(GetString(SK_VIEW_ALL_SALES))
    ShopkeeperWindowTitle:SetText("Shopkeeper - " .. GetString(SK_YOUR_SALES_TITLE))
    ShopkeeperMiniSwitchViewButton:SetText(GetString(SK_VIEW_ALL_SALES))
    ShopkeeperMiniWindowTitle:SetText("Shopkeeper - " .. GetString(SK_YOUR_SALES_TITLE))
    self.viewMode = "self"
  end

  if Shopkeeper:ActiveSettings().viewSize == "full" then
    self:DoSearch(ShopkeeperWindowSearchBox:GetText())
  else
    self:DoSearch(ShopkeeperMiniWindowSearchBox:GetText())
  end
end

-- Switch between total price mode and unit price mode
function Shopkeeper:SwitchPriceMode()
  local settingsToUse = Shopkeeper:ActiveSettings()
  if settingsToUse.showUnitPrice then
    settingsToUse.showUnitPrice = false
    ShopkeeperPriceSwitchButton:SetText(GetString(SK_SHOW_UNIT))
    ShopkeeperWindowPrice:SetText(GetString(SK_PRICE_COLUMN))
    ShopkeeperMiniPriceSwitchButton:SetText(GetString(SK_SHOW_UNIT))
    ShopkeeperMiniWindowPrice:SetText(GetString(SK_PRICE_COLUMN))
  else
    settingsToUse.showUnitPrice = true
    ShopkeeperPriceSwitchButton:SetText(GetString(SK_SHOW_TOTAL))
    ShopkeeperWindowPrice:SetText(GetString(SK_PRICE_EACH_COLUMN))
    ShopkeeperMiniPriceSwitchButton:SetText(GetString(SK_SHOW_TOTAL))
    ShopkeeperMiniWindowPrice:SetText(GetString(SK_PRICE_EACH_COLUMN))
  end

  if self.curSort[1] == "price" then
    self:SortByPrice(self.curSort[2], self.SearchTable)
  else
    self:DisplayRows()
  end
end

-- Handle scrolling the main window
function Shopkeeper.OnSliderMouseWheel(self, delta)
  if Shopkeeper:ActiveSettings().viewSize == "full" then
    local oldSliderLevel = ShopkeeperWindowSlider:GetValue()
    local newSliderLevel = oldSliderLevel - delta
    ShopkeeperWindowSlider:SetValue(newSliderLevel)
  else
    local oldSliderLevel = ShopkeeperMiniWindowSlider:GetValue()
    local newSliderLevel = oldSliderLevel - delta
    ShopkeeperMiniWindowSlider:SetValue(newSliderLevel)
  end
end

-- Update the table if the slider moved
function Shopkeeper.OnSliderMoved(self, sliderLevel, eventReason)
  Shopkeeper:DisplayRows()
end

-- Update the stats window if the slider in it moved
function Shopkeeper.OnStatsSliderMoved(self, sliderLevel, eventReason)
  local guildDropdown = ZO_ComboBox_ObjectFromContainer(ShopkeeperStatsGuildChooser)
  local selectedGuild = guildDropdown:GetSelectedItem()
  if selectedGuild == GetString(SK_STATS_ALL_GUILDS) then selectedGuild = "SK_STATS_TOTAL" end
  Shopkeeper:UpdateStatsWindow(selectedGuild)
end

-- Set up the labels and tooltips from translation files and do a couple other UI
-- setup routines
function Shopkeeper:SetupShopkeeperWindow()
  local settingsToUse = Shopkeeper:ActiveSettings()
  -- Shopkeeper button in guild store screen
  local reopenShopkeeper = CreateControlFromVirtual("ShopkeeperReopenButton", ZO_TradingHouseLeftPane, "ZO_DefaultButton")
  reopenShopkeeper:SetAnchor(CENTER, ZO_TradingHouseLeftPane, BOTTOM, 0, 5)
  reopenShopkeeper:SetWidth(200)
  reopenShopkeeper:SetText("Shopkeeper")
  reopenShopkeeper:SetHandler("OnClicked", self.ToggleShopkeeperWindow)

  -- Shopkeeper button in mail screen
  local shopkeeperMail = CreateControlFromVirtual("ShopkeeperMailButton", ZO_MailInbox, "ZO_DefaultButton")
  shopkeeperMail:SetAnchor(TOPLEFT, ZO_MailInbox, TOPLEFT, 100, 4)
  shopkeeperMail:SetWidth(200)
  shopkeeperMail:SetText("Shopkeeper")
  shopkeeperMail:SetHandler("OnClicked", self.ToggleShopkeeperWindow)

  -- Stats dropdown choice box
  local shopkeeperStatsGuild = CreateControlFromVirtual("ShopkeeperStatsGuildChooser", ShopkeeperStatsWindow, "ShopkeeperStatsGuildDropdown")
  shopkeeperStatsGuild:SetDimensions(270,25)
  shopkeeperStatsGuild:SetAnchor(LEFT, ShopkeeperStatsWindowGuildChooserLabel, RIGHT, 5, 0)
  shopkeeperStatsGuild.m_comboBox:SetSortsItems(false)

  -- Set column headers and search label from translation
  ShopkeeperWindowBuyer:SetText(GetString(SK_BUYER_COLUMN))
  ShopkeeperWindowGuild:SetText(GetString(SK_GUILD_COLUMN))
  ShopkeeperWindowItemName:SetText(GetString(SK_ITEM_COLUMN))
  ShopkeeperWindowSellTime:SetText(GetString(SK_TIME_COLUMN))
  ShopkeeperMiniWindowGuild:SetText(GetString(SK_GUILD_COLUMN))
  ShopkeeperMiniWindowItemName:SetText(GetString(SK_ITEM_COLUMN))
  ShopkeeperMiniWindowSellTime:SetText(GetString(SK_TIME_COLUMN))

  if settingsToUse.showUnitPrice then
    ShopkeeperWindowPrice:SetText(GetString(SK_PRICE_EACH_COLUMN))
    ShopkeeperMiniWindowPrice:SetText(GetString(SK_PRICE_EACH_COLUMN))
  else
    ShopkeeperWindowPrice:SetText(GetString(SK_PRICE_COLUMN))
    ShopkeeperMiniWindowPrice:SetText(GetString(SK_PRICE_COLUMN))
  end

  -- Set second half of window title from translation
  ShopkeeperWindowTitle:SetText("Shopkeeper - " .. GetString(SK_YOUR_SALES_TITLE))
  ShopkeeperMiniWindowTitle:SetText("Shopkeeper - " .. GetString(SK_YOUR_SALES_TITLE))

  -- And set the stats window title and slider label from translation
  ShopkeeperStatsWindowTitle:SetText("Shopkeeper " .. GetString(SK_STATS_TITLE))
  ShopkeeperStatsWindowGuildChooserLabel:SetText(GetString(SK_GUILD_COLUMN) .. ": ")
  ShopkeeperStatsWindowSliderLabel:SetText(GetString(SK_STATS_DAYS))

  -- Set up some helpful tooltips for the Buyer, Item, Time, and Price column headers
  ShopkeeperWindowBuyer:SetHandler("OnMouseEnter", function(self)
    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_BUYER_TOOLTIP)) end)

  ShopkeeperWindowItemName:SetHandler("OnMouseEnter", function(self)
    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_ITEM_TOOLTIP)) end)

  ShopkeeperMiniWindowItemName:SetHandler("OnMouseEnter", function(self)
    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_ITEM_TOOLTIP)) end)

  ShopkeeperWindowSellTime:SetHandler("OnMouseEnter", function(self)
    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SORT_TIME_TOOLTIP)) end)

  ShopkeeperMiniWindowSellTime:SetHandler("OnMouseEnter", function(self)
    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SORT_TIME_TOOLTIP)) end)

  ShopkeeperWindowPrice:SetHandler("OnMouseEnter", function(self)
    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SORT_PRICE_TOOLTIP)) end)

  ShopkeeperMiniWindowPrice:SetHandler("OnMouseEnter", function(self)
    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SORT_PRICE_TOOLTIP)) end)

  -- View switch button
  ShopkeeperSwitchViewButton:SetText(GetString(SK_VIEW_ALL_SALES))
  ShopkeeperMiniSwitchViewButton:SetText(GetString(SK_VIEW_ALL_SALES))

  -- Total / unit price switch button
  if settingsToUse.showUnitPrice then
    ShopkeeperPriceSwitchButton:SetText(GetString(SK_SHOW_TOTAL))
    ShopkeeperMiniPriceSwitchButton:SetText(GetString(SK_SHOW_TOTAL))
  else
    ShopkeeperPriceSwitchButton:SetText(GetString(SK_SHOW_UNIT))
    ShopkeeperMiniPriceSwitchButton:SetText(GetString(SK_SHOW_UNIT))
  end

	ShopkeeperWindowLoadingIcon.animation = ANIMATION_MANAGER:CreateTimelineFromVirtual("LoadIconAnimation", ShopkeeperWindowLoadingIcon)
	ShopkeeperMiniWindowLoadingIcon.animation = ANIMATION_MANAGER:CreateTimelineFromVirtual("LoadIconAnimation", ShopkeeperMiniWindowLoadingIcon)

  -- Refresh button
  ShopkeeperRefreshButton:SetText(GetString(SK_REFRESH_LABEL))
  ShopkeeperMiniRefreshButton:SetText(GetString(SK_REFRESH_LABEL))


  -- Reset button and confirmation dialog
  ShopkeeperResetButton:SetText(GetString(SK_RESET_LABEL))
  ShopkeeperMiniResetButton:SetText(GetString(SK_RESET_LABEL))
  local confirmDialog = {
    title = { text = GetString(SK_RESET_CONFIRM_TITLE) },
    mainText = { text = GetString(SK_RESET_CONFIRM_MAIN) },
    buttons = {
      {
        text = SI_DIALOG_ACCEPT,
        callback = function() self:DoReset() end
      },
      { text = SI_DIALOG_CANCEL }
    }
  }
  ZO_Dialogs_RegisterCustomDialog("ShopkeeperResetConfirmation", confirmDialog)

  -- Make the 15 rows that comprise the visible table
  if #self.DataRows == 0 then
    local dataRowOffsetX = 5
    local dataRowOffsetY = 74
    for i = 1, 15 do
      local dRow = CreateControlFromVirtual("ShopkeeperDataRow", ShopkeeperWindow, "ShopkeeperDataRow", i)
      dRow:SetSimpleAnchorParent(dataRowOffsetX, dataRowOffsetY+((dRow:GetHeight()+2)*(i-1)))
      self.DataRows[i] = dRow
    end
  end

  -- And 8 for the mini window
  if #self.MiniDataRows == 0 then
    local dataRowOffsetX = 10
    local dataRowOffsetY = 74
    for i = 1, 8 do
      local dRow = CreateControlFromVirtual("ShopkeeperMiniDataRow", ShopkeeperMiniWindow, "ShopkeeperMiniDataRow", i)
      dRow:SetSimpleAnchorParent(dataRowOffsetX, dataRowOffsetY+((dRow:GetHeight()+2)*(i-1)))
      self.MiniDataRows[i] = dRow
    end
  end

  -- Stats buttons
  ShopkeeperWindowStatsButton:SetHandler("OnMouseEnter", function(self)
    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_STATS_TOOLTIP))
  end)
  ShopkeeperMiniWindowStatsButton:SetHandler("OnMouseEnter", function(self)
    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_STATS_TOOLTIP))
  end)

  -- View size change buttons
  ShopkeeperWindowViewSizeButton:SetHandler("OnMouseEnter", function(self)
    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SIZE_TOOLTIP))
  end)
  ShopkeeperMiniWindowViewSizeButton:SetHandler("OnMouseEnter", function(self)
    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SIZE_TOOLTIP))
  end)

  -- Slider setup
  ShopkeeperWindow:SetHandler("OnMouseWheel", self.OnSliderMouseWheel)
  ShopkeeperWindowSlider:SetValue(0)
  ShopkeeperMiniWindow:SetHandler("OnMouseWheel", self.OnSliderMouseWheel)
  ShopkeeperMiniWindowSlider:SetValue(0)
  ShopkeeperStatsWindowSlider:SetValue(0)

  -- Search handler
  ZO_PreHookHandler(ShopkeeperWindowSearchBox, "OnTextChanged", function(self) Shopkeeper:DoSearch(ShopkeeperWindowSearchBox:GetText()) end)
  ZO_PreHookHandler(ShopkeeperMiniWindowSearchBox, "OnTextChanged", function(self) Shopkeeper:DoSearch(ShopkeeperMiniWindowSearchBox:GetText()) end)

  -- We're all set, so make sure we're using the right font and then update the UI
  self.windowFont = settingsToUse.windowFont
  self:UpdateFonts()
  self:DisplayRows()
end