--[[

     Lain
     Layouts, widgets and utilities for Awesome WM

     Utilities section

     Licensed under GNU General Public License v2
      * (c) 2013,      Luca CPZ
      * (c) 2010-2012, Peter Hofmann

--]]

local awful        = require("awful")
local sqrt         = math.sqrt
local pairs        = pairs
local client       = client
local tonumber     = tonumber
local wrequire     = require("lain.helpers").wrequire
local setmetatable = setmetatable

-- Lain utilities submodule
-- lain.util
local util = { _NAME = "lain.util" }

-- Like awful.menu.clients, but only show clients of currently selected tags
function util.menu_clients_current_tags(menu, args)
    -- List of currently selected tags.
    local cls_tags = awful.screen.focused().selected_tags

    if cls_tags == nil then return nil end

    -- Final list of menu items.
    local cls_t = {}

    -- For each selected tag get all clients of that tag and add them to
    -- the menu. A click on a menu item will raise that client.
    for i = 1,#cls_tags do
        local t   = cls_tags[i]
        local cls = t:clients()

        for _, c in pairs(cls) do
            cls_t[#cls_t + 1] = { awful.util.escape(c.name) or "",
                                  function ()
                                      c.minimized = false
                                      client.focus = c
                                      c:raise()
                                  end,
                                  c.icon }
        end
    end

    -- No clients? Then quit.
    if #cls_t <= 0 then return nil end

    -- menu may contain some predefined values, otherwise start with a
    -- fresh menu.
    if not menu then menu = {} end

    -- Set the list of items and show the menu.
    menu.items = cls_t
    local m = awful.menu(menu)
    m:show(args)

    return m
end

-- Magnify a client: set it to "float" and resize it.
function util.magnify_client(c, width_f, height_f)
    if c and not c.floating then
        util.magnified_client = c
        util.mc(c, width_f, height_f)
    else
        util.magnified_client = nil
        c.floating = false
    end
end

-- https://github.com/lcpz/lain/issues/195
function util.mc(c, width_f, height_f)
    c = c or util.magnified_client
    if not c then return end

    c.floating   = true
    local s      = awful.screen.focused()
    local mg     = s.workarea
    local g      = {}
    local mwfact = width_f or s.selected_tag.master_width_factor or 0.5
    g.width      = sqrt(mwfact) * mg.width
    g.height     = sqrt(height_f or mwfact) * mg.height
    g.x          = mg.x + (mg.width - g.width) / 2
    g.y          = mg.y + (mg.height - g.height) / 2

    if c then c:geometry(g) end -- if c is still a valid object
end

-- Non-empty tag browsing
-- direction in {-1, 1} <-> {previous, next} non-empty tag
function util.tag_view_nonempty(direction,sc)
    direction  = direction or 1
    local s    = sc or awful.screen.focused()
    local tags = s.tags
    local sel  = s.selected_tag

    local i = sel.index
    repeat
        i = i + direction

        -- Wrap around when we reach one of the bounds
        if i > #tags then
            i = i - #tags
        end
        if i < 1 then
            i = i + #tags
        end

        local t = tags[i]

        -- Stop when we get back to where we started
        if t == sel then
            break
        end

        -- If it's The One, view it.
        if #t:clients() > 0 then
            t:view_only()
            return
        end
    until false
end

-- {{{ Dynamic tagging

-- Add a new tag
function util.add_tag(layout)
    awful.prompt.run {
        prompt       = "New tag name: ",
        textbox      = awful.screen.focused().mypromptbox.widget,
        exe_callback = function(name)
            if not name or #name == 0 then return end
            awful.tag.add(name, { screen = awful.screen.focused(), layout = layout or awful.layout.suit.tile }):view_only()
        end
    }
end

-- Rename current tag
function util.rename_tag()
    awful.prompt.run {
        prompt       = "Rename tag: ",
        textbox      = awful.screen.focused().mypromptbox.widget,
        exe_callback = function(new_name)
            if not new_name or #new_name == 0 then return end
            local t = awful.screen.focused().selected_tag
            if t then
                t.name = new_name
            end
        end
    }
end

-- Move current tag
-- pos in {-1, 1} <-> {previous, next} tag position
function util.move_tag(pos)
    local tag = awful.screen.focused().selected_tag
    if tonumber(pos) <= -1 then
        awful.tag.move(tag.index - 1, tag)
    else
        awful.tag.move(tag.index + 1, tag)
    end
end

-- Delete current tag
-- Any rule set on the tag shall be broken
function util.delete_tag()
    local t = awful.screen.focused().selected_tag
    if not t then return end
    t:delete()
end

-- }}}

-- On the fly useless gaps change
function util.useless_gaps_resize(thatmuch, s, t)
    local scr = s or awful.screen.focused()
    local tag = t or scr.selected_tag
    tag.gap = tag.gap + tonumber(thatmuch)
    awful.layout.arrange(scr)
end

return setmetatable(util, { __index = wrequire })