#!/usr/bin/env lua

local json = require "luci.jsonc"
local fs   = require "nixio.fs"

local function readfile(path)
        local s = fs.readfile(path)
        return s and (s:gsub("^%s+", ""):gsub("%s+$", ""))
end

local service_ignore = {
	"call_cellular",
	"cellular_monitor",
	"call_cid_configuration",
	"firewall",
	"lanwan",
	"poe",
	"pptpinitwatchdog",
	"socat",
	"simtraydetection",
	"snapcap",
	"wanlan",
}

function ignore_service (filename)
	for i,v in ipairs(service_ignore) do
	    if ( v == filename ) then
		return true
	    end
	end
	return false
end

local methods = {
	getServiceList = {
		args = { service = "none", action = "none" },
		call = function(args)
		local sys = require "luci.sys"
		local res = {}
		local model = luci.sys.exec("cat /tmp/sysinfo/model | xargs echo -n")
		function scandir(directory)
			local i, t, popen = 0, {}, io.popen
			local pfile = popen('ls "'..directory..'"')
			for filename in pfile:lines() do
				if (model == "EDS5000" and (ignore_service(filename) == false)) then
					i = i + 1
					t[i] = filename
                                end
			end
			pfile:close()
			return t
		end
		if args.service and args.action then
			local cmd="/etc/init.d/" .. args.service .. " " .. args.action
			luci.sys.exec(cmd)
				res[1]='OK'
			else
				res=scandir("/etc/init.d/")
			end
			return { result = res }
		end
	},
	getCFlowList = {
		call= function()
			local fileContent = {}
			local fs = require "nixio.fs"
			local sys = require "luci.sys"
			fileContent[0] = readfile("/var/run/mach10.pid") and "Running" or "Inactive"
			fileContent[1] = readfile("/tmp/mach10.errors",1024) or "None"

			local timestamp = readfile("/tmp/mach10.status_update",1024)
			fileContent[2] = ""
			if timestamp then
				fileContent[2]=luci.sys.exec("/usr/sbin/timediff.sh /tmp/mach10.status_update")
			end

			timestamp =  readfile("/tmp/mach10.check_update",1024)
			fileContent[3]=""
			if timestamp then
				fileContent[3]=luci.sys.exec("/usr/sbin/timediff.sh /tmp/mach10.check_update")
			end

			fileContent[4] = readfile("/tmp/mach10.available_firmware",1024) or "<None>"
			fileContent[5] = readfile("/tmp/mach10.available_config",1024) or "<None>"
			fileContent[6] = readfile("/tmp/luci_message_cflow",1024) or ""
			return {result = fileContent }
		end
	},
	getDIOList = {
		call = function()
			local fileContent = {}
			fileContent[0] = readfile("/sys/class/gpio/di1/value");
			fileContent[1] = readfile("/sys/class/gpio/di2/value");
			fileContent[2] = readfile("/sys/class/gpio/do1/value");
			fileContent[3] = readfile("/sys/class/gpio/do2/value");
			return {result = fileContent }
		end
	},

	getVIOdata = {
		call = function()
			local fileContent = {}
			fileContent[0] = readfile("/sys/bus/iio/devices/iio\:device0/in_voltage0_raw") or "" ;
			fileContent[1] = readfile("/sys/bus/iio/devices/iio\:device0/in_voltage1_raw") or "" ;
			fileContent[2] = readfile("/sys/class/gpio/vo12/value") or "" ;
			fileContent[3] = readfile("/sys/class/gpio/vo22/value") or "" ;
			fileContent[4] = readfile("/tmp/sysinfo/prodid") or "" ;
			fileContent[5] = readfile("/etc/versatile1/versatile1.conf") or "" ;
			fileContent[6] = readfile("/etc/versatile2/versatile2.conf") or "" ;
			return {result = fileContent }
		end
	},

	getCellulardata = {
		call = function()
			local fileContent = {}
			fileContent[0] = readfile("/tmp/sysinfo/sigstat") or "" ;
			fileContent[1] = readfile("/tmp/sysinfo/regstat") or "" ;
			fileContent[2] = readfile("/tmp/sysinfo/opname") or "" ;
			fileContent[3] = readfile("/tmp/sysinfo/opnumber") or "" ;
			fileContent[4] = readfile("/tmp/sysinfo/optype") or "" ;
			fileContent[5] = readfile("/tmp/sysinfo/roamstat") or "" ;
			fileContent[6] = readfile("/tmp/sysinfo/cpin") or "" ;
			fileContent[7] = readfile("/tmp/sysinfo/imsi") or "" ;
			fileContent[8] = readfile("/tmp/sysinfo/band") or "" ;
			fileContent[9] = readfile("/tmp/sysinfo/iccid") or "" ;
			fileContent[10] = readfile("/sys/class/gpio/sim-switch/value") or "" ;
			fileContent[11] = readfile("/tmp/sysinfo/conf_band") or "" ;
			fileContent[12] = readfile("/tmp/sysinfo/temperature") or "" ;
			return {result = fileContent }
		end
	},

	getSystemdata = {
		call = function()

		function checkLine (findString, fileName, sep)
			file = io.open(fileName)lines = file:lines()
			for line in lines do
				if string.find(line, findString) then
					key, value = line:match("([^,]+)"..sep.."([^,]+)")
					return value
				end
			end
			file:close()
		end

		function check_Line (findString, fileName)
			file = io.open(fileName)lines = file:lines()
			for line in lines do
				if string.find(line, findString) then
					key, value = line:match("([^,]+):([^,]+)")
					return value
				end
			end
		end

		function mysplit (inputstr, sep)
			if sep == nil then
				sep = "%s"
			end
			local t={}
			for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
				table.insert(t, str)
			end
			return t
		end


		local content = {}
		local open = io.open
		local file = open("/tmp/sysinfo/model", "rb")
		if file then
			content = file:read "*a"
			file:close()
		else
			file = open("/proc/device-tree/model", "rb")
			if file  then
				content = file:read "*a"
				file:close()
			else
				content = checkLine("machine","/proc/cpuinfo",":")
				if content then
					print("machine value")
				elseif not content then
					content = checkLine("hardware","/proc/cpuinfo",":")
					if content then
						print("hardware value")
					end
				else
					print("key-value not found")
				end
			end
		end

		local partnum = {}
		local content1 = {}
		local open = io.open
		local file = open("/tmp/sysinfo/prodid", "rb")
		if file  then
			content1 = file:read "*a"
			file:close()
			if content1 ~= "X30x-G4141AS" or content1 ~= "X30x-G41412S" or content1 ~= "X30x-G41417S" or content1 ~= "X30x-G414CS" then
				partnum = content1
			elseif content1 == "X30x-G4141AS" then
				partnum = "G4141AS"
			elseif content1 == "X30x-G41412S" then
				partnum = "G41412S"
			elseif content1 == "X30x-G41417S" then
				partnum = "G41417S"
			elseif content1 == "X30x-G414CS" then
				partnum = "G414CS"
			else
				print("part number:NILL")
			end
		end

		local arch_info
		if content and string.match(content,"EDS5000") then
		    arch_info="ARMV8(aarch64)"
		else
		    arch_info=checkLine("system type","/proc/cpuinfo", "\t: ")
		end
                if not arch_info or arch_info == "0" then
                        arch_info = checkLine("processor","/proc/cpuinfo", "\t: ")
                end
                if not arch_info or arch_info == "0" then
                        arch_info = checkLine("cpu","/proc/cpuinfo","\t: ")
                end
                if not arch_info or arch_info == "0" then
                        arch_info = checkLine("model name","/proc/cpuinfo","\t: ")
                end




		local output = {}
		local result = {}
		local load_avg = {}
		local command = {}

		command = io.popen('cat /proc/loadavg')
		local output = command:read('*all')
		command:close()

		result = mysplit(output, " ");
		load_avg = result[1]..","..result[2]..","..result[3]


		local router_time = {}
		local command2 = io.popen('date')
		router_time = command2:read('*all')
		command2:close()

		local uptime = {}

		command = io.popen('cat /proc/uptime')
		output = command:read('*all')
		command:close()
		uptime = mysplit(output, " ");


		local firmware_version = {}
		local desc_res = {}
		desc_res = checkLine("DESCRIPTION","/etc/openwrt_release", "=")
		firmware_version = desc_res:match("%'(.+)%'");



		command = io.popen('uname -a')
		output = command:read('*all')
		command:close()

		result = mysplit(output, " ");

                command = io.popen('uname -a | cut -d " " -f7-10')
                build_date = command:read('*all')
                command:close()


		local fileContent = {}
		fileContent[0] = readfile("/tmp/sysinfo/imei") or "" ;
		fileContent[1] = readfile("/tmp/bootcause") or "" ;
		fileContent[2] = readfile("/tmp/sysinfo/firmware") or "";
		--fileContent[3] = readfile("/tmp/sysinfo/prodid") or "" ;
		fileContent[3] = partnum;
		fileContent[4] = readfile("/tmp/sysinfo/ubootversion") or "" ;
		fileContent[5] = readfile("/sys/class/gpio/poe/value") or "" ;
		fileContent[6] = readfile("/sys/class/gpio/ripin/value") or "";
		fileContent[7] = checkLine("poe","/etc/hwinfo.json",":") or "" ;
		fileContent[8] = checkLine("snapcap","/etc/hwinfo.json",":") or "" ;
		fileContent[9] =  result[2];
		fileContent[10] = result[3];
		fileContent[11] = content;
		fileContent[12] = uptime[1];
		fileContent[13] = load_avg;
		fileContent[14] = firmware_version;
		fileContent[15] = arch_info;
		fileContent[16] = router_time;
		fileContent[17] = readfile("/proc/device-tree/lantronix/hwcfg") or "";
		fileContent[18] = readfile("/sys/class/gpio/ignition/value") or "";
		fileContent[19] = build_date;

		return { result = fileContent }
		end

	}
}


local function parseInput()                                                                                      
        local parse = json.new()                                                                                 
        local done, err                                                                                                                     
                                                                                                                       
        while true do                                                                                                              
                local chunk = io.read(4096)                                                                                                 
                if not chunk then                                                                                                           
                        break                                                                                                               
                elseif not done and not err then                                                                                            
                        done, err = parse:parse(chunk)                                                                                      
                end                                                                                                                         
        end                                                                                                                                 
                                                                                                                                            
        if not done then                                                                                                                    
                print(json.stringify({ error = err or "Incomplete input" }))                                                                
                os.exit(1)                                                                                                                  
        end                                                                                                                                 
                                                                                                                                            
        return parse:get()                                                                                                                  
end


local function validateArgs(func, uargs)                                          
        local method = methods[func]                                                             
        if not method then                                                         
                print(json.stringify({ error = "Method not found" }))                 
                os.exit(1)                                                                                                                  
        end                                                                         
                                                                                                                                          
        if type(uargs) ~= "table" then                                                                                           
                print(json.stringify({ error = "Invalid arguments" }))        
                os.exit(1)                                                               
        end                                                                     
                                                                                           
        uargs.ubus_rpc_session = nil                                                           
                                                                                                                       
        local k, v                                                                                
        local margs = method.args or {}                                                                        
        for k, v in pairs(uargs) do                                                                                                              
                if margs[k] == nil or                                                                         
                   (v ~= nil and type(v) ~= type(margs[k]))                                                      
                then                                                                                        
                        print(json.stringify({ error = "Invalid arguments" }))                                         
                        os.exit(1)                                          
                end                                                          
        end                                                                              
                                                                                                                    
        return method                                                        
end                                                                     
                                                                                 
if arg[1] == "list" then                                                             
        local _, method, rv = nil, nil, {}                             
        for _, method in pairs(methods) do rv[_] = method.args or {} end                       
        print((json.stringify(rv):gsub(":%[%]", ":{}")))                                                            
elseif arg[1] == "call" then                                                        
        local args = parseInput()                                               
        local method = validateArgs(arg[2], args)                                                     
        local result, code = method.call(args)                                                              
        print((json.stringify(result):gsub("^%[%]$", "{}")))       
        os.exit(code or 0)                                                         
end
