--      ████████╗ █████╗ ███████╗██╗  ██╗    ██╗     ██╗███████╗████████╗
--      ╚══██╔══╝██╔══██╗██╔════╝██║ ██╔╝    ██║     ██║██╔════╝╚══██╔══╝
--         ██║   ███████║███████╗█████╔╝     ██║     ██║███████╗   ██║
--         ██║   ██╔══██║╚════██║██╔═██╗     ██║     ██║╚════██║   ██║
--         ██║   ██║  ██║███████║██║  ██╗    ███████╗██║███████║   ██║
--         ╚═╝   ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝    ╚══════╝╚═╝╚══════╝   ╚═╝

-- ===================================================================
-- Initialization
-- ===================================================================


local awful = require('awful')
local wibox = require('wibox')
local gears = require('gears')
local pl = require("utils.powerline")
local theme = require("theme")

local dpi = require('beautiful').xresources.apply_dpi
local capi = {button = button}
local ICON_DIR = gears.filesystem.get_configuration_dir() .. "/images/"

-- define module table
local task_list = {}


-- ===================================================================
-- Functionality
-- ===================================================================


local function create_buttons(buttons, object)
    if buttons then
        local btns = {}
        for _, b in ipairs(buttons) do
            -- Create a proxy button object: it will receive the real
            -- press and release events, and will propagate them to the
            -- button object the user provided, but with the object as
            -- argument.
            local btn = capi.button {modifiers = b.modifiers, button = b.button}
            btn:connect_signal('press',
                function()
                    object.minimized = false
                    object:raise()
                end
            )
            btns[#btns + 1] = btn
        end
        return btns
    end
end


local function list_update(w, buttons, label, _, objects)
    -- update the widgets, creating them if needed
    w:reset()
    local index = 0
    local count = 0
    for _ in pairs(objects) do
        count = count + 1
    end
    local static_length = 16 * count
    local total_text_length = 0
    for _, o in ipairs(objects) do
        if o.name then
            total_text_length = total_text_length + o.name:len()
        end
    end
    local truncate = (total_text_length + static_length) > 170

    for i, o in ipairs(objects) do
        index = index + 1
        local ib, cb, tb, cbm, bgb, tbm, ibm, tt, l, ll
        ib = wibox.widget.imagebox()
        tb = wibox.widget.textbox()
        cb = wibox.container.margin(wibox.widget.imagebox(ICON_DIR .. "close.svg"), dpi(9), dpi(0), dpi(9), dpi(9))
        cb.shape = gears.shape.circle
        cbm = wibox.container.margin(cb, dpi(0), dpi(0), dpi(0), dpi(0)) -- 4, 8 ,12 ,12 -- close button
        cbm:buttons(gears.table.join(awful.button({}, 1, nil,
            function()
                o.kill(o)
            end
        )))
        bgb = wibox.container.background()
        tbm = wibox.container.margin(tb, dpi(4), dpi(4))
        ibm = wibox.container.margin(ib, dpi(5), dpi(5), dpi(5), dpi(5)) -- 12 is default top and bottom margin --app icon
        l = wibox.layout.fixed.horizontal()
        ll = wibox.layout.fixed.horizontal()

        -- All of this is added in a fixed widget
        l:fill_space(true)
        l:add(ibm)
        l:add(tbm)
        ll:add(l)
        ll:add(cbm)

        if (index % 2 == 0) then
            local end_color = (count == index or objects[index+1].minimized) and "" or theme.top_panel_powerline
            local main_color = o.minimized and "" or theme.bg_normal
            bgb:set_widget(pl(ll, main_color, end_color, true))
        else
            local end_color = (count == index or objects[index+1].minimized) and "" or theme.bg_normal
            local main_color = o.minimized and "" or theme.top_panel_powerline
            bgb:set_widget(pl(ll, main_color, end_color, true))
        end

        l:buttons(create_buttons(buttons, o))

        -- Tooltip to display whole title, if it was truncated
        tt = awful.tooltip({
            objects = {tb},
            mode = 'outside',
            align = 'bottom',
            delay_show = 1,
        })

        local text, _, bg_image, icon, args = label(o, tb)
        args = args or {}

        -- The text might be invalid, so use pcall.
        if text == nil or text == '' then
            tbm:set_margins(0)
        else
            -- truncate when title is too long
            local text_only = text:match('>(.*)<')
            local max_length = math.floor((155 - static_length) / count)
            if (truncate and text_only:len() > max_length) then
                text = text:gsub('>(.*)<', '>' .. string.sub(text_only, 1, max_length) .. '...<')
                tt:set_text(text)
                tt:add_to_object(tb)
            else
                tt:remove_from_object(tb)
            end
            if not tb:set_markup_silently(text) then
                tb:set_markup('<i>&lt;Invalid text&gt;</i>')
            end
        end
        -- bgb:set_bg(bg)
        if type(bg_image) == 'function' then
            -- TODO: Why does this pass nil as an argument?
            bg_image = bg_image(tb, o, nil, objects, i)
        end
        -- bgb:set_bgimage(bg_image)
        if icon then
            ib.image = icon
        else
            ibm:set_margins(0)
        end

        w:add(bgb)
    end
end


-- ===================================================================
-- Widget Creation
-- ===================================================================


local tasklist_buttons = awful.util.table.join(
    awful.button({}, 1,
        function(c)
            if c == client.focus then
                c.minimized = true
            else
                -- Without this, the following
                -- :isvisible() makes no sense
                c.minimized = false
                if not c:isvisible() and c.first_tag then
                    c.first_tag:view_only()
                end
                -- This will also un-minimize
                -- the client, if needed
                client.focus = c
                c:raise()
            end
        end
    ),
    awful.button({}, 2,
        function(c)
            c.kill(c)
        end
    ),
    awful.button({}, 4,
        function()
            awful.client.focus.byidx(1)
        end
    ),
    awful.button({}, 5,
        function()
            awful.client.focus.byidx(-1)
        end
    )
)


local filter = function(c, _)
    local tags = c.screen.tags
    for _, t in ipairs(tags) do
        if t.selected then
            local ctags = c:tags()
            for _, v in ipairs(ctags) do
                if v == t and c.screen == client.focus.screen then
                    return true
                end
            end
        end
    end
    return false
end


task_list.create = function(s)
    return awful.widget.tasklist(
        s,
        filter,
        tasklist_buttons,
        {},
        list_update,
        wibox.layout.fixed.horizontal()
    )
end

return task_list
