---------------------------------
-- Configuration Preview Panel --
---------------------------------
local AddOnName, nsVars = ...
local ss = nsVars.SS

local CreateFrame, getglobal, tonumber, table = CreateFrame, getglobal, tonumber, table
local pairs, select, string, getmetatable = pairs, select, string, getmetatable
local type, next = type, next
local UIDropDownMenu_SetSelectedID, UIDropDownMenu_GetText, UIDropDownMenu_AddButton = UIDropDownMenu_SetSelectedID, UIDropDownMenu_GetText, UIDropDownMenu_AddButton
local UIDropDownMenu_SetText, CloseDropDownMenus, UIDropDownMenu_SetSelectedValue = UIDropDownMenu_SetText, CloseDropDownMenus, UIDropDownMenu_SetSelectedValue
local InterfaceOptionsFrame_OpenToCategory = InterfaceOptionsFrame_OpenToCategory
local ColorPickerFrame, OpacitySliderFrame = ColorPickerFrame, OpacitySliderFrame
local GetScreenHeight, GetScreenWidth = GetScreenHeight, GetScreenWidth


local targetSliderSetValue = function(self)
  if self:IsVisible() then
    local target = UIDropDownMenu_GetText(ss.ConfigPreview.SliderTargetDropDown)
    
    if target == "Animation - Scale" then
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setAnimationScale(self:GetValue())
    elseif target == "Animation - X Position" then
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setAnimationOffset(self:GetValue(), nil)
    elseif target == "Animation - Y Position" then
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setAnimationOffset(nil,self:GetValue())
    elseif target == "Animation - Strata (Z Pos)" then
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setAnimationStrata(self:GetValue() + ss.private.layout.config.frameLevelAdjust)
    elseif target == "Animation - Alpha" then
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setAnimationAlpha(self:GetValue())
    elseif target == "General - Pos X" then
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setPos(nil, self:GetValue(), nil, true)
    elseif target == "General - Pos Y" then
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setPos(nil, nil, self:GetValue(), true)
    elseif target == "General - Scale" then
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setScale(self:GetValue())
    elseif target == "Swirl - Speed" then
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setSwirlSpeed(self:GetValue())
    end
    
    if ss.ConfigPreview.SSTargetSliderEditBox then
      ss.ConfigPreview.SSTargetSliderEditBox:SetText(self:GetValue())
    end
    
    ss.ConfigPreview.ResetButton:Show()
    ss.ConfigPreview.CommitButton:Show()
  end
end

local targetSliderGetValue = function(target)
  if target == "Animation - Scale" then
    return ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getAnimationScale()
  elseif target == "Animation - X Position" then
    return ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getAnimationOffset()
  elseif target == "Animation - Y Position" then
    return select(2, ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getAnimationOffset())
  elseif target == "Animation - Strata (Z Pos)" then
    return ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getAnimationStrata() - ss.private.layout.config.frameLevelAdjust
  elseif target == "Animation - Alpha" then
    return ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getAnimationAlpha()
  elseif target == "General - Pos X" then
    local anch, x, y = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getPos(true)
    return x
  elseif target == "General - Pos Y" then
    local anch, x, y = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getPos(true)
    return y
  elseif target == "General - Scale" then
    return ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getScale()
  elseif target == "Swirl - Speed" then
    return ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlSpeed()
  else
    return 1
  end
end

local configTargets = {
  Swirl = {
    "Speed",
    "Color",
    "Color1",
    "Color2",
    "Color3",
  },
  Filling = {
    "Color",
  },
  Font1 = {
    "Color",
  },
  Font2 = {
    "Color",
  },
  Animation = {
    "Alpha",
    "Scale",
    "Strata (Z Pos)",
    "X Position",
    "Y Position",
  },
  General = {
    "Scale",
    "Pos X",
    "Pos Y",
  },
  ["Load Values"] = {},
};

local targetSliderValues = {
  Swirl = {
    ["Speed"] = {
      low  = 1,
      high = 10,
      step = 1,
    },
  },
  Animation = {
    ["Alpha"] = {
      low  = 0,
      high = 1,
      step = 0.001,
    },
    ["Scale"] = {
      low  = 0.001,
      high = 10,
      step = 0.001,
    },
    ["Strata (Z Pos)"] = {
      low  = 1,
      high = 5,
      step = 0.001,
    },
    ["X Position"] = {
      low  = -2,
      high = 2,
      step = 0.001,
    },
    ["Y Position"] = {
      low  = -2,
      high = 2,
      step = 0.001,
    },
  },
  General = {
    ["Scale"] = {
      low   = 50,
      high  = 150,
      step  = 1,
    },
    ["Pos Y"] = {
      low   = 0,
      high  = 1,
      step  = 1,
    },
    ["Pos X"] = {
      low   = 0,
      high  = 1,
      step  = 1,
    },
  },
};

local configTargetRun = function(target)
  -- Generic event handler for string targetted behavior.
  if string.match(target, "Load Values") then
    -- Get the name of the copy.
    local copyName = string.gsub(target, "(Load%sValues%s%-%s)", "")
    ss.ConfigPreview.loadCopy(copyName)
  end
end

local resetSliderDropdown = function()
  ColorPickerFrame.elementToChange = ""
  ss.ConfigPreview.SSTargetSlider:Hide()
  ss.ConfigPreview.colorFields   :Hide()
  ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:UpdateScale()
  ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:RefreshPos()
  
  UIDropDownMenu_SetText(ss.ConfigPreview.SliderTargetDropDown, "Configure Sphere")
end

local toggleFillTextureDropdown = function()
  -- Fix default value for fill texture dropdown
  if ss.ConfigPreview.FillTexturesDropDown and not ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillColor()[2] then
    local text = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillInfo()["fillId"]
    text = (text == 1) and ss.FillTextures.defaultId or text
  
    UIDropDownMenu_SetText(ss.ConfigPreview.FillTexturesDropDown, text)
    ss.ConfigPreview.FillTexturesDropDown      :Show()
    ss.ConfigPreview.FillTexturesDropDown.label:Show()
  else
    ss.ConfigPreview.FillTexturesDropDown      :Hide()
    ss.ConfigPreview.FillTexturesDropDown.label:Hide()
  end
end

local updateXMLText = function()
  local configName = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("configName")
  configName       = configName == "vehicle" and "health" or configName
  configName       = configName == "vehicleResource" and "mainResource" or configName
  
  if configName and ss.Layout.spheres[configName] then
    local text  = ss.Layout.spheres[configName]:getText()
    local text2 = ss.Layout.spheres[configName]:getText2()
    
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setText (text)
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setText2(text2)
  else
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setText ("")
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setText2("")
  end
end

local setTextFormatText = function(textFormat)
  if textFormat == "truncated" then
    textFormat = "Truncate Value"
  elseif textFormat == "commaSeparated" then
    textFormat = "Comma Separated Value"
  else
    textFormat = "Raw Value"
  end
  
  UIDropDownMenu_SetSelectedValue(ss.ConfigPreview.TextFormattingDropdown, textFormat)
  UIDropDownMenu_SetText         (ss.ConfigPreview.TextFormattingDropdown, textFormat)
end

local updateXMLTextures = function()
  local configName = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("configName")
  if ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillColor()[2] then
    configTargets.Filling = {
      "Color1",
      "Color2",
    };
  else
    configTargets.Filling = {
      "Color",
    };
  end
  
  targetSliderValues.General["Pos Y"].high = GetScreenHeight() - ss.global.general.SphereSize
  targetSliderValues.General["Pos X"].high = GetScreenWidth()  - ss.global.general.SphereSize
  configTargets["Copy Values"] = ss.ConfigPreview.copyMode
  
  -- set animation texture dropdown.
  if ss.ConfigPreview.RotationTexturesDropDown then
    UIDropDownMenu_SetText(ss.ConfigPreview.RotationTexturesDropDown, ss.db[configName].animation.id)
  end
  
  -- set swirl texture dropdown text
  if ss.ConfigPreview.SwirlTexturesDropDown then
    UIDropDownMenu_SetSelectedValue(ss.ConfigPreview.SwirlTexturesDropDown, ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlId())
    UIDropDownMenu_SetText         (ss.ConfigPreview.SwirlTexturesDropDown, ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlId())
  end
  
  -- Fix default value for fill texture dropdown
  toggleFillTextureDropdown()
  
  if ss.ConfigPreview.TextFormattingDropdown then
    --set the selected value appropriately
    local textFormat = ss.db[configName].textFormat
    setTextFormatText(textFormat)
  end
  
  ss.ConfigPreview.widgetFrame.SSSpherePercentageCheckBox:SetChecked(ss.db[ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("configName")].font[1].show)
  ss.ConfigPreview.widgetFrame.SSSphereValueCheckBox     :SetChecked(ss.db[ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("configName")].font[2].show)
end

local previewSphere = function(label, dbConfig)
  -- Reset unsaved scale change before changing resources.
  ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:UpdateScale()
  ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:RefreshPos()

  ss.ConfigPreview.dbConfig = dbConfig
  ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setResource(ss.db[dbConfig])
  ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setMode    (ss.db[dbConfig].modes[ss.profile.modeInfo[dbConfig].modeSpec].default)
  
  if ss.ConfigPreview.widgetFrame.AnimatePreviewCheckBox:GetChecked() == true then
    ss.ConfigPreview.widgetFrame.AnimatePreviewCheckBox:Click()
  end
  
  updateXMLTextures()
  updateXMLText()
  resetSliderDropdown()
  
  ss.ConfigPreview.widgetFrame.Title:SetText(label)
  ss.ConfigPreview.widgetFrame.Title:SetTextColor(ss.ConfigTools.titleColor.r, ss.ConfigTools.titleColor.g, ss.ConfigTools.titleColor.b, ss.ConfigTools.titleColor.a)
  
  UIDropDownMenu_SetSelectedValue(ss.ConfigPreview.ConfigSphereOptionsDropDown, "default")
  UIDropDownMenu_SetText         (ss.ConfigPreview.ConfigSphereOptionsDropDown, "default")
  ss.ConfigPreview.ResetButton:Hide()
  ss.ConfigPreview.CommitButton:Hide()
  ss.ConfigPreview.shouldReload = nil
end

local initPreviewOption = function()
  UIDropDownMenu_SetSelectedValue(ss.ConfigPreview.PreviewDropDown, "Health")
  UIDropDownMenu_SetText         (ss.ConfigPreview.PreviewDropDown, "Health")
  previewSphere("Health", "health")
end

local setColorSelectColors = function(r, g, b, a)
  local fillColor = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillColor()
  
  if ss.ConfigPreview.colorFields.elementToChange == "Filling" then
    fillColor[1] = {r=r,g=g,b=b,a=a}
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setFillColor(fillColor)
  elseif ss.ConfigPreview.colorFields.elementToChange == "Second Filling" then
    fillColor[2] = {r=r,g=g,b=b,a=a}
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setFillColor(fillColor)
  elseif ss.ConfigPreview.colorFields.elementToChange == "SwirlColor" then
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setSwirlColor({r=r,g=g,b=b,a=a})
  elseif ss.ConfigPreview.colorFields.elementToChange == "SwirlColor1" then
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setSwirlColor({r=r,g=g,b=b,a=a}, 1)
  elseif ss.ConfigPreview.colorFields.elementToChange == "SwirlColor2" then
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setSwirlColor({r=r,g=g,b=b,a=a}, 2)
  elseif ss.ConfigPreview.colorFields.elementToChange == "SwirlColor3" then
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setSwirlColor({r=r,g=g,b=b,a=a}, 3)
  elseif ss.ConfigPreview.colorFields.elementToChange == "Font1" then
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setTextColor({r=r,g=g,b=b,a=a})
  elseif ss.ConfigPreview.colorFields.elementToChange == "Font2" then
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setTextColor2({r=r,g=g,b=b,a=a})
  end
  
  ss.ConfigPreview.ResetButton:Show()
  ss.ConfigPreview.CommitButton:Show()
end

local showColorSelect = function(xmlElement)
  local r,g,b,a
  
  if xmlElement == "Filling" then
    local fillColor = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillColor()
    r,g,b,a         = ss:GetRGBAValues(fillColor[1])
    
    a = a or 1
  elseif xmlElement == "SwirlColor" then
    r,g,b,a = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlColor()
  elseif xmlElement == "SwirlColor1" then
    r,g,b,a = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlColor(1)
  elseif xmlElement == "SwirlColor2" then
    r,g,b,a = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlColor(2)
  elseif xmlElement == "SwirlColor3" then
    r,g,b,a = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlColor(3)
  elseif xmlElement == "Font1" then
    r,g,b,a = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getTextColor()
  elseif xmlElement == "Font2" then
    r,g,b,a = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getTextColor2()
  elseif xmlElement == "Second Filling" then
    local fillColor = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillColor()
    if fillColor[2] then
      r,g,b,a = ss:GetRGBAValues(fillColor[2])
    else
      r,g,b,a = ss:GetRGBAValues(fillColor[1])
    end
    
    a = a or 1
  end
  
  ss.ConfigPreview.colorFields:HookScript("OnColorSelect", function(self)
    setColorSelectColors(self:GetColorRGBA())
  end)
  
  ss.ConfigPreview.colorFields.elementToChange = xmlElement
  ss.ConfigPreview.colorFields:SetColorRGBA(r,g,b,a)
  ss.ConfigPreview.colorFields:Show()
end

local copyMode = function()
  local resourceName = UIDropDownMenu_GetText(ss.ConfigPreview.PreviewDropDown)
  local modeName     = UIDropDownMenu_GetText(ss.ConfigPreview.ConfigSphereOptionsDropDown)
  local copyName     = ss.profile.profileName..": "..ss.curSpecName.." - "..resourceName.." ("..modeName.." "..GetTime()..")"
  local anch, x, y   = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getPos(true)
  local r,g,b,a
  
  local swirlColor = {}
  r,g,b,a = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlColor(1)
  swirlColor[1] = {r=r,g=g,b=b,a=a}

  r,g,b,a = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlColor(2)
  swirlColor[2] = {r=r,g=g,b=b,a=a}

  r,g,b,a = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlColor(3)
  swirlColor[3] = {r=r,g=g,b=b,a=a }
  
  local fontColor = {}
  r,g,b,a = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getTextColor()
  fontColor[1] = {r=r,g=g,b=b,a=a}
  
  r,g,b,a = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getTextColor2()
  fontColor[2] = {r=r,g=g,b=b,a=a}

  -- Store a temporary copy of the values.
  local copy = {
    name       = copyName,
    mode       = {
      fillColor = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillColor(),
      swirlColor = swirlColor,
      fontColor = fontColor,
      fillInfo = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillInfo(),
      swirl = {
        id    = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlId(),
        speed = targetSliderGetValue("Swirl - Speed"),
      },
    },
    animation  = {
      posX        = targetSliderGetValue("Animation - X Position"),
      posY        = targetSliderGetValue("Animation - Y Position"),
      alpha       = targetSliderGetValue("Animation - Alpha"),
      camDistance = targetSliderGetValue("Animation - Scale"),
      frameLevel  = targetSliderGetValue("Animation - Strata (Z Pos)") + ss.private.layout.config.frameLevelAdjust,
      id          = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("animId"),
      groupId     = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("animGroup"),
    },
    font       = {
      [1] = {
        show = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("sphere").font1:IsVisible(),
      },
      [2] = {
        show = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("sphere").font2:IsVisible(),
      },
    },
    textFormat = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getTextFormat(),
    general    = {
      globalScale = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getScale(),
      posX        = y,
      posY        = x,
      anchor      = anch,
    },
  }
  
  if configTargets["Load Values"][copyName] then
    table.remove(configTargets["Load Values"], copyName)
  end
  
  ss:NewTemp(copyName, copy)

  -- Add an option to the "Load Values" target.
  table.insert(configTargets["Load Values"], copyName)
end

local loadCopy = function(copyName)
  local copy = ss:GetTemp(copyName)

  if copy and next(copy) ~= nil then
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:UpdateScale()
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:RefreshPos()
  
    -- Updated spheres values.
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setTextFormat(copy.textFormat)
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:showFont(1, copy.font[1].show)
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:showFont(2, copy.font[2].show)
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setAnimation(copy.animation)
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setSwirlTexture(copy.mode.swirl.id)
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setSwirlSpeed(copy.mode.swirl.speed)
--    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setScale(copy.general.globalScale)
--    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setPos(copy.general.anchor, copy.general.posX, copy.general.posY, true)
    
    -- Set sphere colors.
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setSwirlColor(copy.mode.swirlColor[1], 1)
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setSwirlColor(copy.mode.swirlColor[2] or copy.mode.swirlColor[1], 2)
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setSwirlColor(copy.mode.swirlColor[3] or copy.mode.swirlColor[1], 3)
    
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setTextColor(copy.mode.fontColor[1])
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setTextColor2(copy.mode.fontColor[2])
    
    local fillColor = table.copy(copy.mode.fillColor, true)
    
    if not ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillColor()[2] then
      -- Copying into single resource sphere.
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setFillTexture(copy.mode.fillInfo.fillGroup, copy.mode.fillInfo.fillId)
      fillColor[2] = nil
    elseif ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillColor()[2] then
      -- Copying into split resource sphere.
      fillColor[2] = fillColor[2] or ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillColor()[2]
    end
    
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setFillColor(fillColor)
    
    -- Update UI components.
    toggleFillTextureDropdown()
    updateXMLText()
    UIDropDownMenu_SetText(ss.ConfigPreview.RotationTexturesDropDown, copy.animation.id)
    UIDropDownMenu_SetSelectedValue(ss.ConfigPreview.SwirlTexturesDropDown, ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlId())
    UIDropDownMenu_SetText         (ss.ConfigPreview.SwirlTexturesDropDown, ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlId())
    setTextFormatText(copy.textFormat)
    ss.ConfigPreview.widgetFrame.SSSpherePercentageCheckBox:SetChecked(copy.font[1].show)
    ss.ConfigPreview.widgetFrame.SSSphereValueCheckBox     :SetChecked(copy.font[2].show)
  end
end

--- Resource emulation
local resourceMonitor

local emulateResource = function(emulate)
  resourceMonitor = resourceMonitor or ss.ResourceMonitor:New()
  local isDual = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillColor()[2]
  
  if emulate == true then
    resourceMonitor:Emulate(
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("sphere"),
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere.resourceUpdate,
      isDual)
  else
    resourceMonitor:EmulateFinish(ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("sphere"))
  end
end

ss["ConfigPreview"] = {
};

function ss:InitializeConfigPreviewPanel()
  -- Create the config preview frame
  ss.ConfigPreview = ss.Config:AddTab("Preview", initPreviewOption)

  ss.ConfigPreview:HookScript("OnShow", function(self)
    if self.shouldReload then
      initPreviewOption()
    end
  end)

  ss.ConfigPreview:HookScript("OnHide", function()
    if ss.ConfigPreview.widgetFrame.AnimatePreviewCheckBox:GetChecked() == true then
      -- Cancel running emulatio,
      ss.ConfigPreview.widgetFrame.AnimatePreviewCheckBox:Click()
    end
    
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:UpdateScale()
    ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:RefreshPos()
  end)
  
  ss.ConfigPreview.loadCopy = loadCopy
  ss.ConfigPreview.copyMode = copyMode

  ss.ConfigPreview.dbConfig = "health"
  
  -- Add the widget container
  ss.ConfigPreview.widgetFrame = ss.ConfigTools.getWidgetContainer(ss.ConfigPreview, "PreviewWidgetFrame")
  
  -- Add the title
  ss.ConfigPreview.widgetFrame.Title = ss.ConfigTools.createTitle("", ss.ConfigPreview.widgetFrame)
  
  -- Add preview sphere select dropdown
  ss.Config.previewSphereList      = {}
  ss.ConfigPreview.PreviewDropDown = ss.ConfigTools.createDropdown{
    name   = "ConfigPreviewDropDown",
    parent = ss.ConfigPreview,
    tAlign = "LEFT",
    width  = 125,
    height = 50,
    anchor = "TOPLEFT",
    x      = ss.ConfigTools.itemPadCorner + ss.ConfigTools.leftLabelMargin,
    y      = 5 - ss.ConfigTools.itemPadCorner,
    init   = function(self, level)
      local stuff = {}
      
      for k,v in ss.pairsByKeys(ss.Config.previewSphereList) do
        stuff                = {}
        stuff.text           = v[1]
        stuff.value          = v[1]
        
        stuff.func = function(self)
          if self:GetText() ~= "Select Sphere" then
            UIDropDownMenu_SetSelectedValue(ss.ConfigPreview.PreviewDropDown, self:GetText())
            UIDropDownMenu_SetText         (ss.ConfigPreview.PreviewDropDown, self:GetText())
            previewSphere(self:GetText(), k)
            CloseDropDownMenus()
          end
        end
        
        UIDropDownMenu_AddButton(stuff, level)
      end
    end,
    label = {
      name     = "PreviewSphereLabel",
      text     = "Preview Sphere",
      location = "left",
      color    = ss.ConfigTools.headerItemColor,
    },
  }
  
  -- Add the mode dropdown
  ss.ConfigPreview.ConfigSphereOptionsDropDown = ss.ConfigTools.createDropdown{
    name   = "ConfigSphereOptionsDropDown",
    parent = ss.ConfigPreview,
    tAlign = "LEFT",
    width  = 125,
    height = 50,
    anchor = "TOPLEFT",
    x      = ss.ConfigTools.itemPadCorner + ss.ConfigTools.leftLabelMargin,
    y      = 5 - ss.ConfigTools.itemPadCorner - ss.ConfigTools.itemHeight,
    init   = function(self, level)
      local stuff = {}
      
      for k,v in ss.pairsByKeys(ss.db[ss.ConfigPreview.dbConfig].modes[ss.profile.modeInfo[ss.ConfigPreview.dbConfig].modeSpec]) do
        if getmetatable(v) then
          -- Ensure that defaults are available.
          stuff       = {}
          stuff.text  = k
          stuff.value = k
          stuff.func  = function(self)
            -- Update fill texture dropdown.
            local text = (v.fillInfo.fillId == 1) and ss.FillTextures.defaultId or v.fillInfo.fillId
            UIDropDownMenu_SetText(ss.ConfigPreview.FillTexturesDropDown, text)
    
            UIDropDownMenu_SetSelectedID(ss.ConfigPreview.ConfigSphereOptionsDropDown, self:GetID())
            UIDropDownMenu_SetText      (ss.ConfigPreview.ConfigSphereOptionsDropDown, k)
            resetSliderDropdown()
    
            ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setMode(v)
            ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Set    ("modeId", k)
    
            UIDropDownMenu_SetSelectedValue(ss.ConfigPreview.SwirlTexturesDropDown, ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlId())
            UIDropDownMenu_SetText         (ss.ConfigPreview.SwirlTexturesDropDown, ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlId())
    
            -- Fix default value for fill texture dropdown
            toggleFillTextureDropdown()
    
            CloseDropDownMenus()
            ss.ConfigPreview.ResetButton:Hide()
            ss.ConfigPreview.CommitButton:Hide()
          end
          UIDropDownMenu_AddButton(stuff, level)
        end
      end
    end,
    label = {
      name     = "SphereModeLabel",
      text     = "Mode",
      location = "left",
      color    = ss.ConfigTools.headerItemColor,
    },
  }
  
  -- TextFormattingDropdown
  local fillOptions = {
    "Comma Separate Value",
    "Truncate Value",
    "Raw Value"
  }
  
  ss.ConfigPreview.TextFormattingDropdown = ss.ConfigTools.createDropdown{
    name   = "TextFormattingDropdown",
    parent = ss.ConfigPreview,
    tAlign = "LEFT",
    width  = 150,
    height = 45,
    anchor = "TOPLEFT",
    x      = 0,
    y      = ss.ConfigTools.topMargin - ss.ConfigTools.itemHeight,
    init   = function(self, level)
      local stuff = {}
      
      for k,v in pairs(fillOptions) do
        stuff       = {}
        stuff.text  = v
        stuff.value = v
        stuff.func  = function(self)
          UIDropDownMenu_SetSelectedID(ss.ConfigPreview.TextFormattingDropdown, self:GetID())
          UIDropDownMenu_SetText      (ss.ConfigPreview.TextFormattingDropdown, self:GetText())
          
          if self:GetText() == "Truncate Value" then
            ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setTextFormat("truncated")
          elseif self:GetText() == "Comma Separate Value" then
            ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setTextFormat("commaSeparated")
          elseif self:GetText() == "Raw Value" then
            ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setTextFormat("raw")
          end
          
          updateXMLText()
          CloseDropDownMenus()
          ss.ConfigPreview.ResetButton:Show()
          ss.ConfigPreview.CommitButton:Show()
        end
        UIDropDownMenu_AddButton(stuff, level)
      end
    end,
    label = {
      name     = "TextFormattingDropdownLabel",
      text     = "Text Format",
      location = "top",
    },
  }
  
  -- Add the show percentage checkbox.
  ss.ConfigPreview.widgetFrame.SSSpherePercentageCheckBox = ss.ConfigTools.createCheckbox{
    name    = "SS32SpherePercentageCheckBox",
    parent  = ss.ConfigPreview.widgetFrame,
    anch    = "TOPLEFT",
    x       = 22,
    y       = ss.ConfigTools.topMargin - (ss.ConfigTools.itemHeight * 2),
    text    = "Show Percentage",
    onClick = function(self)
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:showFont(1, self:GetChecked())
      ss.ConfigPreview.ResetButton:Show()
      ss.ConfigPreview.CommitButton:Show()
    end,
  }
  
  -- Add the show value checkbox.
  ss.ConfigPreview.widgetFrame.SSSphereValueCheckBox = ss.ConfigTools.createCheckbox{
    name    = "SS32SphereValueCheckBox",
    parent  = ss.ConfigPreview.widgetFrame,
    anch    = "TOPLEFT",
    x       = 22,
    y       = ss.ConfigTools.topMargin - (ss.ConfigTools.itemHeight * 3),
    text    = "Show Value",
    onClick = function(self)
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:showFont(2, self:GetChecked())
      ss.ConfigPreview.ResetButton:Show()
      ss.ConfigPreview.CommitButton:Show()
    end,
  }
  
  -- Add the Animate Preview checkbox.
  ss.ConfigPreview.widgetFrame.AnimatePreviewCheckBox = ss.ConfigTools.createCheckbox{
    name    = "AnimatePreviewCheckBox",
    parent  = ss.ConfigPreview.widgetFrame,
    anch    = "TOPRIGHT",
    x       = -125,
    y       = ss.ConfigTools.topMargin - (ss.ConfigTools.itemHeight * 2),
    text    = "Animate Preview",
    onClick = function(self)
      emulateResource(self:GetChecked())
    end,
  }
  
  -- Add the preview sphere
  ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2 = CreateFrame("Frame", ss._f.."cfg_preview_sphere", ss.ConfigPreview.widgetFrame)
  ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2:SetPoint("TOP",0,(ss.ConfigTools.topMargin-45))
  ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2:SetSize (ss.private.general.SphereSize, ss.private.general.SphereSize)
  
  -- Initialize the sphere
  ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere = ss.Sphere:New()
  ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:initialize(ss.db.health,ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2,"preview")
  ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2       :SetScale  (1.5)
  
  -- Background textures
  local textureNameTable = ss.FillTextures.listAll()
  
  ss.ConfigPreview.FillTexturesDropDown = ss.ConfigTools.createDropdown{
    name   = "FillTexturesDropDown",
    parent = ss.ConfigPreview,
    tAlign = "LEFT",
    width  = 100,
    height = 45,
    anchor = "BOTTOMLEFT",
    x      = 0,
    y      = 15,
    init   = function(self, level, menuList)
      local stuff = {}
      
      if level == 1 then
        for k,v in ss.pairsByKeys(textureNameTable) do
          local text = (k == "split") and ss.FillTextures.defaultGroup or k
          stuff.text     = text
          stuff.menuList = text
          stuff.hasArrow = true
          stuff.checked  = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillInfo()["fillGroup"] == text
          
          UIDropDownMenu_AddButton(stuff, level)
        end
      elseif level == 2 then
        for k,v in ss.pairsByKeys(textureNameTable[menuList]) do
          local text = (k == 1) and ss.FillTextures.defaultId or k
          stuff.text    = text
          stuff.value   = text
          stuff.checked = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getFillInfo()["fillId"] == text
          stuff.func    = function(self)
            UIDropDownMenu_SetText(ss.ConfigPreview.FillTexturesDropDown, self:GetText())
            ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setFillTexture(menuList, self:GetText())
            CloseDropDownMenus()
            ss.ConfigPreview.ResetButton:Show()
            ss.ConfigPreview.CommitButton:Show()
          end
          
          UIDropDownMenu_AddButton(stuff, level)
        end
      end
    end,
    label = {
      name     = "FillTextureLabel",
      text     = "Background",
      location = "top",
    },
  };
  
  -- Animations
  local animationNameTable = ss.Animations.list()
  ss.ConfigPreview.RotationTexturesDropDown = ss.ConfigTools.createDropdown{
    name   = "RotationTexturesDropDown",
    parent = ss.ConfigPreview,
    tAlign = "LEFT",
    width  = 100,
    height = 45,
    anchor = "BOTTOMLEFT",
    x      = 150,
    y      = 15,
    init   = function(self, level, menuList)
      local stuff = {};
      
      if level == 1 then
        for k,v in ss.pairsByKeys(animationNameTable) do
          stuff.text     = k
          stuff.menuList = k
          stuff.hasArrow = true
          stuff.checked  = (ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("animGroup") == k)
          UIDropDownMenu_AddButton(stuff, level)
        end
      elseif level == 2 then
        for k,v in ss.pairsByKeys(animationNameTable[menuList]) do
          stuff.text    = k
          stuff.value   = k
          stuff.checked = (ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("animId") == k)
          stuff.func    = function(self)
            UIDropDownMenu_SetText(ss.ConfigPreview.RotationTexturesDropDown, self:GetText())
            ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setAnimationDisplayInfo(ss.ConfigPreview.RotationTexturesDropDown.menuList,self:GetText())
            CloseDropDownMenus()
            ss.ConfigPreview.ResetButton:Show()
            ss.ConfigPreview.CommitButton:Show()
          end
          
          UIDropDownMenu_AddButton(stuff, level)
        end
      end
    end,
    label = {
      name     = "SphereTextureLabel",
      text     = "Animation",
      location = "top",
    },
  };
  
  -- Swirl textures
  local swirlTextureNameTable = ss.FillTextures.list("swirl")
  ss.ConfigPreview.SwirlTexturesDropDown = ss.ConfigTools.createDropdown{
    name   = "SwirlTexturesDropDown",
    parent = ss.ConfigPreview,
    tAlign = "LEFT",
    width  = 100,
    height = 45,
    anchor = "BOTTOMLEFT",
    x      = 300,
    y      = 15,
    init   = function(self, level)
      local stuff = {}
      for k,v in ss.pairsByKeys(swirlTextureNameTable) do
        stuff         = {}
        stuff.text    = k
        stuff.value   = k
        stuff.checked = (ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:getSwirlId() == k)
        stuff.func    = function(self)
          UIDropDownMenu_SetSelectedID(ss.ConfigPreview.SwirlTexturesDropDown, self:GetID())
          UIDropDownMenu_SetText      (ss.ConfigPreview.SwirlTexturesDropDown, self:GetText())
          ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:setSwirlTexture(k)
          CloseDropDownMenus()
          ss.ConfigPreview.ResetButton:Show()
          ss.ConfigPreview.CommitButton:Show()
        end
        UIDropDownMenu_AddButton(stuff, level)
      end
    end,
    label = {
      name     = "SwirlTextureLabel",
      text     = "Swirl",
      location = "top",
    },
  };
  
  -- Display the "slider target" dropdown to determine which value the slider should manage
  ss.ConfigPreview.SliderTargetDropDown = ss.ConfigTools.createDropdown{
    name   = "SliderTargetDropDown",
    parent = ss.ConfigPreview,
    tAlign = "LEFT",
    width  = 175,
    height = 45,
    anchor = "BOTTOMLEFT",
    x      = 0,
    y      = 112,
    init   = function(self, level, menuList)
      local skip
      local stuff = {};
      stuff.notCheckable = true
      
      if level == 1 then
        for k,v in ss.pairsByKeys(configTargets) do
          stuff.text     = k
        
          if type(v) == "table" then
            if next(v) ~= nil then
              stuff.menuList = k
              stuff.hasArrow = true
              stuff.func = nil
            else
              stuff.text = nil
              skip = true
            end
          elseif type(v) == "function" then
            stuff.func = v
            stuff.menuList = nil
            stuff.hasArrow = false
          end
          
          if not skip then
            UIDropDownMenu_AddButton(stuff, level)
          end
          
          skip = nil
        end
      elseif level == 2 then
        for k,v in ss.pairsByKeys(configTargets[menuList]) do
          stuff.text  = v
          stuff.value = menuList
          stuff.func  = function(self)
            if string.match(self:GetText(), "Color") then
              ss.ConfigPreview.SSTargetSlider:Hide()
              local target = self.value .. " - " .. self:GetText()
              
              UIDropDownMenu_SetSelectedID(ss.ConfigPreview.SliderTargetDropDown, self:GetID())
              UIDropDownMenu_SetText      (ss.ConfigPreview.SliderTargetDropDown, target)
              
              if self.value == "Filling" then
                showColorSelect((self:GetText() == "Color2") and "Second Filling" or self.value)
              elseif self.value == "Swirl" then
                showColorSelect(self.value..self:GetText())
              else
                showColorSelect(self.value)
              end
            elseif targetSliderValues[self.value] and targetSliderValues[self.value][self:GetText()] then
              ss.ConfigPreview.colorFields:Hide()
              ss.ConfigPreview.SSTargetSlider:Hide()
              local target     = self.value .. " - " .. self:GetText()
              local sliderVals = targetSliderValues[self.value][self:GetText()]
              
              UIDropDownMenu_SetSelectedID(ss.ConfigPreview.SliderTargetDropDown, self:GetID())
              UIDropDownMenu_SetText      (ss.ConfigPreview.SliderTargetDropDown, target)
              
              getglobal(ss.ConfigPreview.SSTargetSlider:GetName().."High"):SetText(sliderVals.high)
              getglobal(ss.ConfigPreview.SSTargetSlider:GetName().."Low") :SetText(sliderVals.low)
              
              ss.ConfigPreview.SSTargetSlider:SetMinMaxValues(sliderVals.low,sliderVals.high)
              ss.ConfigPreview.SSTargetSlider:SetValueStep   (sliderVals.step)
  
              ss.ConfigPreview.SSTargetSlider:Show()
              ss.ConfigPreview.SSTargetSlider:SetValue(targetSliderGetValue(target))
            else
              -- Run generic event handler.
              configTargetRun(self.value.." - "..self:GetText())
            end
  
            ss.ConfigPreview.ResetButton:Show()
            ss.ConfigPreview.CommitButton:Show()
            CloseDropDownMenus()
          end
          
          UIDropDownMenu_AddButton(stuff, level)
        end
      end
    end,
    label = {
      name     = "SliderTargetLabel",
      text     = "Customize",
      location = "top",
    },
  };
  
  ss.ConfigPreview.SSTargetSlider, ss.ConfigPreview.SSTargetSliderEditBox = ss.ConfigTools.createSliderField({
    name      = "SSTargetSlider",
    parent    = ss.ConfigPreview,
    len       = 275,
    heigt     = 16,
    anchor    = "BOTTOMLEFT",
    x         = 25,
    y         = 90,
    onChanged = targetSliderSetValue,
  },{
    maxLetters     = 5,
    onEnterPressed = function(self)
      local val = self:GetText()
      if tonumber(val) then
        self:GetParent() :SetValue(val)
        self:SetText(self:GetParent():GetValue())
        self:ClearFocus()
      end
    end,
  });
  
  ss.ConfigPreview.SSTargetSlider:Hide()
  
  -- Add the color picker
  ss.ConfigPreview.colorFields = ss.ConfigTools.createColorPicker{
    parent        = ss.ConfigPreview,
    anch          = "BOTTOMRIGHT",
    x             = -25,
    y             = 75,
  }
  
  -- Add the reset button
  ss.ConfigPreview.ResetButton =  ss.ConfigTools.createButton{
    parent  = ss.ConfigPreview,
    name    = "PreviewResetButton",
    anch    = "BOTTOMRIGHT",
    x       = -15,
    y       = 15 + ss.ConfigTools.itemHeight,
    text    = "Undo Changes",
    onClick = function(self)
      previewSphere(ss.ConfigPreview.widgetFrame.Title:GetText(), ss.ConfigPreview.dbConfig)
      self:Hide()
      ss.ConfigPreview.CommitButton:Hide()
    end,
  }
  
  -- Add the save button
  ss.ConfigPreview.CommitButton =  ss.ConfigTools.createButton{
    parent  = ss.ConfigPreview,
    name    = "PreviewCommitButton",
    anch    = "BOTTOMRIGHT",
    x       = -15,
    y       = 15,
    text    = "Save Changes",
    onClick = function(self)
      ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:dbUpdate()
      
      local configName = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("configName")
      local dbConfig   = ss.ConfigPreview.widgetFrame.xmlSphereDisplayFrame2.sphere:Get("configName")
      configName       = (configName == "vehicle")         and "health" or configName
      configName       = (configName == "vehicleResource") and "mainResource" or configName
      
      if ss.Layout.spheres[configName] and (UnitInVehicle("player") or (not UnitInVehicle("player") and dbConfig ~= "vehicle" and dbConfig ~= "vehicleResource")) then
        ss.Layout.spheres[configName]:setResource(ss.db[dbConfig])
      end
      
      self:Hide()
      ss.ConfigPreview.ResetButton:Hide()
    end,
  }
end
