--   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/>. 
-- Pure lua module for controlling, reading and enumerating devices through sysfs
-- Because in Linux we trust.
local syscontrol = {
    power_supply = {},
    backlight = {},
    hwmon = {}
}
syscontrol.backlight.enumerate = function()
    local lshandler = io.popen("ls -1 /sys/class/backlight","r")
    if lshandler then
        local out = lshandler:read("*a")
        lshandler:close()
        local devices = {}
        out:gsub("(%S*)\n",function(a)
            table.insert(devices,a)
        end)
        return devices
    else
        return nil, "Unable to ls /sys/class/backlight"
    end
end
syscontrol.backlight.read_attribs = function(dev_name)
    local fhandler,err = io.open("/sys/class/backlight/"..dev_name.."/brightness","r")
    if fhandler then
        local bhandler = io.open("/sys/class/backlight/"..dev_name.."/max_brightness","r")
        local device = {
            name = dev_name,
            full_path = "/sys/class/backlight/"..dev_name,
            brightness = tonumber(fhandler:read("*a")),
            max_brightness = tonumber(bhandler:read("*a")),
            writable = false
        }
        fhandler:close()
        bhandler:close()
        local wfhandler = io.open("/sys/class/backlight/"..dev_name.."/brightness","w")
        if wfhandler then
            wfhandler:close()
            device.writable = true
        end
        return device
    else
        return nil, err
    end
end
syscontrol.backlight.set_brightness = function(device,brightness)
    if device.writable then
        brightness = tonumber(brightness)
        if (brightness < 0) or (brightness > device.max_brightness) then
            return nil, "Brightness exceeds given limits"
        end
        local fhandler,err = io.open(device.full_path.."/brightness","w")
        if fhandler then
            fhandler:write(tostring(brightness))
            fhandler:close()
            return true
        else
            return nil, err
        end
    else
        return nil, "Device is not writable"
    end
end
syscontrol.power_supply.enumerate = function()
    local lshandler = io.popen("ls -1 /sys/class/power_supply","r")
    if lshandler then
        local out = lshandler:read("*a")
        lshandler:close()
        local devices = {}
        out:gsub("(%S*)\n",function(a)
            table.insert(devices,a)
        end)
        return devices
    else
        return nil, "Unable to ls /sys/class/power_supply"
    end
end
syscontrol.power_supply.read_attribs = function(dev_name)
    local fhandler,err = io.open("/sys/class/power_supply/"..dev_name.."/type","r")
    if fhandler then
        local uevent_f = io.open("/sys/class/power_supply/"..dev_name.."/uevent","r")
        if not uevent_f then
            return nil, "Unable to open uevent file"
        end
        local uevent_data = {}
        local device = {
            type = fhandler:read("*a"):match("%S*"),
            full_path = "/sys/class/power_supply/"..dev_name,
            name = dev_name
        }
        fhandler:close()
        uevent_f:read("*a"):gsub("[^\n]+",function(line)
            local key,value = line:match("^([^=]+)=([^=]*)")
            if value:match("^%d+$") then
                value = tonumber(value)
            end
            uevent_data[key] = value
        end)
        uevent_f:close()
        if device.type == "Battery" then
            device.model = uevent_data.POWER_SUPPLY_MODEL_NAME or "N/A"
            device.energy_full_design = uevent_data.POWER_SUPPLY_ENERGY_FULL_DESIGN
            device.energy_full = uevent_data.POWER_SUPPLY_ENERGY_FULL
            if not device.energy_full_design then
                device.energy_full_design = uevent_data.POWER_SUPPLY_CHARGE_FULL_DESIGN or -1
                device.energy_full = uevent_data.POWER_SUPPLY_CHARGE_FULL or -1
            end
            device.quality = (device.energy_full/device.energy_full_design)*100
            device.capacity = uevent_data.POWER_SUPPLY_CAPACITY or 0
            device.charging = (uevent_data.POWER_SUPPLY_STATUS == "Charging")
        elseif device.type == "Mains" then
            device.online = (uevent_data.POWER_SUPPLY_ONLINE == 1)
        end
        return device
    else
        return nil, err
    end
end
return syscontrol
