Proximo = LibStub("AceAddon-3.0"):NewAddon("Proximo", "AceEvent-3.0", "AceConsole-3.0", "AceTimer-3.0", "AceHook-3.0", "AceComm-3.0")
local Proximo = Proximo
local L = LibStub("AceLocale-3.0"):GetLocale("Proximo", true)
local TG = LibStub:GetLibrary("TalentGuess-1.1"):Register()
local db

Proximo.title = "Proximo"
Proximo.version = GetAddOnMetadata(Proximo.title, "Version")
Proximo.PVP_TRINKET = 42292
Proximo.PVP_RACIAL = 59752
Proximo.PVP_TIME = 120

local prox_list = {}
local arena_list = {}
local unfound_arena_list = {}
local prox_units = {}
local prox_cur_unit = 1
local max_unit_size = 5
local mainassist = "target"
local mainassistset = false

for i=1,max_unit_size do
  prox_units["arena" .. i] = i
end

--LUA calls
local pairs = pairs
local gsub = gsub
local string_format = string.format
local string_split = string.split
local string_match = string.match
local math_floor = math.floor

--Blizzard API
local UnitName = UnitName
local UnitClass = UnitClass
local UnitHealth = UnitHealth
local UnitHealthMax = UnitHealthMax
local UnitPowerType = UnitPowerType
local UnitSex = UnitSex
local UnitRace = UnitRace
local UnitMana = UnitMana
local UnitManaMax = UnitManaMax
local UnitExists = UnitExists
local UnitCanAttack = UnitCanAttack
local UnitIsPlayer = UnitIsPlayer
local UnitIsCharmed = UnitIsCharmed
local UnitLevel = UnitLevel
local UnitFactionGroup = UnitFactionGroup
local UnitGUID = UnitGUID
local InCombatLockdown = InCombatLockdown
local GetNumPartyMembers = GetNumPartyMembers
local GetPlayerBuff = GetPlayerBuff
local GetPlayerBuffTexture = GetPlayerBuffTexture
local GetRealmName = GetRealmName
local IsInInstance = IsInInstance
local GetBattlefieldStatus = GetBattlefieldStatus
local UNKNOWNOBJECT = UNKNOWNOBJECT

--combat log locals
Proximo.COMBAT_EVENTS = {
  ["UNIT_DIED"] = "DEATH",
  ["UNIT_DESTROYED"] = "DEATH",
}
local COMBAT_EVENTS = Proximo.COMBAT_EVENTS
local CombatLog_Object_IsA = CombatLog_Object_IsA
local COMBATLOG_OBJECT_NONE = COMBATLOG_OBJECT_NONE
local COMBATLOG_FILTER_HOSTILE_PLAYERS = COMBATLOG_FILTER_HOSTILE_PLAYERS

----------------------
--table caching
local new, del
do
  local list = setmetatable({}, {__mode='k'})
  function new(...)
    local t = next(list)
    if t then
      list[t] = nil
      for i = 1, select('#', ...) do
        t[i] = select(i, ...)
      end
      return t
    else
      return { ... }
    end
  end
  function del(t)
    for k in pairs(t) do
      t[k] = nil
    end
    list[t] = true
    return nil
  end
end

local function in_arena_zone()
  if select(2, IsInInstance()) == "arena" then
    return true
  end
end

local function in_bg_zone()
  if select(2,IsInInstance()) == "pvp" and db.useinbg then
    return true
  end
end

local function valid_unit(unitid)
  if UnitExists(unitid) and UnitName(unitid) and UnitIsPlayer(unitid) and UnitCanAttack("player",unitid) and not UnitIsCharmed(unitid) and not UnitIsCharmed("player") then
    return true
  end
end

local function clear_arena_units()
  for k in pairs(arena_list) do
    arena_list[k]= nil
  end
  for k in pairs(unfound_arena_list) do
    unfound_arena_list[k] = nil
  end
end

local function add_arena_units()
  for i = 1, Proximo:GetBracketSize() do
    arena_list["arena"..i] = true
    unfound_arena_list["arena"..i] = true
  end
end

local function add_bg_units()
  arena_list["target"] = true
  arena_list["focus"] = true
end

----------------------
--Update local db and frame
function Proximo:Refresh()
  db = self.db.profile
  self:UpdateFrame()
end

----------------------
--On start
function Proximo:OnInitialize()
  self.db = LibStub("AceDB-3.0"):New("ProximoDB", self:GetDefaultConfig(), "Defaults")
  self:SetupOptions()
  --callbacks for profile changes
  self.db.RegisterCallback(self, "OnProfileChanged", "Refresh")
  self.db.RegisterCallback(self, "OnProfileCopied", "Refresh")
  self.db.RegisterCallback(self, "OnProfileReset", "Refresh")
  --local the profile table
  db = self.db.profile
end

----------------------
--Disabled
function Proximo:OnDisable()
  self:ResetList()
  if self.frame then
    self.frame:Hide()
  end
end

----------------------
--Loaded
function Proximo:OnEnable()
  self:RegisterEvent("PLAYER_ENTERING_WORLD")
  self:RegisterComm(self.title)
end

----------------------
--Player Zoned
function Proximo:PLAYER_ENTERING_WORLD(event)
  mainassistset = false
  self:ResetList()
  self:ZoneCheck()
end

----------------------
--Combat events
function Proximo:COMBAT_LOG_EVENT_UNFILTERED(arg1, timestamp, event, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags, ...)
  --check for events we care about
  local etype = COMBAT_EVENTS[event]
  if not etype then return end

  --see if its to an enemy
  local toEnemyPlayer, fromEnemyPlayer, fromTarget, fromFocus
  if (destName and not CombatLog_Object_IsA(destFlags, COMBATLOG_OBJECT_NONE) ) then
    toEnemyPlayer = CombatLog_Object_IsA(destFlags, COMBATLOG_FILTER_HOSTILE_PLAYERS)
    toTarget = CombatLog_Object_IsA(destFlags, COMBATLOG_OBJECT_TARGET)
    toFocus = CombatLog_Object_IsA(destFlags, COMBATLOG_OBJECT_FOCUS)
  end
  if (sourceName and not CombatLog_Object_IsA(sourceFlags, COMBATLOG_OBJECT_NONE) ) then
    fromEnemyPlayer = CombatLog_Object_IsA(sourceFlags, COMBATLOG_FILTER_HOSTILE_PLAYERS)
    fromTarget = CombatLog_Object_IsA(sourceFlags, COMBATLOG_OBJECT_TARGET)
    fromFocus = CombatLog_Object_IsA(sourceFlags, COMBATLOG_OBJECT_FOCUS)
  end

  --if not from a enemy type we care about, then end
  if not toEnemyPlayer and not fromEnemyPlayer then return end

  local spellId, spellName, texture, time
  ------------buff/debuff gain----------------
  if etype == "BUFF" then
    if prox_list[destGUID] and toEnemyPlayer and not toTarget and not toFocus and not fromTarget and not fromFocus  then
      spellId, spellName = select(1, ...)
      texture = select(3, GetSpellInfo(spellId))
      self:AuraApplied(prox_list[destGUID].button.aura, prox_list[destGUID].name, prox_list[destGUID].class, spellName, texture)
    end
  ------------buff/debuff lose----------------
  elseif etype == "FADE" then
    if prox_list[destGUID] and toEnemyPlayer then
      spellId, spellName = select(1, ...)
      if spellId == self.PVP_TRINKET or spellId == self.PVP_RACIAL then
        texture = self:GetTrinketIcon(prox_list[destGUID].faction, prox_list[destGUID].level)
        self:AuraApplied(prox_list[destGUID].button.trinket, prox_list[destGUID].name, prox_list[destGUID].class, spellName, texture)
      elseif db.auras then
        texture = select(3, GetSpellInfo(spellId))
        self:AuraRemoved(prox_list[destGUID].button.aura, prox_list[destGUID].name, prox_list[destGUID].class, spellName, texture)
      end
    end
  ------------spell start----------------
  elseif etype == "CASTSTART" then
    if prox_list[sourceGUID] and fromEnemyPlayer and not fromTarget and not fromFocus then
      spellId, spellName = select(1, ...)
      time = select(7, GetSpellInfo(spellId)) / 1000
      self:SpellStart(prox_list[sourceGUID].button.spellBar, spellName, time, 1)
    end
  ------------spell end----------------
  elseif etype == "CASTEND" then
    if prox_list[sourceGUID] and fromEnemyPlayer and not fromTarget and not fromFocus then
      self:HandleSpellEnd(prox_list[sourceGUID].button.spellBar, 1)
    end
  ------------interrupt----------------
  elseif etype == "INTERRUPT" then
    if prox_list[destGUID] and toEnemyPlayer then
      self:HandleSpellEnd(prox_list[destGUID].button.spellBar, 1)
    end
  ------------deaths----------------
  elseif etype == "DEATH" then
    if prox_list[destGUID] and toEnemyPlayer then
      self:KillGUID(destGUID)
    end
  end
end

----------------------
--Kill the unit
function Proximo:KillGUID(guid)
  --set to dead
  prox_list[guid].dead = true
  --update health/mana
  self:UpdateHealth(guid)
  self:UpdateMana(guid)
  --update spell and aurs
  self:AuraFade(prox_list[guid].button.aura)
  self:HandleSpellEnd(prox_list[guid].button.spellBar, 1)
  if db.death then
    local announcement = string_format(ERR_PLAYER_DIED_S, prox_list[guid].name)
    self:SendAnnouncement(announcement, 1, .1, .1)
    if db.deathsound then
      PlaySound("LEVELUP")
    end
  end
end

----------------------
--Zone Check
function Proximo:ZoneCheck()
  if InCombatLockdown() then
    self:ScheduleTimer("ZoneCheck", 1, self)
    return
  end
  if in_arena_zone() or in_bg_zone() then
    if self.frame==nil then
      self:MakeFrame()
    end
    self.frame:Show()
    self:UpdateFrameHeight()
    self:RegisterEvent("UNIT_HEALTH")
    self:RegisterEvent("UNIT_MAXHEALTH", "UNIT_HEALTH")
    self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
    self:RegisterEvent("PLAYER_TARGET_CHANGED")
    if db.mana then self:RegisterEvent("UNIT_MANA") end
    if db.auras or db.trinket then self:RegisterAuras() end
    if db.spell then self:RegisterSpells() end
    if db.talents then
      TG:EnableCollection()
      TG:RegisterCallback(self, "TalentsGuessChanged")
    end
    self:ScheduleRepeatingTimer("TimedEvents", .25, self)
    if in_arena_zone() then
      add_arena_units()
    elseif in_bg_zone() then
      self:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
      self:RegisterEvent("PLAYER_FOCUS_CHANGED")
      add_bg_units()
    end
  else
    self:UnregisterEvent("UNIT_HEALTH")
    self:UnregisterEvent("UNIT_MAXHEALTH")
    self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
    self:UnregisterEvent("UPDATE_MOUSEOVER_UNIT")
    self:UnregisterEvent("PLAYER_TARGET_CHANGED")
    self:UnregisterEvent("PLAYER_FOCUS_CHANGED")
    self:UnregisterEvent("UNIT_MANA")
    self:UnregisterAuras()
    self:UnregisterSpells()
    self:CancelAllTimers()
    TG:DisableCollection()
    if self.frame then self.frame:Hide() end
    clear_arena_units()
  end
end


----------------------
--Add a unit to local list
function Proximo:AddToList(name, server, class, race, sex, health, mana, guid, unitid, faction, level)
  if not name or name == UNKNOWNOBJECT then return end
  local announcement = name.." - "..self:GetLocalClass(class)
  local t = new()
  local cur_unit = prox_units[unitid] or prox_cur_unit
  local button = self.frame.buttons[cur_unit]
  t.server = server
  t.race = race
  t.sex = sex
  t.class = class
  t.displayname = db.classtext and announcement or name
  t.health = health
  t.lhealth = 100
  t.mana = mana
  t.click = false
  t.unit = cur_unit
  t.unitid = unitid
  t.name = name
  t.faction = faction
  t.level = level
  t.button = button
  t.colortext = "|cFFFFFFFF"
  self:RemoveFromList(cur_unit)
  prox_list[guid] = t
  --setup frame class
  self:FrameClass(button,class, db.mana)
  --update name
  self:UpdateNameText(guid)
  --setup frame race
  if db.race then
    self:SetRaceIcon(button.raceicon, race, sex)
  end
  --update health/mana
  self:UpdateHealth(guid)
  self:UpdateMana(guid)
  --update prox_cur_unit count
  prox_cur_unit = prox_cur_unit + 1
  if prox_cur_unit > max_unit_size then prox_cur_unit = 1 end
  --send announcement
  self:SendAnnouncement(announcement, self:GetClassColor(class))
end

----------------------
--Reset local list
function Proximo:ResetList()
  for k, v in pairs(prox_list) do
    prox_list[k] = del(v)
  end
  prox_cur_unit = 1
  self:FrameClean()
end

----------------------
--Remove a unit from list
function Proximo:RemoveFromList(unit)
  for k, v in pairs(prox_list) do
    if v.unit == unit then
      prox_list[k] = del(v)
    end
  end
end

----------------------
--get local list
function Proximo:GetList()
  return prox_list
end

----------------------
--get local list
function Proximo:GetArenaList()
  return arena_list
end

----------------------
--Check unit for updates
function Proximo:CheckUnitIDChanges(unitid)
  if valid_unit(unitid) then
    local guid = UnitGUID(unitid)
    local health = math_floor((UnitHealth(unitid)/UnitHealthMax(unitid)) * 100)
    local mana = 0
    --if display mana and they have mana, set mana values
    if db.mana and UnitPowerType(unitid) == 0 then
      mana = math_floor((UnitMana(unitid)/UnitManaMax(unitid)) * 100)
    end
    --if a new player
    if not prox_list[guid] then
      local name, server = UnitName(unitid)
      local class = select(2, UnitClass(unitid))
      local race = select(2, UnitRace(unitid))
      local sex = UnitSex(unitid)
      local guid = UnitGUID(unitid)
      local faction = UnitFactionGroup(unitid)
      local level = UnitLevel(unitid)
      if not server then
        server = GetRealmName()
      end
      self:AddToList(name, server, class, race, sex, health, mana, guid, unitid, faction, level)
    else
      prox_list[guid].health = health
      prox_list[guid].mana = mana
    end
    --if display talents
    if db.talents and prox_list[guid] and not prox_list[guid].talents then
      self:TalentsGuessChanged(guid)
    end
  end
end

----------------------
--Talent Guess Changed
function Proximo:TalentsGuessChanged(guid)
  if not db.talents then return end
  if prox_list[guid] then
    local t1, t2, t3 = TG:GetTalents(guid)
    local talents = string_format("%d/%d/%d", t1 or 0, t2 or 0, t3 or 0)
    prox_list[guid].talents = talents
    self:UpdateNameText(guid)
  end
end

----------------------
--Update name
function Proximo:UpdateNameText(guid)
  local enemy = prox_list[guid]
  local button = enemy.button
  if db.talents and enemy.talents then
    button.text:SetText(enemy.colortext..enemy.displayname.." ("..enemy.talents..")|r")
  else
    button.text:SetText(enemy.colortext..enemy.displayname.."|r")
  end
end

----------------------
--Mouse over event
function Proximo:UPDATE_MOUSEOVER_UNIT(event)
  self:CheckUnitIDChanges("mouseover")
end

----------------------
--Target changed event
function Proximo:PLAYER_TARGET_CHANGED(event)
  if in_bg_zone() then
    self:CheckUnitIDChanges("target")
  end
  --update selected target
  if db.highlighttar then
    for k, v in pairs(prox_list) do
      if UnitGUID("target") == k then
        v.button.healthBar.selected:Show()
      else
        v.button.healthBar.selected:Hide()
      end
    end
  end
end

----------------------
--Focus changed event
function Proximo:PLAYER_FOCUS_CHANGED(event)
  self:CheckUnitIDChanges("focus")
end

----------------------
--Unit Health event
function Proximo:UNIT_HEALTH(event, unitid)
  if arena_list[unitid] then
    self:CheckUnitIDChanges(unitid)
    local guid = UnitGUID(unitid)
    if prox_list[guid] then
      self:UpdateHealth(guid)
    end
  end
end

----------------------
--Unit Health event
function Proximo:UpdateHealth(guid)
  local alpha, colortext = 0, "|cFFFFFFFF"
  local enemy = prox_list[guid]
  local health, lhealth = enemy.health, enemy.lhealth
  local button = enemy.button
  --set colors
  if health <= 0 or enemy.dead then
    health = 0
    colortext = "|cFF444444"
    button.icon:SetAlpha(.33)
    if button.raceicon then button.raceicon:SetAlpha(.33) end
    if button.aura then self:AuraFade(button.aura) end
    if button.spell then self:SpellEnd(button.spell) end
  else
    if health <= 33 then
      colortext = "|cFFFF0000"
    elseif health <= 66 then
      colortext = "|cFFFFFF00"
    end
    if button.icon:GetAlpha(1) ~= 1 then button.icon:SetAlpha(1) end
    if button.raceicon and button.raceicon:GetAlpha(1) ~= 1 then button.raceicon:SetAlpha(1) end
  end
  --update status bar
  button.healthBar:SetValue(health)
  if enemy.dead then
    button.healthtext:SetText(string_format("%s%s|r", colortext, DEAD))
  else
    button.healthtext:SetText(string_format("%s%d%s|r", colortext, health, "%"))
  end
  prox_list[guid].colortext = colortext
  self:UpdateNameText(guid)
  --update low health announcement
  if db.lowhealth then
    if (health ~= 0) and (health <= 20) and (lhealth > 20) then
      self:SendAnnouncement(enemy.name.." ("..L["LowHealth"]..")", .8, .3, .3)
      if db.lowhealthsound then
        PlaySound("RaidWarning")
      end
    end
    prox_list[guid].lhealth = health
  end
end

----------------------
--Unit Mana event
function Proximo:UNIT_MANA(event, unitid)
  if arena_list[unitid] then
    self:CheckUnitIDChanges(unitid)
    local guid = UnitGUID(unitid)
    if prox_list[guid] then
      self:UpdateMana(guid)
    end
  end
end

----------------------
--Unit Health event
function Proximo:UpdateMana(guid)
  --update mana bar
  if db.mana then
    local enemy = prox_list[guid]
    local mana = enemy.mana
    local button = enemy.button
    if button.manaBar then
      if enemy.dead then mana = 0 end
      button.manaBar:SetValue(mana)
      if mana > 0 and not button.manaBar:IsVisible() then button.manaBar:Show() end
    end
  end
end

----------------------
--Events to do every timespan
function Proximo:TimedEvents()
  local party
  if in_arena_zone() then
    for i=1, GetNumPartyMembers() do
      party = "party"..i.."target"
      --update party targets
      self:UpdatePartyTarget(i, party)
    end
    --look for missing arena units
    for k, v in pairs(unfound_arena_list) do
      if valid_unit(k) then
        self:CheckUnitIDChanges(k)
        if prox_list[UnitGUID(k)] then
          unfound_arena_list[k] = nil
        end
      end
    end
    --update secure clicks
    local unit, button
    for i=1,max_unit_size do
      button=self.frame.buttons[i]
      --update secure clicks if not updated already and not in combat
      if not button.setup and not InCombatLockdown() then
        unit = "arena"..i
        button:SetAttribute("unit", unit)
        self:UpdateSecureClicks(button, db.leftclick, "1", unit, db.leftspellname)
        self:UpdateSecureClicks(button, db.rightclick, "2", unit, db.rightspellname)
        self:UpdateSecureClicks(button, db.mouse3click, "3", unit, db.mouse3spellname)
        self:UpdateSecureClicks(button, db.mouse4click, "4", unit, db.mouse4spellname)
        self:UpdateSecureClicks(button, db.mouse5click, "5", unit, db.mouse5spellname)
        self.frame.buttons[i].setup = true
      end
    end
  end
  --update MA while arena has not started
  if not mainassistset then
    self:SetMainAssist(db.ma)
  end
  --update highlight and clicks
  for k, v in pairs(prox_list) do
    local button = v.button
    if UnitGUID(mainassist) == k then
      button.healthBar.highlight:SetBackdropBorderColor(db.highlightcolor.r,db.highlightcolor.g,db.highlightcolor.b,1)
    else
      button.healthBar.highlight:SetBackdropBorderColor(db.highlightcolor.r,db.highlightcolor.g,db.highlightcolor.b,0)
    end
    --update bg macros if not updated already and not in combat
    if in_bg_zone() then
      if not v.setup and not InCombatLockdown() then
        self:UpdateMacroClicks(button, db.leftclick, "macrotext1", v.name, db.leftspellname)
        self:UpdateMacroClicks(button, db.rightclick, "macrotext2", v.name, db.rightspellname)
        self:UpdateMacroClicks(button, db.mouse3click, "macrotext3", v.name, db.mouse3spellname)
        self:UpdateMacroClicks(button, db.mouse4click, "macrotext4", v.name, db.mouse4spellname)
        self:UpdateMacroClicks(button, db.mouse5click, "macrotext5", v.name, db.mouse5spellname)
        prox_list[k].setup = true
      end
    end
  end
end

----------------------
--Set the MA based on a name
function Proximo:SetMainAssist(ma)
  if mainassistset then return end
  if UnitName("player") == ma or in_bg_zone() then
    mainassist = "target"
    mainassistset = true
  else
    local party
    for i=1, GetNumPartyMembers() do
      party = "party"..i
      if UnitName(party) == ma then
        mainassist = party.."target"
        mainassistset = true
        return
      end
    end
  end
end

----------------------
--Send Comm message to Prox clients
function Proximo:SendProxComm(data)
  self:SendCommMessage(self.title, data, "PARTY", nil, "ALERT")
end

----------------------
--Receive a comm message
function Proximo:OnCommReceived(prefix, message, distribution, sender)
  if prefix == self.title and sender ~= UnitName("player") then
    local method, data = string_match(message, "([^:]+)%:(.+)")
    if self[method] then
      self[method](self, sender, string_split(",", data))
    end
  end
end

----------------------
--Receive a MA
function Proximo:ReceiveMainAssist(sender, ma)
  db.ma = ma
  mainassistset = false
  self:SetMainAssist(ma)
  self:Print(L["MainAssist"]..": "..ma)
end

----------------------
--Receive a version check
function Proximo:ReceiveVersion(sender)
  self:SendProxComm("ReceiveVersionResponse:"..self.version)
end

----------------------
--Receive a version check response
function Proximo:ReceiveVersionResponse(sender, version)
  self:Print(L["VersionCheck"]..": "..sender.." - "..version)
end

----------------------
--Refresh the frame display for test frame
function Proximo:FrameRefresh()
  self:UpdateFrameHeight()
  for k, v in pairs(prox_list) do
    name, class, health, mana, talents, guid = v.name, v.class, v.health, v.mana, v.talents, k
    button = v.button
    alpha, colortext = 0, "|cFFFFFFFF"
    --set colors

    if health <= 0 then
      colortext = "|cFF444444"
    elseif health <= 33 then
      colortext = "|cFFFF0000"
    elseif health <= 66 then
      colortext = "|cFFFFFF00"
    end

    --update status bar
    button.healthBar:SetValue(health)
    button.healthtext:SetText(string_format("%s%d%s|r", colortext, health, "%"))

    --class
    if db.classtext then
      lname = name.." - "..self:GetLocalClass(class)
    else
      lname = name
    end

    --talents
    if talents and db.talents then
      lname = lname.." ("..talents..")"
    end

    --Update unit text
    button:SetAlpha(1)
    button.text:SetText(colortext..lname.."|r")

    --update mana bar
    if db.mana and button.manaBar then
      button.manaBar:SetValue(mana)
      if mana > 0 and not button.manaBar:IsVisible() then button.manaBar:Show() end
    end
  end

end

----------------------
--update a buttons clicks
function Proximo:UpdateMacroClicks(button, option, etype, name, spell)
  local target_macro = "/targetexact "..name
  if option == "target" then
    button:SetAttribute(etype, "/script PlaySound(\"igMainMenuOptionCheckBoxOn\")\n"..target_macro)
  elseif option == "focus" then
    button:SetAttribute(etype, target_macro.."\n/focus\n/targetlasttarget")
  elseif option == "spell" and spell and spell ~= "" then
    button:SetAttribute(etype, target_macro.."\n/cast "..spell)
  elseif option == "macro" then
    --add name, fix raw string break to line breaks
    local macro = gsub(gsub(gsub(spell, "*t", name), ";", "\n"), "\\n", "\n")
    button:SetAttribute(etype, macro)
  end
end

----------------------
--update a buttons clicks
function Proximo:UpdateSecureClicks(button, option, num, unit, spell)
  local etype = "type"..num
  if option == "target" then
    button:SetAttribute(etype, "target")
  elseif option == "focus" then
    button:SetAttribute(etype, "focus")
  elseif option == "spell" and spell and spell ~= "" then
    button:SetAttribute(etype, "spell")
    button:SetAttribute("spell"..num, spell)
  elseif option == "macro" then
    --add name, fix raw string break to line breaks
    local macro = gsub(gsub(gsub(spell, "*t", unit), ";", "\n"), "\\n", "\n")
    button:SetAttribute(etype, "macro")
    button:SetAttribute("macrotext"..num, macro)
  end
end

----------------------
--Scan party for target updates
function Proximo:UpdatePartyTarget(num, target)
  if db.partytargets then
    local name, unit, button
    --update each frame
    for k, v in pairs(prox_list) do
      button = v.button
      if UnitExists(target) and UnitGUID(target) == k then
        local r,g,b = self:GetClassColor(select(2, UnitClass("party"..num)))
        button.partytargets[num]:SetStatusBarColor(r,g,b,1)
        button.partytargets[num]:SetValue(1)
      else
        button.partytargets[num]:SetValue(0)
      end
      if not button.partytargets[num]:IsVisible() then button.partytargets[num]:Show() end
    end
  end
end

----------------------
--Get Max unit
function Proximo:GetMaxUnit()
  if db.grow and not in_bg_zone() then
    return self:GetBracketSize()
  else
    return max_unit_size
  end
end

----------------------
--Get bracket unit (code taken from SSArenaFrames)
function Proximo:GetBracketSize()
  local size = max_unit_size
  for i=1, MAX_BATTLEFIELD_QUEUES do
    local status, _, _, _, _, teamSize = GetBattlefieldStatus(i)
    if( status == "active" and teamSize > 0 ) then
      size = teamSize
      break
    end
  end
  return size
end

----------------------
--Get Trinket Icon (code sampled from SSArenaFrames)
function Proximo:GetTrinketIcon(faction, level)
  local trinket
  if(faction == "Horde") then
    trinket = level == 80 and "Interface\\Icons\\INV_Jewelry_Necklace_38" or "Interface\\Icons\\INV_Jewelry_TrinketPVP_02"
  else
    trinket = level == 80 and "Interface\\Icons\\INV_Jewelry_Necklace_37" or "Interface\\Icons\\INV_Jewelry_TrinketPVP_01"
  end
  return trinket
end
