#!/usr/bin/env lua

local jsonc = require 'luci.jsonc'
local operations = {}
require "pl"

operations["status"] = {}
operations["status"]["interface"] = "string"
operations["interfaces"] = {}

sfp_status = {}
function get_sfp_data(ifname, debugfspath)
    local statefile = file.read(debugfspath .. "state")
    if (statefile == nil) then
        return false
    end
    local state_lines = stringx.splitlines(statefile)
    local present = false
    local has_rxlos = false
    local has_txfault = false
    local link_up = false
    for i,line in ipairs(state_lines) do
        local linekey,lineval = line:match("([%w _]+): (.+)")
        if (linekey ~= nil) and (lineval ~= nil) then
            if (linekey == "Module state") then
                present = (lineval == "present")
            elseif (linekey == "rx_los") then
                has_rxlos = (lineval == "1")
            elseif (linekey == "tx_fault") then
                has_txfault = (lineval == "1")
            elseif (linekey == "Main state") then
                link_up = (lineval == "link_up")
            end
        end
    end
    local this_sfp_status_dict = {}
    this_sfp_status_dict["present"] = present
    if (present) then
        this_sfp_status_dict["rxlos"] = has_rxlos
        this_sfp_status_dict["txfault"] = has_txfault
    end
    this_sfp_status_dict["link_up"] = link_up
    sfp_status[ifname] = this_sfp_status_dict
    return true, present, has_rxlos, has_txfault
end


function list_sfp_interfaces()
    board_file = file.read("/etc/sfp.json")
    if (board_file == nil) then
        return {}
    end
    parsed_board_file = jsonc.parse(board_file)
    if (parsed_board_file["sfp"] == nil) then
        return {}
    end
    local sfp_data = parsed_board_file["sfp"]
    local return_data = {}
    for k,v in pairs(sfp_data) do
        local this_interface = k
        local this_interface_data = {}
        if (v["debugfs"] ~= nil) then
            local has_debugfs, present = get_sfp_data(this_interface,v["debugfs"])
            if (has_debugfs == true) then
                this_interface_data["present"] = present
            end
        end
        return_data[this_interface] = this_interface_data
    end
    return return_data
end

function get_ethtool_output(interface)
    return_wrapper = {}
    local ethtool_success, ethtool_return, ethtool_stdout,
        ethtool_stderr = utils.executeex("ethtool --json -m \"" .. utils.quote_arg(interface) .. "\"")


    if (sfp_status[interface] ~= nil) then
        return_wrapper["status"] = sfp_status[interface]
    end
    if (ethtool_success == true) then
        local parsed_ethtool_output = jsonc.parse(ethtool_stdout)
        if (#parsed_ethtool_output == 1) then
            return_wrapper["ethtool"] = parsed_ethtool_output[1]
        end
    end
    return return_wrapper
end

local op = arg[1]
if (op == "list") then
    local op_json = jsonc.stringify(operations)
    op_json = op_json:gsub("%[%]","{}")
    print(op_json)
elseif (op == "call") then
    local call_op = arg[2]
    if (call_op == nil) then
        os.exit(1)
    end
    local json_str = io.read("*a")
    local parsed_call = jsonc.parse(json_str)
    local return_data = {}
    local sfp_interface_list = list_sfp_interfaces()
    if (call_op == "status") then
        local interface = parsed_call["interface"]
        if (interface == nil) and (tablex.size(sfp_interface_list) >= 1) then
            for intf_name, intf_data in pairs(sfp_interface_list) do
                return_data[intf_name] = get_ethtool_output(intf_name)
            end
        elseif (interface ~= nil) then
            return_data[interface] = get_ethtool_output(interface)
        else
            return_data["error"] = "Interface not specified, and no SFPs defined in sfp.json"
            return_data["success"] = false
        end
    elseif (call_op == "interfaces") then
        return_data = sfp_interface_list
    end
    local return_json = jsonc.stringify(return_data)
    print(return_json)
end