Prat:AddModuleToLoad(function()

    local SMFHax = Prat:NewModule("SMFHax", "AceHook-3.0")

    SMFHax.fs_pool = {}

    local new, del
    do
        local wipe = wipe
        local cache = setmetatable({}, { __mode = 'k' })
        function new()
            local t = next(cache)
            if t then
                cache[t] = nil
                return t
            else
                return {}
            end
        end

        function del(t)
            wipe(t)
            cache[t] = true
            return nil
        end
    end

    function SMFHax:OnModuleEnable()
        self:RawHook("ChatFrame_OnUpdate", true)
    end

    function SMFHax:OnModuleDisable()
        self:UnhookAll()

        self:ClearColumn1()
    end

    function SMFHax:ClearColumn1()
        for k, v in pairs(self.fs_pool) do
            for k2, v2 in pairs(v) do
                v2:SetText("")
            end
        end

        for k, v in pairs(Prat.HookedFrames) do
            if v:IsShown() then
                v:Hide()
                v:Show()
            end
        end
    end

    function SMFHax:ChatFrame_OnUpdate(this, ...)
        --   self:ReflowFontStrings(this, ...)

        if not IsCombatLog(this) then
            self:SplitFontStrings(this, this:GetRegions())
        end

        self.hooks["ChatFrame_OnUpdate"](this, ...)
    end


    -- used for flowing text around a button which is on the frame
    local avoid_frames = {}

    -- used for flowing text around a button which is on the frame
    local function intersects_pts(o1t, o1b, o2t, o2b)
        -- above
        local above = o1t > o2t and o1b > o2t
        -- below
        local below = o1t < o2b and o1b < o2b
        -- either one true and we dont intersect
        return not (above or below)
    end

    -- used for flowing text around a button which is on the frame
    local function intersects_line(line, frame)
        return intersects_pts(line:GetTop(), line:GetBottom(), frame:GetTop(), frame:GetBottom())
    end

    local function getAvoidFrames(frame)
        local id = frame:GetID()
        local af = avoid_frames[id]
        if af then
            return af
        end

        avoid_frames[id] = {}
        af = avoid_frames[id]
        af.cfup = _G["ChatFrame" .. id .. "UpButton"]
        af.cfdown = _G["ChatFrame" .. id .. "DownButton"]
        af.cfbottom = _G["ChatFrame" .. id .. "BottomButton"]
        af.cfreminder = _G["ChatFrame" .. id .. "ScrollDownReminder"]

        if ChatFrameMenuButton:IsShown() then
            af.menu = ChatFrameMenuButton
        end

        return af
    end

    function SMFHax:SplitFontStrings(this, ...)
        local fs
        local tmp = this.visibleLines
        local af = getAvoidFrames(this)
        local last, pool
        for n, o in ipairs(tmp) do
            if not self.fs_pool[this:GetID()] then
                self.fs_pool[this:GetID()] = {}
            end
            pool = self.fs_pool[this:GetID()]

            if self.twocolumn then
                if not pool[n] then
                    pool[n] = this:CreateFontString(this:GetName() .. "LeftExtra" .. n)
                    pool[n]:SetJustifyV("TOP")
                end
            end


            if o:GetNumPoints() ~= 0 then
                local l = o:GetText()
                if l then
                    fs = pool[n]
                    if self.twocolumn then

                        fs:ClearAllPoints()
                        o:ClearAllPoints()

                        if not last then
                            fs:SetPoint("BOTTOMLEFT", this, "BOTTOMLEFT", 0, 0)
                        else
                            fs:SetPoint("BOTTOMLEFT", last, "TOPLEFT", 0, 0)
                        end

                        fs:SetFont(o:GetFont())


                        -- /print (select(2,ChatFrame1:GetRegions())):GetText():match("^\124c00000000\124r(.*)")
                        last = fs
                        local s
                        local e = l:match("^(\124c00000000\124r.*)")
                        if not e then
                            s, e = l:match("^(.-)(\124c00000000\124r.*)")
                        end

                        l = e or l

                        if s then fs:SetText(s) elseif not e then fs:SetText("") end
                        o:SetText(l)

                        self:ReflowFontString(this, o, fs, "BOTTOMRIGHT", this, "RIGHT", af)
                        o:SetPoint("BOTTOMLEFT", fs, "BOTTOMRIGHT", 0, 0)

                        o:SetPoint("RIGHT", this, "RIGHT", 0, 0)

                        -- Ensure proper text wrappring
                        o:SetWidth(o:GetRight() - o:GetLeft())
                    else
                        self:ReflowFontString(this, o, this, "DONTCLEAR", this, "RIGHT", af)
                    end

                    if fs then
                        fs:SetHeight(o:GetHeight())
                        o:SetJustifyV("TOP")
                    end

                    -- Playerlink hover-fade effect
                    if self.overPlayer then
                        if l:match("player:" .. self.overPlayer) then
                            o:SetAlpha(1)
                            if not o:IsShown() and o:GetTop() < this:GetTop() then
                                o.restoreTo = 0
                                o:Show()
                            end
                        else
                            if o.restoreTo == 0 then
                                o:Hide()
                                o.restoreTo = nil
                            else
                                o:SetAlpha(0.50)
                                o.restoreTo = 1
                            end
                        end
                    else
                        if o.restoreTo == 0 then
                            o:Hide()
                            o.restoreTo = nil
                        elseif o.restoreTo == 1 then
                            o.restoreTo = nil
                            o:SetAlpha(1)
                        end
                    end

                    if self.twocolumn then
                        fs:SetAlpha(o:GetAlpha())
                        fs:SetTextColor(o:GetTextColor())
                        fs:SetShadowColor(o:GetShadowColor())
                        fs:SetShadowOffset(o:GetShadowOffset())

                        if fs:GetTop() > this:GetTop() or l:trim():len() == 0 then
                            fs:Hide()
                        end

                        if o:GetTop() > this:GetTop() then
                            o:Hide()
                        else
                            o:Show()
                        end

                        if o:IsShown() then
                            fs:Show()
                        else
                            fs:Hide()
                        end
                    end
                end
            end
        end
    end


    -- flow text around a frame which is also on the chatframe
    function SMFHax:ReflowFontString(frame, fontstring, leftanchor, leftanchorpt, rightanchor, rightanchorpt, avoidframes)
        local found = false

        if leftanchorpt and leftanchorpt ~= "DONTCLEAR" then
            fontstring:ClearAllPoints()

            fontstring:SetPoint("BOTTOMLEFT", leftanchor, leftanchorpt, 0, 0)
        end

        for k, v in pairs(avoidframes) do
            if v:IsVisible() and intersects_line(fontstring, v) then
                fontstring:SetPoint("RIGHT", v, "LEFT", 0, 0)
                found = true
                break
            end
        end

        if not found then
            fontstring:SetPoint("RIGHT", rightanchor, rightanchorpt, 0, 0)
        end

        fontstring:SetWidth(fontstring:GetRight() - fontstring:GetLeft())

        if fontstring:GetTop() > frame:GetTop() then
            fontstring:Hide()
        else
            fontstring:Show()
        end
    end

    Prat:AddModuleExtension(function()
        local module = Prat.Addon:GetModule("Timestamps", true)

        if not module then return end

        local L = module.PL

        module.pluginopts["TwoColumnFrames"] = {
            twocolumn = {
                type = "toggle",
                name = L["twocolumn_name"],
                desc = L["twocolumn_desc"],
                order = 185
            }
        }

        local orgOME = module.OnModuleEnable
        function module:OnModuleEnable(...)
            orgOME(self, ...)

            if self.db.profile.twocolumn then
                SMFHax:Enable()
                SMFHax.twocolumn = true
            end
        end

        function module:PlainTimestampNotAllowed()
            return SMFHax.twocolumn
        end

        local ovc = module.OnValueChanged
        function module:OnValueChanged(info, b)
            ovc(self, info, b)

            if info[#info] == "twocolumn" then
                if SMFHax.twocolumn ~= b then
                    SMFHax.twocolumn = b
                    if b then
                        SMFHax:Enable()
                    else
                        SMFHax:ClearColumn1()
                    end
                end
            end
        end
    end) -- Module Extension


    Prat:AddModuleExtension(function()
        local module = Prat.Addon:GetModule("PlayerNames", true)

        if not module then return end

        local L = module.PL

        module.pluginopts["HoverHilight"] = {
            hoverhilight = {
                type = "toggle",
                name = L["hoverhilight_name"],
                desc = L["hoverhilight_desc"],
                order = 230
            }
        }


        local function hoverOnHyperlinkEnter(frame, link, ...)
            local linktype = link:match("^([^:]+)")
            if linktype == "player" then
                SMFHax.overPlayer = link:match("^[^:]+:([^:%]||-]+)")
            end
        end

        local function hoverOnHyperlinkLeave(frame, ...)
            SMFHax.overPlayer = nil
        end

        local function hoverHilight(enable)
            if (enable) then
                SMFHax:Enable()
                for k, v in pairs(Prat.HookedFrames) do
                    SMFHax:HookScript(v, "OnHyperlinkEnter", hoverOnHyperlinkEnter)
                    SMFHax:HookScript(v, "OnHyperlinkLeave", hoverOnHyperlinkLeave)
                end
            else
                for k, v in pairs(Prat.HookedFrames) do
                    SMFHax:Unhook(v, "OnHyperlinkEnter")
                    SMFHax:Unhook(v, "OnHyperlinkLeave")
                end
            end
        end

        local orgOME = module.OnModuleEnable
        function module:OnModuleEnable(...)
            orgOME(self, ...)

            if self.db.profile.hoverhilight then
                hoverHilight(true)
            end
        end

        local ovc = module.OnValueChanged
        function module:OnValueChanged(info, b)
            ovc(self, info, b)

            if info[#info] == "hoverhilight" then
                hoverHilight(b)
            end
        end
    end) -- Module Extension

    return
end) -- Prat:AddModuleToLoad