-----------------------------------------------------
-- Layout Container for SeamoreSpheres unit frames --
-----------------------------------------------------
local addon, nsVars = ...
local ss = nsVars.SS

local setmetatable = setmetatable
local CreateFrame, UIParent, pairs = CreateFrame, UIParent, pairs
local strlower, select, table = strlower, select, table
local GetShapeshiftFormID = GetShapeshiftFormID

local mtLayout = {
  spheres = {},
  artwork = {},
};

function mtLayout:AddArtwork(texture,sphere,name,offsetX,offsetY,height,width)
  local art = CreateFrame("Frame",ss._f..name,sphere)
  art:SetPoint      ("CENTER",offsetX,offsetY)
  art:SetHeight     (height)
  art:SetWidth      (width)
  art:SetFrameStrata("MEDIUM")
  art:SetFrameLevel (9)
  art.texture = art:CreateTexture(nil,"OVERLAY")
  art.texture:SetTexture  (texture)
  art.texture:SetAllPoints(art)

  return art
end

function mtLayout:AddMicroSpheres(sphere)
  sphere = sphere or "health"
  self.spheres[sphere]:toggleResourceGroup         (false)
  self.spheres[sphere]:toggleSecondaryResourceGroup(false)
  local microResource = (sphere == "mainResource") and ss.profile.microResourcesSecondary or ss.profile.microResources

  if ss.curClass == "druid" then
    if microResource and microResource[strlower(ss.curSpecName)] then
      for k,v in pairs(microResource[strlower(ss.curSpecName)]) do
        if ss.curShapeshift and (k == ss.curShapeshift) then
          self.spheres[sphere]:AddResourceGroup(v, (sphere == "mainResource") and "secondary" or nil)
          break
        end
      end
    end
  else
    if microResource then
      for k,v in pairs(microResource) do
        if k == strlower(ss.curSpecName) then
          self.spheres[sphere]:AddResourceGroup(v, (sphere == "mainResource") and "secondary" or nil)
          break
        end
      end
    end
  end

  self:ToggleMicroSpheres(sphere)
end

function mtLayout:CheckConfig()
  if ss.Config:IsVisible() then
    ss:ToggleConfig()
  end
end

function mtLayout:EndCombat()
  if self.inCombat then
    if ss.global.track.combat then
      for k,v in pairs(self.spheres) do
        local configName = v:Get("configName")

        if ss.db[configName].modes[ss.profile.modeInfo[configName].modeSpec] and v:Get("prevMode") then
          if (configName ~= "pet") and (configName == "health" or ss.curClass ~= "druid") then
            v:setMode(ss.db[configName].modes[ss.profile.modeInfo[configName].modeSpec][ss.profile.modeInfo[configName].mode]);
          end
        end
      end
    end

    self.inCombat = nil
  end
end

function mtLayout:InCombat()
  return self.inCombat
end

function mtLayout:Initialize()
  ss:InitializeConfigPanel()

  self.spheres.health = ss.Sphere:New()
  self.spheres.health:initialize(ss.db.health, UIParent, "active")
  self:AddMicroSpheres()

  ss.Config.previewSphereList.health  = {"Health", "Health"}
  ss.Config.previewSphereList.vehicle = {"Vehicle", "Vehicle"}

  -- Create main resource sphere
  self.spheres.mainResource = ss.Sphere:New()
  self.spheres.mainResource:initialize(ss.db.mainResource,UIParent,"active")
  self:AddMicroSpheres("mainResource")

  ss.Config.previewSphereList.mainResource    = {"Main Resource", "MainResource"}
  ss.Config.previewSphereList.vehicleResource = {"Vehicle Resource", "VehicleResource"}

  self:TrackAdditionalResource(ss.global.track.additionalResource and ss.ClassResources.hasSecondaryResource())
  self:ShowArtwork            (ss.global.show.artwork)

  if ss.curClass == "druid" then
    self:Shapeshift(ss.shapeshiftToString(GetShapeshiftFormID() or 0))
  elseif (ss.curClass == "hunter") or (ss.curClass == "warlock") or (ss.curClass == "mage") then
    self:TrackPet(true)
    self:TrackPet(false)
  end
end

function mtLayout:OnPetBattleStart()
  if ss.global.track.petBattles then
    for k,v in pairs(self.spheres) do
      v:Hide()
    end
  end
end

function mtLayout:OnPetBattleEnd()
  if ss.global.track.petBattles then
    for k,v in pairs(self.spheres) do
      v:Show()
    end
  end
end

function mtLayout:OnPlayerEnteredVehicle()
  if not self.inVehicle then
    self.spheres["health"]      :setResource(ss.db["vehicle"])
    self.spheres["mainResource"]:setResource(ss.db["vehicleResource"])

    if self.inCombat then
      self.spheres["health"]:setMode(ss.db["vehicle"].modes[ss.profile.modeInfo["vehicle"].modeSpec]["combat"]);

      if ss.curClass ~= "druid" then
        self.spheres["mainResource"]:setMode(ss.db["vehicleResource"].modes[ss.profile.modeInfo["vehicleResource"].modeSpec]["combat"]);
      end
    end

    self.inVehicle = true
  end
end

function mtLayout:OnPlayerExitedVehicle()
  if self.inVehicle then
    self.spheres["health"]      :setResource(ss.db["health"])
    self.spheres["mainResource"]:setResource(ss.db["mainResource"])

    if self.inCombat then
      self.spheres["health"]:setMode(ss.db["health"].modes[ss.profile.modeInfo["health"].modeSpec]["combat"]);

      if ss.curClass ~= "druid" then
        self.spheres["mainResource"]:setMode(ss.db["mainResource"].modes[ss.profile.modeInfo["mainResource"].modeSpec]["combat"]);
      end
    end

    self.inVehicle = nil
  end
end

function mtLayout:OnSpecializationChanged()
  self:Refresh()
  self:AddMicroSpheres()
  self:AddMicroSpheres("mainResource")
end

function mtLayout:OnUnitMaxPowerChanged()
  self:AddMicroSpheres()
  self:AddMicroSpheres("mainResource")
end

function mtLayout:ShowArtwork(show)
  if show then
    self.healthArtwork       = self.healthArtwork       or self:AddArtwork(ss.private.textures.healthArtwork,       self.spheres.health      :Get("sphere"), "HealthArtwork",      -90, 5, 160, 160)
    self.mainResourceArtwork = self.mainResourceArtwork or self:AddArtwork(ss.private.textures.mainResourceArtwork, self.spheres.mainResource:Get("sphere"), "MainResourceArtwork",70,  5, 160, 160)

    self.healthArtwork      :Show()
    self.mainResourceArtwork:Show()
  else
    if self.healthArtwork       then self.healthArtwork      :Hide() end
    if self.mainResourceArtwork then self.mainResourceArtwork:Hide() end
  end
end

function mtLayout:ShowGradients(show)
  for k,v in pairs(self.spheres) do
    if show then
      v:showGradients()
    else
      v:hideGradients()
    end
  end

  ss.global.show.gradient  = show
end

function mtLayout:TrackAdditionalResource(track)
  if track and not self.spheres.additionalResource then
    self.spheres.additionalResource = ss.Sphere:New()
    self.spheres.additionalResource:initialize(ss.db.additionalResource,UIParent,"active")
    ss.Config.previewSphereList.additionalResource = {"Additional Resource", "AdditionalResource"}
  elseif track and self.spheres.additionalResource then
    self.spheres.additionalResource:setResource(ss.db.additionalResource)
    self.spheres.additionalResource:show       (true)
    ss.Config.previewSphereList.additionalResource = {"Additional Resource", "AdditionalResource"}
  elseif not track and self.spheres.additionalResource then
    self.spheres.additionalResource:show(false)
    ss.Config.previewSphereList.additionalResource = nil
  end
end

function mtLayout:ToggleMicroSpheres(sphere)
  sphere              = sphere or "health"
  local microResource = (sphere == "mainResource") and ss.profile.microResourcesSecondary or ss.profile.microResources

  if microResource then
    microResource = microResource[strlower(ss.curSpecName)]

    if ss.curClass == "druid" and microResource then
      microResource = microResource[ss.curShapeshift]
    end
  end

  if microResource then
    if (not microResource.getMinMax) and (not microResource.buffGroup) then
      if microResource[1].buffGroup then
        self.spheres[sphere]:toggleResourceGroup(microResource[1])
      elseif microResource[1].getMinMax then
        self.spheres[sphere]:toggleResourceGroup(select(2, microResource[1].getMinMax(microResource[1][1])))
      else
        self.spheres[sphere]:toggleResourceGroup(false)
      end

      if microResource[2].buffGroup then
        self.spheres[sphere]:toggleSecondaryResourceGroup(microResource[2])
      elseif microResource[2].getMinMax then
        self.spheres[sphere]:toggleSecondaryResourceGroup(select(2, microResource[2].getMinMax(microResource[2][1])))
      else
        self.spheres[sphere]:toggleSecondaryResourceGroup(false)
      end
    elseif microResource.buffGroup then
      -- depricated
      self.spheres[sphere]:toggleResourceGroup         (microResource)
      self.spheres[sphere]:toggleSecondaryResourceGroup(false)
    elseif microResource.getMinMax then
      -- depricated
      self.spheres[sphere]:toggleResourceGroup         (select(2, microResource.getMinMax(microResource[1])))
      self.spheres[sphere]:toggleSecondaryResourceGroup(false)
    else
      self.spheres[sphere]:toggleResourceGroup         (false)
      self.spheres[sphere]:toggleSecondaryResourceGroup(false)
    end
  end
end

function mtLayout:TrackPet(track)
  if track and not self.spheres.pet then
    self.spheres.pet = ss.Sphere:New()
    self.spheres.pet:initialize(ss.db.pet,UIParent,"active")

    ss.Config.previewSphereList     = ss.Config.previewSphereList or {}
    ss.Config.previewSphereList.pet = {"Pet", "Pet"}
  elseif track and self.spheres.pet then
    self.spheres.pet:setResource(ss.db.pet)
    self.spheres.pet:show       (true)

    ss.Config.previewSphereList.pet = {"Pet", "Pet"}
  elseif not track and self.spheres.pet then
    self.spheres.pet:show(false)
    ss.Config.previewSphereList.pet = nil
  end
end

function mtLayout:UpdateMicroSphereTextures(group, texture, sphere)
  sphere = sphere or "health"
  self.spheres[sphere]:updateResourceGroupTextures(1, group, texture)
  self.spheres[sphere]:updateResourceGroupTextures(2, group, texture)
end

function mtLayout:UpdateScale()
  if not InCombatLockdown() then
    for k,v in pairs(self.spheres) do
      v:UpdateScale()
    end
  end
end

function mtLayout:Refresh()
  ss.profile.modeInfo.mainResource.modeSpec       = ss.db.mainResource.modes[ss.curSpec]       and ss.curSpec or "defaultSpec"
  ss.profile.modeInfo.additionalResource.modeSpec = ss.db.additionalResource.modes[ss.curSpec] and ss.curSpec or "defaultSpec"
  ss.profile.modeInfo.health.modeSpec             = ss.db.health.modes[ss.curSpec]             and ss.curSpec or "defaultSpec"

  self.spheres.health      :setResource(ss.db.health)
  self.spheres.mainResource:setResource(ss.db.mainResource)
  self:TrackAdditionalResource(ss.global.track.additionalResource and ss.ClassResources.hasSecondaryResource())

  if ss.ClassResources.hasSecondaryResource() then
    ss.Config.buttonFrame.UsePowerTrackerCheckButton:Show()
  else
    ss.Config.buttonFrame.UsePowerTrackerCheckButton:Hide()
  end

  self:ToggleMicroSpheres()
  self:ToggleMicroSpheres("mainResource")
end

function mtLayout:Shapeshift(shapeshift)
  if shapeshift ~= ss.curShapeshift then
    ss.curShapeshift = shapeshift

    for k,v in pairs(self.spheres) do
      if ss.db[k].modes[ss.profile.modeInfo[k].modeSpec] and ss.db[k].modes[ss.profile.modeInfo[k].modeSpec][shapeshift] then

        if k == "health" and self.inCombat then
          v:Set("prevMode", ss.db[k].modes[ss.profile.modeInfo[k].modeSpec][shapeshift])
          ss.profile.modeInfo[k].mode = shapeshift
        else
          v:setMode(ss.db[k].modes[ss.profile.modeInfo[k].modeSpec][shapeshift], shapeshift);
        end
      end
    end

    self:AddMicroSpheres()
    self:AddMicroSpheres("mainResource")
  end
end

function mtLayout:StartCombat()
  if not self.inCombat then
    self.inCombat = true

    if ss.global.track.combat then
      for k,v in pairs(self.spheres) do
        local configName = v:Get("configName")

        if ss.db[configName].modes[ss.profile.modeInfo[configName].modeSpec] and ss.db[configName].modes[ss.profile.modeInfo[configName].modeSpec]["combat"] then
          if (configName ~= "pet") and (configName == "health" or configName == "vehicle" or ss.curClass ~= "druid") then
            v:setMode(ss.db[configName].modes[ss.profile.modeInfo[configName].modeSpec]["combat"]);
          end
        end
      end
    end
  end
end

ss["Layout"] = setmetatable({}, { __index = mtLayout });
