--   This file is part of Reno desktop.
--
--  Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
--
--  Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
--  You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>. 
--  Pulseaudio per-client volume setting
local awful = require("awful")
local gears = require("gears")
local wibox = require("wibox")
local awmtk2 = require("awmtk2")
local fastyaml = require("parsers").fast_split_yaml
local beautiful = require("beautiful")
local ask = require("asckey")

local test_pactl = os.execute("pactl --version")
local result = test_pactl
if _VERSION:match("5.1") then
    result = (test_pactl == 0)
end
if not result then
    return
end

local function get_icon(percent)
    if percent >= 66 then
        return beautiful["volume-high-symbolic"]
    elseif percent >= 33 then
        return beautiful["volume-medium-symbolic"]
    elseif percent > 0 then
        return beautiful["volume-low-symbolic"]
    else
        return beautiful["volume-muted-symbolic"]
    end
end


return function(args)
    local style = awmtk2.create_style("client_volume",
        awmtk2.generic.oneline_widget, args.style,args.vertical)
    local templates = awmtk2.create_template_lib("client_volume",awmtk2.templates,args.templates)
    local t = awmtk2.build_templates(templates,style,args.vertical)
    local widget = wibox.widget(t.container({
        t.icon({
            id = "client_volume_icon",
            resize = true,
        }),
        (args.vertical and {
            t.textbox({
                id = "error"
            }),
            widget = wibox.container.rotate,
            direction = "east"
        }) or t.textbox({
            id = "error"
        }),
        t.slider({
            minimum = 0,
            maximum = 100,
            id = "client_volume",
            value = -1
        }),
        layout = (args.vertical and wibox.layout.fixed.vertical) or
            wibox.layout.fixed.horizontal
    }))
    local errorbox = widget:get_children_by_id("error")[1]
    local icon = widget:get_children_by_id("client_volume_icon")[1]
    local slider = widget:get_children_by_id("client_volume")[1]
    -- Local tracking value to prevent zero volume on start
    local touched = false
    -- Attach to focus change
    client.connect_signal("update_volume",function(c)
        awful.spawn.easy_async("pactl list sink-inputs",function(stdout)
            local pactl_data = fastyaml(stdout)
            local cl
            for _,v in pairs(pactl_data) do
                if not c then return end
                if v:match("application.process.id = \""..tostring(c.pid).."\"") then
                    cl = v
                end
            end
            if not cl then
                slider.visible = false
                errorbox.visible = true
                errorbox:set_markup("No sound/Not available")
                icon:set_image(beautiful["volume-muted-symbolic"])
                return
            end
            local volume = tonumber(cl:match("Volume:[^\n]-(%d*)%%"))
            slider.visible = true
            errorbox.visible = false
            icon:set_image(get_icon(volume))
            slider.value = volume
            touched = true
        end)
    end)
    client.connect_signal("focus",function(c)
        touched = false
        c:emit_signal("update_volume")
    end)
    local update_timer = gears.timer({
        timeout = 0.5,
        autostart = true,
        callback = function()
            if client.focus then
                client.focus:emit_signal("update_volume")
            end
        end
    })
    -- Async lock to prevent callback interference
    local volume_lock = false
    -- Function to set client volume
    local function volume(value)
        if volume_lock then return end
        volume_lock = true
        awful.spawn.easy_async("pactl list sink-inputs",function(stdout)
            local pactl_data = fastyaml(stdout)
            if not (client.focus and client.focus.pid) then
                volume_lock = false
                return
            end
            for _,v in pairs(pactl_data) do
                if v:match("application.process.id = \""..tostring(client.focus.pid).."\"") then
                    local sink_id = v:match("^%s*Sink Input #(%d+)")
                    if sink_id then
                        print(sink_id, value)
                        awful.spawn("pactl set-sink-input-volume "..tostring(sink_id).." "..tostring(value).."%")
                    end
                end
            end
            volume_lock = false
        end)
    end
    -- Attach change to slider
    slider:connect_signal("widget::redraw_needed",function()
        if touched then
            volume(slider.value)
            update_timer:again()
        end
    end)
    root.keys(gears.table.join(
        root.keys(),
        ask.k(":client.volume_up", function()
            volume("+5")
        end,{description = "increase client volume", group = "client"}),
        ask.k(":client.volume_down", function()
            volume("-5")
        end,{description = "decrease client volume", group = "client"}),
        ask.k(":client.volume_mute", function()
            volume(0)
        end,{description = "mute client", group = "client"})
    ))
    return widget
end
