---------------------------
-- Initialization Script --
---------------------------

local AddOnName, nsVars = ...

--Cache global variables
local vehicleInUse
local CreateFrame, PlaySound = CreateFrame, PlaySound
local rawget, rawset = rawget, rawset
local pairs, type = pairs, type
local UnitName, GetRealmName = UnitName, GetRealmName
local setmetatable, getmetatable = setmetatable, getmetatable
local table, pairs, type = table, pairs, type

function table.copy(t, deep, seen)
  seen = seen or {}
  if t == nil then return nil end
  if seen[t] then return seen[t] end

  local nt = {}
  for k, v in pairs(t) do
    if deep and type(v) == 'table' then
      nt[k] = table.copy(v, deep, seen)
    else
      nt[k] = v
    end
  end
  setmetatable(nt, table.copy(getmetatable(t), deep, seen))
  seen[t] = nt
  return nt
end

-- Prepare Addon variables
local SS = CreateFrame("Frame");
nsVars.SS = SS
SS.dVars = {};
SS.dVars["spheres"] = {};
SS.dVars["global"] = {};

SS.pVars = {};
SS.pVars["spheres"] = {};

function SS:SetMetatables(vars, stored)
  setmetatable(vars, { __index = stored })

  for k,v in pairs(stored) do
    if (type(v) == "table") then
      if rawget(vars, k) and type(vars[k]) ~= "table" then
        rawset(vars, k, {})
      end

      vars[k] = SS:SetMetatables(rawget(vars, k) or {}, v)
    elseif rawget(vars, k) and type(vars[k]) == "table" then
      rawset(vars, k, nil)
    end
  end

  return vars
end

-- Load profile data
function SS:Initialize()
  Spheres = Spheres or {}
  Seamore = Seamore or {}
  SeamoreSpheres = SeamoreSpheres or {}

  self.global = SS:SetMetatables(Seamore, self.dVars.global);
  self.profile = SS:SetMetatables(Spheres, self.dVars.spheres);

  -- Depricated
  if not self.global["SSProfile_Default"] then
    self.global["SSProfile_Default"] = {}
  end

  if not self.global["SSProfile_" .. UnitName("player") .. "-" .. GetRealmName()] and not self.global.characters[UnitName("player") .. "-" .. GetRealmName()] then
    if self.profile.health then
      self.global["SSProfile_" .. UnitName("player") .. "-" .. GetRealmName()] = self.profile
      self.profile = nil
      Spheres = {}

      self.profile = SS:SetMetatables(Spheres, self.dVars.spheres);
    else
      self.global["SSProfile_" .. UnitName("player") .. "-" .. GetRealmName()] = {}
    end

    self.global.characters[UnitName("player") .. "-" .. GetRealmName()] = true
  elseif self.profile.profileName and self.profile.health then
    local profileName = self.profile.profileName
    self.profile = nil
    Spheres = {}

    self.profile = SS:SetMetatables(Spheres, self.dVars.spheres);
    self.profile.profileName = profileName
    self.global.characters[UnitName("player") .. "-" .. GetRealmName()] = true
  end

  self.profile.profileName = self.profile.profileName or "SSProfile_" .. UnitName("player") .. "-" .. GetRealmName()
  self.MicroSphereData.load()
  self.global[self.profile.profileName] = self.global[self.profile.profileName] or {}
  self.db = SS:SetMetatables(self.global[self.profile.profileName], self.pVars.spheres["SSProfile_Default"]);
  self.private = SS:SetMetatables(SeamoreSpheres, self.pVars.spheres);

  self:OnInitialized()
end

-- Initialize event listeners
local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("ADDON_LOADED")
eventFrame:RegisterEvent("VARIABLES_LOADED")
eventFrame:RegisterEvent("PLAYER_LOGIN")
eventFrame:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
eventFrame:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
eventFrame:RegisterEvent("UNIT_PET")
eventFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
eventFrame:RegisterEvent("UNIT_MAXPOWER")
eventFrame:RegisterEvent("UNIT_ENTERED_VEHICLE")
eventFrame:RegisterEvent("UNIT_EXITED_VEHICLE")

function eventFrame:OnEvent(event,arg1, ...)
  if event == "ADDON_LOADED" then
    self:UnregisterEvent(event)
    SS:Initialize()
  elseif event == "VARIABLES_LOADED" then
    SS:OnVariablesLoaded()
    self:UnregisterEvent(event)
  elseif event == "PLAYER_LOGIN" then
    SS:OnPlayerLoggedIn()
    self:UnregisterEvent(event)
  elseif event == "PLAYER_REGEN_DISABLED" then
    SS:OnRegenDisabled()

    self:UnregisterEvent(event)
    self:RegisterEvent("PLAYER_REGEN_ENABLED")
  elseif event == "PLAYER_REGEN_ENABLED" then
    SS:OnRegenEnabled()

    self:UnregisterEvent(event)
    self:RegisterEvent("PLAYER_REGEN_DISABLED")
  elseif event == "PLAYER_SPECIALIZATION_CHANGED" and arg1 == "player"  then
    SS:OnPlayerSpecializationChanged()
  elseif event == "UPDATE_SHAPESHIFT_FORM" then
    SS:OnPlayerShapeshift()
  elseif event == "UNIT_MAXPOWER" and arg1 == "player" then
    SS:OnUnitMaxPowerChanged()
  elseif event == "UNIT_SPELLCAST_SUCCEEDED" and arg1 == "player" then
    SS:OnSpellCastSuccess(event, ...)
  elseif event == "UNIT_PET" then
    local name = UnitName("pet")
    SS:OnPetAvailable(name, HasPetSpells() or 0)
  elseif event == "UNIT_ENTERED_VEHICLE" and arg1 == "player" then
    local args = {...}

    if args[4] == true and args[7] == true then
      SS:OnPlayerEnteredVehicle()
    end
  elseif event == "UNIT_EXITED_VEHICLE" and arg1 == "player" then
    SS:OnPlayerExitedVehicle()
  end
end

eventFrame:SetScript("OnEvent",eventFrame.OnEvent)

function SS:AddEvent(e)
  eventFrame:RegisterEvent(e)
end

function SS:ResetSpheres()
--  table.wipe(self.db)
--  table.wipe(self.global)
--  table.wipe(self.private)
--
--  Spheres = self.dVars.spheres
--  Seamore = self.dVars.global
--  SeamoreSpheres = self.pVars.spheres
--
--  self.db = Spheres
--  self.global = Seamore
--  self.private = SeamoreSpheres
--
--  self:OnInitialized()


--  local sphereId
--  if SeamoreSpheres.sphereIds then
--    sphereId = SeamoreSpheres.sphereIds[self.name..' - '..self.realm]
--  end
--
--  if sphereId and SeamoreSpheres.spheres and SeamoreSpheres.spheres[sphereId] then
--    SeamoreSpheres.spheres[sphereId] = nil;
--  end

  Seamore[Spheres.profileName] = nil
  Spheres = nil
  SeamoreSpheres = nil

  ReloadUI()
end

function SS:ToggleConfig()
  if not InCombatLockdown() then
    if self.Config:IsVisible() then
      self.Config:Hide()
      PlaySound("SPELLBOOKCLOSE", "master");
    else
      self.Config:Show()
      PlaySound("SPELLBOOKOPEN", "master");
    end
  end
end