--
-- Control playing music/media and sound volume
-- Currently supports :
-- - playerctl
-- - Spotify
--

--
-- DEBUG
--
local inspect = require("simple/debug/inspect")

local awful = require("awful")
local beautiful = require("beautiful")
local gears = require("gears")
local naughty = require("naughty")
local wibox = require("wibox")

local hotkey = require("simple/core/hotkey")

local config = require("config")

local hasPlayerctl = os.execute("playerctl -v") == true

-- playerctl
function sendToPlayerctl(command)
    os.execute("playerctl " .. command)
end

-- Spotify
function sendToSpotify(command)
    awful.util.spawn_with_shell("dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player." .. command)
end

-- Volume control
function getVolume()
    if isMuted() then return 0 end
    local handle = io.popen("amixer -D pulse sget Master | awk -F\"[][]\" '/%/ { print $2 }' | head -n 1", "r")
    local volume = string.gsub(handle:read("*a"), "[\n%%]+", "") / 100
    handle:close()
    return volume
end

function isMuted()
    local handle = io.popen("amixer -D pulse sget Master | awk -F\"[][]\" '/[onf]{2,3}/ { print $4 }' | head -n -1", "r")
    local muted = string.gsub(handle:read("*a"), "[\n]+", "") == "off"
    handle:close()
    return muted
end

function getVolumeImage(volume)
    local path = beautiful.volume_osd_icon_3
    if volume < 0.667 then
        path = beautiful.volume_osd_icon_2
    end
    if volume < 0.334 then
        path = beautiful.volume_osd_icon_1
    end
    if volume <= 0 then
        path = beautiful.volume_osd_icon_0
    end
    return gears.color.recolor_image(path, beautiful.volume_osd_image_color)
end

local volumeWibox = wibox({
    ontop = true,
    bg = beautiful.volume_osd_bg,
    border_width = beautiful.volume_osd_border_width,
    border_color = beautiful.volume_osd_border_color,
    shape = beautiful.volume_osd_shape,
    width = beautiful.volume_osd_width,
    height = beautiful.volume_osd_bar_height + beautiful.volume_osd_padding * 3,
    widget = wibox.widget {
        {
            {
                image = getVolumeImage(1),
                widget = wibox.widget.imagebox
            },
            left = beautiful.volume_osd_padding,
            right = beautiful.volume_osd_padding,
            top = beautiful.volume_osd_padding,
            bottom = 0,
            widget = wibox.container.margin,
        },
        {
            {
                {
                    max_value = 1,
                    value = 0.33,
                    shape = gears.shape.rounded_bar,
                    bar_shape = gears.shape.rounded_bar,
                    margins = beautiful.volume_osd_padding + 4,
                    color = beautiful.volume_osd_progress_color,
                    background_color = beautiful.volume_osd_progress_bg,
                    border_color = beautiful.volume_osd_progress_border_color,
                    border_width = beautiful.volume_osd_progress_border_width,
                    widget = wibox.widget.progressbar
                },
                forced_width = 80,
                forced_height = 80,
                direction = "east",
                layout = wibox.container.rotate,
            },
            left = beautiful.volume_osd_padding,
            right = beautiful.volume_osd_padding,
            top = 0,
            bottom = beautiful.volume_osd_padding,
            widget = wibox.container.margin,
        },
        layout = wibox.layout.align.vertical
    },
})

local imagebox = volumeWibox.widget:get_children()[1]:get_children()[1]
local progressbar = volumeWibox.widget:get_children()[2]:get_children()[1]:get_children()[1]

local timer = nil

-- {{{ Control
local playPause = function()
    if hasPlayerctl then
        sendToPlayerctl("play-pause")
    else
        sendToSpotify("PlayPause")
    end
end

local nextTrack = function()
    if hasPlayerctl then
        sendToPlayerctl("next")
    else
        sendToSpotify("Next")
    end
end

local previousTrack = function()
    if hasPlayerctl then
        sendToPlayerctl("previous")
    else
        sendToSpotify("Previous")
    end
end

local displayVolume = function()
    -- Update screen
    local screen = awful.screen:focused()
    volumeWibox.screen = screen

    -- Position
    local position = beautiful.volume_osd_position(screen.geometry.width, screen.geometry.height, beautiful.volume_osd_width, beautiful.volume_osd_height)
    volumeWibox:geometry({
        x = (screen.geometry.x + position[1]),
        y = (screen.geometry.y + position[2])
    })

    -- Get volume
    local volume = getVolume()

    -- Update values
    imagebox.image = getVolumeImage(volume)
    progressbar.value = volume

    -- Show
    volumeWibox.visible = true

    -- Schedule hide
    if timer ~= nil then
        timer:stop()
    end
    timer = gears.timer {
        timeout = config.volume_osd_timeout,
        callback = function()
            volumeWibox.visible = false
            timer:stop()
            timer = nil
        end
    }
    timer:start()
end
local raiseVolume = function()
    os.execute("amixer -D pulse set Master 5%+")
    displayVolume()
end
local lowerVolume = function()
    os.execute("amixer -D pulse set Master 5%-")
    displayVolume()
end
local toggleMute = function()
    local muted = isMuted()
    os.execute("amixer -D pulse set Master " .. (muted and 'on' or 'off'))
    displayVolume()
end
-- }}}

function getKeys(config)
    return
        -- Volume control
    hotkey.make(config.raiseVolume, raiseVolume,
        { description = "Raise volume", group = "media control" }),
    hotkey.make(config.lowerVolume, lowerVolume,
        { description = "Lower volume", group = "media control" }),
    hotkey.make(config.toggleMute, toggleMute,
        { description = "Toggle mute audio", group = "media control" }),

    -- Media control
    hotkey.make(config.playPause, playPause,
        { description = "Toggle Play / Pause", group = "media control" }),
    hotkey.make(config.nextTrack, nextTrack,
        { description = "Next track", group = "media control" }),
    hotkey.make(config.previousTrack, previousTrack,
        { description = "Previous track", group = "media control" })
end

return {
    getKeys = getKeys,
}