--------------------------
-- Core Addon Framework --
--------------------------
local AddOnName, nsVars = ...
local ss = nsVars.SS

local IsShiftKeyDown = IsShiftKeyDown
local PlayerFrame, PlayerFrame_OnEvent = PlayerFrame, PlayerFrame_OnEvent
local GetShapeshiftFormID = GetShapeshiftFormID
local UnitClass, GetSpecialization, GetSpecializationInfo = UnitClass, GetSpecialization, GetSpecializationInfo
local select, math, strlower = select, math, strlower
local UnitAffectingCombat, GetTime, GetSpellCooldown = UnitAffectingCombat, GetTime, GetSpellCooldown
local floor, tostring, pairs = floor, tostring, pairs
local InCombatLockdown = InCombatLockdown
local table, type, print, next = table, type, print, next

--- Global properties.
------------------------
ss.version = "v-0.9.25-alpha"
ss.gradientScale = 0.05

ss.curClass = strlower(select(2, UnitClass("player")))

ss.gcdWatch = {
  max = 1,
  cur = 1,
};

ss.pendingTasks = {
}

--- Global functions.
-----------------------

function ss:CompletePendingTasks()
  local completed = {};

  for k,v in pairs(self.pendingTasks) do
    if InCombatLockdown() then
      break
    end

    if type(v) == "function" then
      v()
      print("SeamoreSpheres: Completed pending task: " .. k)
    else
      print("SeamoreSpheres: Could not complete pending task: " .. k)
    end

    table.insert(completed, k)
  end

  for k,v in pairs(completed) do
    self.pendingTasks[v] = nil
  end
end

function ss:AddPendingTask(name, task)
  self.pendingTasks[name] = task

  if not InCombatLockdown() then
    self:CompletePendingTasks()
  else
    print("SeamoreSpheres: " .. name .. " will be called once combat has ended.")
  end
end

function ss:HandlePlayerFrame(show)
  if show then
    PlayerFrame:SetScript("OnEvent",PlayerFrame_OnEvent)
    PlayerFrame:Show()
  else
    PlayerFrame:SetScript("OnEvent",nil)
    PlayerFrame:Hide()
  end
end

function ss:GetRGBAValues(colorTable)
  if not colorTable then return 1,1,1,1; end

  if (colorTable.r and colorTable.r > 1) or (colorTable[1] and colorTable[1] > 1) then
    return (colorTable.r or colorTable[1]) / 255, (colorTable.g or colorTable[2]) / 255, (colorTable.b or colorTable[3]) / 255, (100 - (colorTable.a or colorTable[4])) / 100
  else
    return colorTable.r or colorTable[1], colorTable.g or colorTable[2], colorTable.b or colorTable[3], colorTable.a or colorTable[4]
  end
end

function ss:MakeFrameMovable(frame,button,listener)
  local btnString = "LeftButton"
  if button then
    btnString = button
  end

  frame:SetClampedToScreen(true)
  frame:SetMovable(true)
  frame:EnableMouse(true)
  frame:RegisterForDrag(btnString)
  frame:SetScript("OnDragStart", function(self)
    if IsShiftKeyDown() then
      self:StartMoving()
    end
  end)
  frame:SetScript("OnDragStop", function(self)
    self:StopMovingOrSizing()
    if listener then
      listener(self)
    end
  end)
end

function ss:round(num, idp)
  local mult = 10^(idp or 0)
  return math.floor(num * mult + 0.5) / mult
end

function ss.shapeshiftToString(id)
  local forms = {
    [0]  = "default",
    [1]  = "cat",
    [2]  = "tree of life",
    [3]  = "travel",
    [4]  = "aquatic",
    [5]  = "bear",
    [27] = "flight",
    [31] = "moonkin",
  };

  return forms[id] or "default"
end

function ss:valueFormat(val, formatting, petOverride)
  local newVal = val
  if petOverride == true then
    if val > 10000 then
      newVal = (floor((val/1000)*10)/10).."k"
    end
    return newVal;
  elseif formatting == "truncated" then
    if val > 1000000 then
      newVal = (floor((val/1000000)*10)/10) .."m"
    elseif val > 999 then
      newVal = (floor((val/1000)*10)/10) .."k"
    end
    return newVal;
  elseif formatting == "commaSeparated" then
    newVal = tostring(val):reverse():gsub("%d%d%d", "%1,"):reverse():gsub("^,", "");
    return newVal;
  else
    return newVal;
  end
end

------------------------------
-- Liftcycle Event Handlers --
------------------------------

function ss:OnInitialized()
  ss.Updater.update()
end

function ss:OnPetAvailable(name, hasPetSpells)
  ss.petAvail = ((hasPetSpells > 10) and name) and true or nil
  self.Layout:TrackPet(self.global.track["pet"] and (hasPetSpells > 10) and name)
end

function ss:OnPlayerEnteredVehicle()
  ss.Layout:OnPlayerEnteredVehicle()
end

function ss:OnPlayerExitedVehicle()
  ss.Layout:OnPlayerExitedVehicle()
end

function ss:OnPlayerLoggedIn()
  self.curSpec = GetSpecialization()
  self.curSpecName = self.curSpec and select(2, GetSpecializationInfo(self.curSpec)) or "None"
  self.curSpec = strlower(self.curSpec)
  self.Layout:Initialize()

  if self.curClass == "druid" then
    self:AddEvent("UPDATE_SHAPESHIFT_FORM")
  end
end

function ss:OnPlayerShapeshift()
  if ss.curSpec and ss.curClass == "druid" then
    self.Layout:Shapeshift(self.shapeshiftToString(GetShapeshiftFormID() or 0))
  end
end

function ss:OnPlayerSpecializationChanged()
  self.curSpec = GetSpecialization()
  self.curSpecName = self.curSpec and select(2, GetSpecializationInfo(self.curSpec)) or "None"
  self.curSpec = strlower(self.curSpec)

  self.Layout:OnSpecializationChanged()
end

function ss:OnRegenEnabled()
  if self.Layout and not UnitAffectingCombat("player") then
    self.Layout:EndCombat()
  end

  -- Check for pending tasks
  if next(self.pendingTasks) ~= nil then
    self:CompletePendingTasks()
  end
end

function ss:OnRegenDisabled()
  if self.Layout and UnitAffectingCombat("player") then
    self.Layout:StartCombat()
  end
end

function ss:OnSpellCastSuccess(event, ...)
  self.updateGCD()
end

function ss:OnUnitMaxPowerChanged()
  ss.Layout:OnUnitMaxPowerChanged()
end

function ss.updateGCD()
  --  self.Debug.describe(self.dVars.spheres.health.general)
  --    local tempSpellList = ""
  --    wipe(gcdSpells)
  --    local _, _, offset, numSpells = GetSpellTabInfo(2)
  --    for i = 1, offset + numSpells do
  --      local slotType, slotID = GetSpellBookItemInfo(i, "spell")
  --      if slotType == "SPELL" then
  --        local slotName = GetSpellBookItemName(i, "spell")
  --        local spellName, _, _, _, _, _, spellID = GetSpellInfo(slotName)
  --        local spellCD = GetSpellBaseCooldown(spellID or 0) -- spellID can be nil during loading
  --        if spellCD == 0 then
  --          gcdSpells[spellID] = true
  --        end
  --      end
  --    end
  --    gcdMasterSpell = next(gcdSpells)
  --
  --    local start, duration = GetSpellCooldown(gcdMasterSpell)


  -- Get additiona args
  --    local eSpell, eRank, eLineID, eSpellID = ...
  --    --    local name, rank, icon, castingTime, minRange, maxRange, spellID = GetSpellInfo(eSpellID)
  --        local name, rank, icon, castingTime, minRange, maxRange, spellID = GetSpellInfo(61304)
  --local test = name .. rank .. icon .. castingTime .. minRange .. maxRange .. spellID

  --    realCastTime = castingTime / 1000


  --  local gcd = gcdVal - GCDReduc

  -- Get the GCD duration
  local tempStart, tempGCD = GetSpellCooldown(61304) -- get gcd, 61304 = gcd spell id
  --    DebugEventArgs = name .. " " .. tempGCD
  ss.gcdWatch.max = tempGCD

  if tempGCD > 0 then
    if not ss.gcdWatch.start then
      ss.gcdWatch.start = GetTime()
    end

    ss.gcdWatch.cur = 0
  end
end

function ss:OnVariablesLoaded()
  if self.global.general.MapMarker.show then
    self.MapMarker:Initialize()
  end
end
