--[[---------------------------------------------------------------------------
    Name: phRaid
    Author: pherl <pherl@live.com>
-----------------------------------------------------------------------------]]

local L = AceLibrary("AceLocale-2.2"):new("phRaid")

function phRaid:ShowTooltip(frame)
    local name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(frame.id);
    if level == 0 then level = "??" end
    GameTooltip:SetOwner(frame)
    GameTooltip:AddDoubleLine(name, level, RAID_CLASS_COLORS[fileName].r, RAID_CLASS_COLORS[fileName].g, RAID_CLASS_COLORS[fileName].b, 1, 1, 1)
    GameTooltip:AddLine(UnitRace(frame.unit) .. " " .. class, 1, 1, 1);
    GameTooltip:AddLine(zone, 1, 1, 1);
    GameTooltip:Show()
end

local function OnDragStart()
    if not phRaid.db.profile.Lock or phRaid.db.profile.AltDragAlways and IsAltKeyDown() then
        this:GetParent():StartMoving()
        if not phRaid.moving then phRaid.moving = {} end
        phRaid.moving[phRaid.visible[this.unit]] = true
    else
        phRaid:Print(L["LockedHint"])
    end
end

local function OnDragStop()
    this:GetParent():StopMovingOrSizing()
    phRaid:SavePosition()
end

local function OnEnter()
    if phRaid.db.profile.ShowTooltip and (not phRaid.db.profile.HideWhenCombat or not UnitAffectingCombat("player")) then
        phRaid:ShowTooltip(this)
    end
    if not this.Highlight.shown then
        this.Highlight:SetVertexColor(0, 0, 0)
        this.Highlight:Show()
    end
    this.Highlight.mouseover = true
end

local function OnLeave()
    GameTooltip:Hide()
    if not this.Highlight.shown then
        this.Highlight:Hide()
    end
    this.Highlight.mouseover = false
end

function phRaid:CreateOneUnitFrame(parent)
    local texture = self.BARTEXTURE[self.db.profile.FrameStyle.BarTexture]
    local f = CreateFrame("Button", nil, parent)

    f:SetMovable(true)
    f:SetClampedToScreen(true)
    f:EnableMouse(true)

    -- SubFrames
    local bar = CreateFrame("StatusBar", nil, f)
    bar:SetParent(f)
    bar:SetMinMaxValues(0, 100)
    bar:SetStatusBarTexture(texture)
    f.HPBar = bar

    bar = CreateFrame("StatusBar", nil, f)
    bar:SetParent(f)
    bar:SetMinMaxValues(0, 100)
    bar:SetStatusBarTexture(texture)
    f.MPBar = bar

    --Textures and FontStrings
    local font = f:CreateFontString(nil, "OVERLAY")
    font:SetFontObject(GameFontHighlightSmall)
    f.Group = font

    font = f:CreateFontString(nil, "OVERLAY")
    font:SetFontObject(GameFontNormalSmall)
    f.Name = font

    font = f.HPBar:CreateFontString(nil, "OVERLAY")
    font:SetFontObject(GameFontHighlightSmall)
    font:SetText("??")
    f.HP = font

    font = f:CreateFontString(nil, "OVERLAY")
    font:SetFontObject(GameFontNormalSmall)
    f.Status = font

    local aggro = f:CreateTexture(nil, "OVERLAY")
    aggro:SetTexture("Interface\\Addons\\phRaid\\textures\\phRaidAggroHighlight")
    aggro:Hide()
    f.Aggro = aggro

    local mark = f:CreateTexture(nil, "ARTWORK")
    mark:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons")
    mark:SetWidth(12)
    mark:SetHeight(12)
    mark:Hide()
    f.Mark = mark

    local t = f.HPBar:CreateTexture(nil, "BACKGROUND")
    t:SetTexture(texture)
    f.HPBG = t

    t = f.MPBar:CreateTexture(nil, "BACKGROUND")
    t:SetTexture(texture)
    t:SetVertexColor(0.6, 0.6, 0.6, 0.8)
    f.MPBG = t

    border = CreateFrame("StatusBar", nil, f)
    border:SetMinMaxValues(0,100)
    border:SetStatusBarTexture("Interface/Tooltips/UI-Tooltip-Background")
    border:SetStatusBarColor(0,0,0,1)
    border:ClearAllPoints()
    border:SetPoint("TOP", f.HPBar, "TOP", 0, 1)
    border:SetPoint("LEFT", f.HPBar, "LEFT", -1, 0)
    border:SetPoint("RIGHT", f.HPBar, "RIGHT", 1, 0)
    border:SetPoint("BOTTOM", f.MPBar, "BOTTOM", -1, 0)
    border:SetFrameLevel(f.HPBar:GetFrameLevel() - 1)
    f.Border = border

    local t = f:CreateTexture(nil, "BACKGROUND")
    t:SetTexture("Interface\\AddOns\\phRaid\\textures\\phRaidHighlight")
    t:ClearAllPoints()
    t:Hide()
    f.Highlight = t

    f.Buff = CreateFrame("Frame", nil, f)
    f.Buff.frames = {}
    f.Buff.num = 0

    f:RegisterForClicks("LeftButtonUp", "RightButtonUp", "MiddleButtonUp", "Button4Up", "Button5Up")
    f:RegisterForDrag("LeftButton")
    f:SetScript("OnDragStart", OnDragStart)
    f:SetScript("OnDragStop", OnDragStop)
    f:SetScript("OnEnter", OnEnter)
    f:SetScript("OnLeave", OnLeave)
    f:SetScript("OnClick", self.OnClick)
    f:SetScript("OnUpdate", UnitFrame_OnUpdate)
    return f
end

function phRaid:UpdateOneUnitFrameLayout(f)
    local opt = self.db.profile.FrameStyle
    local barWidth, nameWidth, stautsWidth, frameWidth, frameHeight
    local nameX, nameY, hpbarX, hpbarY, mpbarX, mpbarY
    local manaHeight = opt.MPBarHeight
    f.Name:ClearAllPoints()
    f.Status:ClearAllPoints()
    f.Buff:ClearAllPoints()
    f.Mark:ClearAllPoints()
    if f.class then
        if opt.ShowMana and (opt.EnableAllTypeMP or f.class ~= "WARRIOR" and f.class ~= "ROGUE") then
            f.MPBar:Show()
            f.MPBG:Show()
            manaHeight = opt.MPBarHeight
        else
            f.MPBar:Hide()
            f.MPBG:Hide()
            manaHeight = 0
        end
    end
    f.Name:SetWidth(opt.NameWidth)
    nameWidth = f.Name:GetStringWidth()

    if opt.Layout == L["Single Line Mode"] then
        barWidth = opt.BarWidth
        statusWidth = opt.StatusWidth
        statusJustH = "LEFT"
        nameX, nameY = 1, 1 + manaHeight
        if opt.NameOnBar then
            f.Name:SetPoint("BOTTOMLEFT", f.HPBar, "BOTTOMLEFT")
            frameWidth = barWidth + statusWidth
            nameJustH = "LEFT"
            hpbarX, hpbarY = nameX +  1, nameY
            mpbarX, mpbarY = nameX +  1, 1
        else
            f.Name:SetPoint("BOTTOMRIGHT", f.HPBar, "BOTTOMLEFT")
            frameWidth = barWidth + opt.NameWidth + statusWidth
            nameJustH = "RIGHT"
            hpbarX, hpbarY = nameX + opt.NameWidth + 1, nameY
            mpbarX, mpbarY = nameX + opt.NameWidth + 1, 1
        end
        frameHeight = opt.HPBarHeight + manaHeight + 3
        f.Mark:SetPoint("RIGHT", f.Group, "LEFT", 0, 0)
        f.Buff:SetPoint("LEFT", f.HPBar, "RIGHT", 1, 0)
        f.Status:SetPoint("LEFT", f.Buff, "RIGHT", -1, 0)
        f.Status:SetHeight(opt.HPBarHeight)
        f.Name:SetHeight(opt.HPBarHeight)
        f.Group:SetHeight(opt.HPBarHeight)
    else
        barWidth = opt.BarWidth
        statusWidth = opt.StatusWidth
        statusJustH = "LEFT"
        frameWidth = barWidth + 2
        frameHeight = opt.HPBarHeight + manaHeight + 15
        f.Name:SetPoint("BOTTOMLEFT", f.HPBar, "TOPLEFT")
        nameX, nameY = 1, opt.HPBarHeight + manaHeight + 1
        nameJustH = "LEFT"
        hpbarX, hpbarY = 1, manaHeight + 1
        mpbarX, mpbarY = 1, 1
        
        f.Mark:SetPoint("RIGHT", f.HPBar, "LEFT", 0, -1)
        f.Buff:SetPoint("BOTTOMLEFT", f.HPBar, "TOPRIGHT", 1, 0)
        f.Status:SetPoint("LEFT", f.HP, "RIGHT", 1, 0)
        f.Status:SetHeight(13)
        f.Name:SetHeight(13)
        f.Group:SetHeight(13)
    end

    f:SetWidth(frameWidth)
    f:SetHeight(frameHeight)

    f.HPBar:SetWidth(barWidth)
    f.HPBar:SetHeight(opt.HPBarHeight)
    f.HPBar:ClearAllPoints()
    f.HPBar:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", hpbarX, hpbarY)
    f.HPBG:SetWidth(barWidth)
    f.HPBG:SetHeight(opt.HPBarHeight)
    f.HPBG:ClearAllPoints()
    f.HPBG:SetPoint("BOTTOMLEFT", f.HPBar, "BOTTOMLEFT")

    f.MPBar:SetWidth(barWidth)
    f.MPBar:SetHeight(manaHeight)
    f.MPBar:ClearAllPoints()
    f.MPBar:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", mpbarX, mpbarY)
    f.MPBG:SetWidth(barWidth)
    f.MPBG:SetHeight(manaHeight)
    f.MPBG:ClearAllPoints()
    f.MPBG:SetPoint("BOTTOMLEFT", f.MPBar, "BOTTOMLEFT", 0, 0)

    f.Name:SetWidth(nameWidth)
    f.Name:SetJustifyH(nameJustH)

    f.Group:ClearAllPoints()
    f.Group:SetPoint("RIGHT", f.Name, "LEFT", -5, 0)
    f.Group:SetWidth(13)
    f.Group:SetJustifyH("RIGHT")
    if opt.ShowGroup then f.Group:Show() else f.Group:Hide() end

    f.HP:ClearAllPoints()
    f.HP:SetPoint("RIGHT", f.HPBar, "RIGHT", 0, 0)
    f.HP:SetHeight(opt.HPBarHeight)
    f.HP:SetWidth(barWidth)
    f.HP:SetJustifyH("RIGHT")

    f.Highlight:ClearAllPoints()
    f.Highlight:SetPoint("LEFT", f, "LEFT", 0, 0)
    f.Highlight:SetPoint("RIGHT", f, "RIGHT", 0, 0)
    f.Highlight:SetHeight(frameHeight)

    f.Status:SetWidth(statusWidth)
    f.Status:SetJustifyH(statusJustH)

    f.Aggro:ClearAllPoints()
    f.Aggro:SetPoint("LEFT", f, "LEFT", -2, 0)
    f.Aggro:SetPoint("RIGHT", f, "RIGHT", 2, 0)
    f.Aggro:SetHeight(frameHeight + 3)

    f.Buff:SetHeight(opt.BuffSize)
    for i = 1, f.Buff.num do
        f.Buff.frames[i]:SetWidth(opt.BuffSize)
        f.Buff.frames[i]:SetHeight(opt.BuffSize)
    end
end

function phRaid:UpdateAllUnitFrameLayout()
    for i = 1, 40 do
        local frame = self.frames[self.RAIDUNIT[i]]
        if not frame then return end
        self:UpdateOneUnitFrameLayout(frame)
    end
end

function phRaid:LinkFrameToUnit(f, unit, name, class, group)
    local opt = self.db.profile.FrameStyle
    f.name = name
    f.group = group
    f.class = class
    f.Group:SetText(group)
    f.Name:SetText(self.CLASSCOLOR[class] .. name)
    local mpcolor = ManaBarColor[UnitPowerType(unit)]
    f.MPBar:SetStatusBarColor(mpcolor.r, mpcolor.g, mpcolor.b)
    self:UpdateOneUnitFrameLayout(f)
end

function phRaid:OnClick()
    local unit = this.unit
    local button = arg1
    if phRaid.db.profile.ClickHeal then
        if Clique and Clique:OnClick(button, unit) then
        return
        elseif CastParty and CastParty.Event then -- CastParty v4
            CastParty.Event.OnClickByUnit(button, unit)
            return
        elseif CastParty_OnClickByUnit and CastPartyConfig then -- CastParty Old
            local function CastParty_BuildActionKey(button)
                local action_key = ""
                if IsAltKeyDown() then
                    action_key = action_key .. 'Alt'
                end
                if IsControlKeyDown() then
                    action_key = action_key .. 'Ctrl'
                end
                if IsShiftKeyDown() then
                    action_key = action_key .. 'Shift'
                end
                if action_key == "" then
                    action_key = "None"
                end
                return action_key
            end

            local action_key = CastParty_BuildActionKey()
            local action = CastPartyConfig.key_bindings[button][action_key]

            if (action ~= "CastParty_WoWDefaultClick" and action ~= "CastParty_PartyDropDown" and action ~= CASTPARTY_KEYBINDINGS_NONE) then
                CastParty_OnClickByUnit(button, unit)
                return true
            end
        elseif Heart_MouseHeal then					-- Heart
            if Heart_MouseHeal(unit, button) then
                return
            end
        elseif (JC_CatchKeyBinding) then				-- JustClick
            if JC_CatchKeyBinding(button, unit) then
                return
            end
        elseif (CH_Config and CH_Config.PCUFEnabled and CH_UnitClicked) then	-- Click Heal
            local mb = CH_BuildMouseButton(button)
            actionType = CH_MouseSpells.Friend[mb]
            if (actionType ~= "MENU" and actionType ~= "TARGET" and actionType ~= "TOOLTIP") then
                CH_UnitClicked(unitid, button)
                return true
            end        
        elseif (SmartHeal) then
            if (SmartHeal.Loaded and SmartHeal:getConfig("enable", "clickmode")) then
                local KeyDownType = SmartHeal:GetClickHealButton();
                if(KeyDownType and KeyDownType ~= "undetermined") then
                    SmartHeal:ClickHeal(KeyDownType..button, unit);
                else
                    SmartHeal:DefaultClick(button, unit);
                end
                return;
            end
        end
    end

    if button == "LeftButton" then
        if not UnitExists(unit) then return end
        if SpellIsTargeting() then
            SpellTargetUnit(unit)
            return
        end
        if CursorHasItem() then
            if unit == "player" then AutoEquipCursorItem()
            else DropItemOnUnit(unit) end
            return
        end
        TargetUnit(unit)
    elseif button == "RightButton" then
        if IsAltKeyDown() then
            phRaid.dewdrop:Open(phRaid.main, "cursorX", true, "cursorY", true)
        else
            phRaid:Print(L["AltConfig"])
        end
    end    
end

function phRaid:CreateMainFrame(name)
    local f = CreateFrame("Frame", name, UIParent)
    f:SetMovable(false)
    return f
end

function phRaid:CreateRegionFrames()
    local regions = {}
    local regionFrames = {}
    for i = 1, self.MAXREGION do
        local f = CreateFrame("Frame", "fphRaidRegion" .. i, self.main)
        f:SetMovable()
        regionFrames[i] = f
        regions[i] = {}
        regions[i].numToShow = 0
        regions[i].sortFunctions = {}
        regions[i].groups = {}
    end
    return regions, regionFrames
end

function phRaid:RestorePosition()
    local f = self.main
    f:SetHeight(100)
    f:SetWidth(100)
    f:ClearAllPoints()
    f:SetPoint("CENTER", UIParent, "CENTER")

    for i = 1, self.MAXREGION do
        local rf = self.regionFrames[i]
        rf:ClearAllPoints()
        rf:SetHeight(100)
        rf:SetWidth(100)
        local x = self.db.profile.Regions[i].PosX
        local y = self.db.profile.Regions[i].PosY
        if not x or not y then
            rf:SetPoint("CENTER", UIParent, "CENTER", -200 + 80 * i, 200 - 400 * math.floor((i - 1) / 5))
        else
            local s = rf:GetEffectiveScale()
            x, y = x / s, y / s
            rf:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
        end
    end
end

function phRaid:SavePosition()
    for i = 1, self.MAXREGION do
        local f = self.regionFrames[i]
        local x, y = f:GetLeft(), f:GetTop()
        local s = f:GetEffectiveScale()
        x, y = x * s, y * s
        self.db.profile.Regions[i].PosX = x
        self.db.profile.Regions[i].PosY = y
    end
end

function phRaid:GetHPColor(percent)
    if percent <= 0 or percent > 1.0 then return 0.09, 0.49, 0.03 end
    if percent >= 0.5 then
        return (1.0 - percent)* 2, 1.0, 0.0
    else
        return 1.0, percent * 2, 0.0
    end
end

function phRaid:ParseColorText(c)
    return string.format("|cff%02x%02x%02x", 255 * c.r, 255 * c.g, 255 * c.b)
end

-- Minimap Icon
function phRaid.MiniOnClick()
    local button = arg1
    if button == "LeftButton" then
        if phRaid.main:IsVisible() then
            phRaid:Print(L["HideDone"])
            phRaid.main:Hide()
        else
            phRaid:Print(L["ShowDone"])
            phRaid.main:Show()
        end
    else
        phRaid.dewdrop:Open(phRaid.main, "cursorX", true, "cursorY", true)
    end
end

function phRaid:MiniUpdatePosition()
    local degree = self.db.profile.MiniPos
    self.mini:SetPoint("TOPLEFT", Minimap, "TOPLEFT", 54 - 78 * cos(degree), 78 * sin(degree) - 55)
    if phRaid.db.profile.ShowMini then
        self.mini:Show()
    else
        self.mini:Hide()
    end
end

function phRaid:MiniSetPosition(v)
    if v < 0 then v = v + 360 end
    phRaid.db.profile.MiniPos = v
    phRaid:MiniUpdatePosition()
end

function phRaid.MiniDragging()
	local xpos, ypos = GetCursorPosition()
	local xmin, ymin = Minimap:GetLeft(), Minimap:GetBottom()

	xpos = xmin - xpos / UIParent:GetScale() + 70
	ypos = ypos / UIParent:GetScale() - ymin - 70

	phRaid:MiniSetPosition(math.deg(math.atan2(ypos, xpos)))
end

function phRaid:CreateMiniButton()
    local mini = CreateFrame("Button", "phRaidMiniButton", Minimap)
    mini:SetFrameLevel(5)
    local texture = mini:CreateTexture(nil, "ARTWORK")
    texture:SetTexture("Interface\\Addons\\phRaid\\textures\\ph")
    mini:SetHeight(32)
    mini:SetWidth(32)
    texture:SetHeight(32)
    texture:SetWidth(32)
    texture:SetPoint("TOPLEFT", mini, "TOPLEFT")
    mini:SetScript("OnClick", phRaid.MiniOnClick)
    mini:SetScript("OnDragStart", function()
        if IsAltKeyDown() then
            this:SetScript("OnUpdate", phRaid.MiniDragging)
        end
    end)
    mini:SetScript("OnDragStop", function()
        this:SetScript("OnUpdate", nil)
    end)
    mini:SetScript("OnEnter", function()
        GameTooltip:SetOwner(this, "ANCHOR_LEFT")
        GameTooltip:SetText("phRaid", 1, 1, 1)
        GameTooltip:AddLine(L["LeftClickToggle"])
        GameTooltip:AddLine(L["RightClickConfig"])
        GameTooltip:AddLine(L["AltDragMini"])
        GameTooltip:Show()
    end)
    mini:SetScript("OnLeave", function()
        GameTooltip:Hide()
    end)
    mini:RegisterForDrag("LeftButton")
    mini:RegisterForClicks("LeftButtonUp", "RightButtonUp")
    return mini
end
