----------------------------
-- Sphere Filling Creator --
----------------------------
local addon, ns = ...
local ss = ns.SS

local setmetatable = setmetatable
local math = math

local mtFilling = {
  createGradient = function(gradient)
    local grad = gradient.parent:CreateTexture(nil, "BACKGROUND")
    grad:SetTexture    (gradient.texture)
    grad:SetPoint      (gradient.anch,gradient.x,gradient.y)
    grad:SetWidth      (gradient.width)
    grad:SetHeight     (gradient.height)
    grad:SetAlpha      (1)
    grad:SetVertexColor(ss:GetRGBAValues(gradient.color))

    local r,g,b = ss:GetRGBAValues(gradient.color)
    grad:SetGradientAlpha("VERTICAL",r,g,b,0,r,g,b,0)

    if not InCombatLockdown() then
      grad:Show()
    end

    return grad
  end,
  createFillGradient = function(parent, filling, size)
    local gradient =  ss.FillingCreator.createGradient{
      parent  = parent,
      texture = filling:GetTexture(),
      anch    = "BOTTOM",
      x       = 0,
      y       = size * -0.05,
      width   = size * 1.086,
      height  = size * 1.086,
      color   = {filling:GetVertexColor()},
    }

    function filling:UpdateGradient(targetHeight, maxHeight, displayPercent, color, maxAlpha)
      ss.FillingCreator.updateSingleGradient(ss.FillingCreator.updateGradient(self, targetHeight, maxHeight, displayPercent, color, maxAlpha))
    end

    return gradient
  end,
  createSplitGradients = function(parent, fillingLeft, fillingRight, size)
    local leftGradient = ss.FillingCreator.createGradient{
      parent  = parent,
      texture = fillingLeft:GetTexture(),
      anch    = "BOTTOM",
      x       = -size/4 + 0.60,
      y       = size * 0.02,
      width   = (size * 0.9) / 2,
      height  = size * 0.95,
      color   = {fillingLeft:GetVertexColor()},
    }

    local rightGradient = ss.FillingCreator.createGradient{
      parent  = parent,
      texture = fillingRight:GetTexture(),
      anch    = "BOTTOM",
      x       = size/4 - 0.60,
      y       = size * 0.02,
      width   = (size * 0.95) / 2,
      height  = size * 0.95,
      color   = {fillingRight:GetVertexColor()},
    }

    function fillingLeft:UpdateGradient(targetHeight, maxHeight, displayPercent, color, maxAlpha)
      ss.FillingCreator.updateLeftGradient(ss.FillingCreator.updateGradient(self, targetHeight, maxHeight, displayPercent, color, maxAlpha))
    end

    function fillingRight:UpdateGradient(targetHeight, maxHeight, displayPercent, color, maxAlpha)
      ss.FillingCreator.updateRightGradient(ss.FillingCreator.updateGradient(self, targetHeight, maxHeight, displayPercent, color, maxAlpha))
    end

    return leftGradient, rightGradient
  end,
  updateGradient = function(self, targetHeight, maxHeight, displayPercent, color, maxAlpha)
    if self and ss.global.show.gradient then
      if color and maxAlpha and self.gradient then
        local r,g,b = ss:GetRGBAValues(color)

        self.gradient:SetGradientAlpha("VERTICAL",r,g,b,maxAlpha,r,g,b,0)
      end

      local textCoordTop = (displayPercent - ss.gradientScale)
      local newHeight    = targetHeight - (maxHeight * ss.gradientScale)
      textCoordTop = textCoordTop < 0 and 0 or textCoordTop

      if displayPercent < 0 then
        displayPercent = 0
      end

      newHeight = newHeight < 1 and 1 or newHeight

      self:SetHeight  (newHeight)
      self:SetTexCoord(0,1,math.abs(textCoordTop - 1),1)

      local gradientTextCoordBottom = 1 - (displayPercent - ss.gradientScale)
      local gradientTextCoordTop    = displayPercent
      local gradientHeight          = maxHeight * ss.gradientScale

      gradientTextCoordBottom = gradientTextCoordBottom < 0 and 0 or gradientTextCoordBottom
      gradientTextCoordBottom = gradientTextCoordBottom > 1 and 1 or gradientTextCoordBottom

      local newY = (maxHeight * (1 - gradientTextCoordBottom)) - (maxHeight * ss.gradientScale)

      return self, gradientHeight, gradientTextCoordTop, gradientTextCoordBottom, newY, textCoordTop, newHeight, maxHeight
    end
  end,
  updateSingleGradient = function(self, gradientHeight, gradientTextCoordTop, gradientTextCoordBottom, newY)
    if self and ss.global.show.gradient then
      self.gradient:SetHeight  (gradientHeight)
      self.gradient:SetTexCoord(0, 1, math.abs(gradientTextCoordTop - 1), math.abs(gradientTextCoordBottom))
      self.gradient:SetPoint   ("BOTTOM", 0, newY)
    end
  end,
  updateLeftGradient = function(self, gradientHeight, gradientTextCoordTop, gradientTextCoordBottom, newY, textCoordTop, newHeight, maxHeight)
    if self and ss.global.show.gradient then
      gradientTextCoordTop = gradientTextCoordTop + ss.gradientScale
      gradientTextCoordBottom = gradientTextCoordBottom - ss.gradientScale

      if gradientTextCoordTop > 1 then
        textCoordTop = textCoordTop + gradientTextCoordTop - 1
        newHeight = newHeight + newHeight * (gradientTextCoordTop - 1)
        gradientTextCoordTop = 1
      end

      if (textCoordTop - ss.gradientScale) < 0 then
        gradientTextCoordBottom = gradientTextCoordBottom - (textCoordTop - ss.gradientScale)
        gradientTextCoordTop = gradientTextCoordTop + (textCoordTop - ss.gradientScale)
      end

      self:SetHeight  (newHeight)
      self:SetTexCoord(0,1,math.abs(textCoordTop - 1),1)

      newY = newY + (maxHeight * 0.07)
      self.gradientLeft:SetHeight  (gradientHeight)
      self.gradientLeft:SetTexCoord(0, 1, math.abs(gradientTextCoordTop - 1), math.abs(gradientTextCoordBottom))
      self.gradientLeft:SetPoint   ("BOTTOM", -maxHeight/4 + 0.60, newY)
    end
  end,
  updateRightGradient = function(self, gradientHeight, gradientTextCoordTop, gradientTextCoordBottom, newY, textCoordTop, newHeight, maxHeight)
    if self and ss.global.show.gradient then
      gradientTextCoordTop = gradientTextCoordTop + ss.gradientScale

      if gradientTextCoordTop > 1 then
        textCoordTop = textCoordTop + gradientTextCoordTop - 1
        gradientTextCoordBottom = gradientTextCoordBottom - (gradientTextCoordTop - 1)
        newHeight = newHeight + newHeight * (gradientTextCoordTop - 1)
        gradientTextCoordTop = 1
      end

      if (textCoordTop - ss.gradientScale) < 0 then
        gradientTextCoordTop = gradientTextCoordTop + (textCoordTop - ss.gradientScale)
      end

      self:SetHeight  (newHeight)
      self:SetTexCoord(0,1,math.abs(textCoordTop - 1),1)

      newY = newY + (maxHeight * 0.07)
      self.gradientRight:SetHeight  (gradientHeight)
      self.gradientRight:SetTexCoord(0, 1, math.abs(gradientTextCoordTop - 1), math.abs(gradientTextCoordBottom))
      self.gradientRight:SetPoint   ("BOTTOM", maxHeight/4 - 0.60, newY)
    end
  end,
};

function mtFilling:New(parent, size, displayMode, c, t, t2, c2)
  size = (displayMode and displayMode == "preview") and 150 or size

  if c2 then
    if not t2 then
      local split = ss.FillTextures.get("split", 1)
      t, t2 = split[1], split[2]
    end

    local fillingLeft = parent:CreateTexture(nil, "BACKGROUND")
    fillingLeft:SetTexture    (t)
    fillingLeft:SetPoint      ("BOTTOM", -size/4 + 0.70, size * 0.02)
    fillingLeft:SetWidth      ((size * 0.95) / 2)
    fillingLeft:SetHeight     (size * 0.95)
    fillingLeft:SetAlpha      (1)
    fillingLeft:SetVertexColor(ss:GetRGBAValues(c))

    local fillingRight = parent:CreateTexture(nil, "BACKGROUND")
    fillingRight:SetTexture    (t2)
    fillingRight:SetPoint      ("BOTTOM", size/4 - 0.70, size * 0.02)
    fillingRight:SetWidth      ((size * 0.95) / 2)
    fillingRight:SetHeight     (size * 0.95)
    fillingRight:SetAlpha      (1)
    fillingRight:SetVertexColor(ss:GetRGBAValues(c2))

    if ss.global.show.gradient and displayMode ~= "preview" then
      fillingLeft.gradientLeft, fillingRight.gradientRight = self.createSplitGradients(parent, fillingLeft, fillingRight, size)
    end

    return fillingLeft, fillingRight
  else
    if t2 then
      t = ss.FillTextures.get("primary", "moon")
    end

    local filling = parent:CreateTexture(nil, "BACKGROUND")
    filling:SetTexture    (t)
    filling:SetPoint      ("BOTTOM",0,size * -0.05)
    filling:SetWidth      (size * 1.086)
    filling:SetHeight     (size * 1.086)
    filling:SetAlpha      (1)
    filling:SetVertexColor(ss:GetRGBAValues(c))

    if ss.global.show.gradient and displayMode ~= "preview" then
      filling.gradient = self.createFillGradient(parent, filling, size)
    end

    return filling
  end
end

ss["FillingCreator"] = setmetatable({}, { __index = mtFilling });
