require "luarocks.require"
require "md5"
require "lfs"

home = os.getenv( "HOME" )

os.execute("mkdir -p " .. home .. "/.conky/requests");
os.execute("mkdir -p " .. home .. "/.conky/info");
c_timer_init = -1

do
 function conky_eval(...)
    return conky_parse(table.concat(arg, " "))
 end
 
 function conky_multiply_line(times, ...)
    local str = table.concat(arg, " ")
    local tbl = {}
    for i=1,times,1 do
	tbl[i] = string.gsub(str,"@i@", i-1)
    end
    local res = table.concat(tbl,"\n")
    return res;
 end

 function split(delimiter, text)
  local list = {}
  local pos = 1
  if string.find("", delimiter, 1) then -- this would result in endless loops
    error("delimiter matches empty string!")
  end
  while 1 do
    local first, last = string.find(text, delimiter, pos)
    if first then -- found?
      table.insert(list, string.sub(text, pos, first-1))
      pos = last+1
    else
      table.insert(list, string.sub(text, pos))
      break
    end
  end
  return list
 end
 
 function conky_filter_real_ip(iface)
    local req =  string.format('${addrs %s}', iface)
    local ips = conky_parse(req);
--[[
    print(ips)
--]]
    local list = split(",", ips)
    for i, item in ipairs(list) do
	if (string.match(item, "141\.52\.64")) then
	    return item
	end
    end
    return "Unknown"
 end

 user = split('/', home)
 user = user[#user]

 result_check_server_status = {}
 result_check_adei_source = {}
 result_check_server_ = {}
 result_check_service_ = {}
 online = {}
 status = {}
 tested = {}
 c_timer = c_timer_init
 width = 80
 update_time = 0
 outdate_time = 0
 timeout = 2

 function conky_set_width (w)
    width = tonumber(w)
    return ""
 end
 
 function conky_set_timeout (t)
    timeout = tonumber(t)
    return ""
 end

 function cmd_popen(server, port, cmd)
    if (c_timer_init == 0) then
	return io.popen(cmd)
    else 
	local cmd_md5 = md5.sumhexa(cmd)
        local fn = string.format("%s/.conky/info/%s:%s-%s.srv", home, server, port, cmd_md5)
	stat = lfs.attributes(fn)
	if (stat == nil) then
	    return nil
	end
	
	local since = os.difftime(stat['modification'], update_time)
	if (since < 0) then
	    return nil
	end
	since = os.difftime(outdate_time, os.time())
	if (since < 0) then
	    return nil
	end
	return io.open(fn, "r")
    end
 end

 function conky_check_server_status(server, port, ...)
    port = port or 22
    local name = string.format("%s:%i", server, port);

    if (c_timer < 0) then
	if (c_timer == -1) then
	    local fn = string.format("%s/.conky/requests/%s:%i.srv", home, server, port)
	    
	    tested[string.format("%s:%i", server, port)] = false;

	    local f = assert(io.open(fn, "w"))

	    local cmd = string.format("/etc/conky/scripts/ping.pl %s:%i %i", server, port, timeout)
	    f:write(cmd .. "\n")

	    if (arg[1] ~= "-") then
		cmd = string.format("ssh -x -p %i -o ConnectTimeout=%i root@%s /opt/scripts/check_server_status.sh 2>&1 | fold -w %i", port, timeout, server, width)
		f:write(cmd .. "\n")
	    
		for i, service in ipairs(arg)
		do		
		    cmd = string.format("ssh -x -p %i -o ConnectTimeout=%i root@%s /opt/scripts/check_%s_status.sh 2>&1 | fold -w %i", port, timeout, server, service, width)
	    	    f:write(cmd .. "\n")
		end
	    end
	    f:close()
	end    
	if (result_check_server_status[name] == nil)  then
	    local res
	    if (math.abs(c_timer)%2 > 0) then
		res = "${color yellow}?${color}"
	    else
		res = "${color yellow}.${color}"
	    end
	    
	    if (arg[1] ~= "-") then
		res = res .. "  "
		for i, service in ipairs(arg) do
	    	    res = res .. "  "
		end
	    end
	    --result_check_server_status[server] = res
	    --status[server] = false
	    return res
	end
    elseif (c_timer == 0) then
	result_check_server_status[name] = check_server_status(server, port, arg)
    end

    return result_check_server_status[name];
 end
 
 function check_server_status(server, port, additional)
    port = port or 22

    local res
    local cmd = string.format("/etc/conky/scripts/ping.pl %s:%i %i", server, port, timeout)
    local cmdf = cmd_popen(server, port, cmd)
    if (cmdf == nil) then
	res = -1
    else
	local data = cmdf:read("*a")
	res = tonumber(data)
	cmdf:close()
    end
    
    if (additional[1] == "-") then
	if (res > 0) then
	    online[server] = true
	    return "${color green}*"
	elseif (res < 0) then
	    return "${color red}?"
	else
	    online[server] = false
	    return "${color red}*"
	end
    end
    
    if (res > 0) then
	online[server] = true
	
	local output

	cmd = string.format("ssh -x -p %i -o ConnectTimeout=%i root@%s /opt/scripts/check_server_status.sh 2>&1 | fold -w %i", port, timeout, server, width)
	cmdf = cmd_popen(server, port, cmd)
	if (cmdf == nil) then
	    output = string.format("${color green}* ${color red}?")
	else
	    local res = {}
	    local line = cmdf:read("*l")
	    while line do
		local m1 = string.match(line, "^\(.*[^%s]\)%s*$")
		if (m1) then
	    	    table.insert(res, m1)
		end
		line = cmdf:read("*l")
	    end
--	    res = cmdf:read("*a")
	    cmdf:close()
	    
	    res = table.concat(res, "\n")
	    
	    if (string.match(res, "[%a%d]")) then
		table.insert(status, string.format("${color yellow}%s:%i${color gray}\n%s", server, port, res))
	        output = string.format("${color green}* ${color red}*")
	    else
		output = string.format("${color green}* *")
	    end
	end

	for i, service in ipairs(additional)
	do	
	    cmd = string.format("ssh -x -p %i -o ConnectTimeout=%i root@%s /opt/scripts/check_%s_status.sh 2>&1 | fold -w %i", port, timeout, server, service, width)
	    cmdf = cmd_popen(server, port, cmd)
	    if (cmdf == nil) then
		output = output .. string.format(" ${color red}?")
	    else 
	        local res = {}
		local line = cmdf:read("*l")
	        while line do
		    local m1 = string.match(line, "^\(.*[^%s]\)%s*$")
		    if (m1) then
	    		table.insert(res, m1)
		    end
		    line = cmdf:read("*l")
		end
		cmdf:close()

		if (res[1]) then
		    local info = table.remove(res)
		    local s = 0
		    local extra = ""
		    
		    local m1, m2 = string.match(info, "^\(%d+\)\(%s.+\)$")
		    if (m1 == nil) then
			m1 = string.match(info, "^\%d+$");
		    end
		    if (m1 == nil) then
			table.insert(res, info)
		    else
			s = tonumber(m1)
			if (m2 ~= nil) then
			    extra = string.sub(m2,2)
			end
		    end
	    	    
		    if (res[1]) then
			res = table.concat(res, "\n")
			table.insert(status, string.format("${color yellow}%s:%i:%s${color gray}\n%s", server, port, service, res))
		    end
		    if (s == 0) then
			output = output .. string.format(" ${color red}*")
		    elseif (s == 1) then
			output = output .. string.format(" ${color green}*")
		    else
			output = output .. string.format(" ${color yellow}*")
		    end
		    output=output .. " ${color white}" .. extra;
		else
		    output = output .. string.format(" ${color green}*")
		end
	    end
	end
	
	return output
    else
	if (res < 0) then
	    res = string.format("${color red}?  ")
	else
	    online[server] = false
	    res = string.format("${color red}*  ")
	end
	for i, service in ipairs(additional) do
	    res = res .. "  "
	end

	return res
    end
 end

 function conky_check_adei_source(server, port, config, setup, db_server, db_name, ignore_list)
    port = port or 22
    local name = string.format("%s:%i__%s__%s", server, port, db_server, db_name)
    if (c_timer < 0) then
	if (c_timer == -1) then
	    ignore_list = ignore_list or ""

	    local fn = string.format("%s/.conky/requests/%s:%i.srv", home, server, port)

	    local f = assert(io.open(fn, "a+"))
	    local cmd = string.format('ssh -x -p %i -o ConnectTimeout=%i root@%s /opt/scripts/check_adei_source.sh %s %s %s %s "%s" 2>&1', port, timeout, server, config, setup, db_server, db_name, ignore_list)
	    f:write(cmd .. "\n")
	    f:close()
	end
	
	if (result_check_adei_source[name] == nil) then
	    return "${color yellow}?${color}"
	else
	    if (online[server]) then
    		return result_check_adei_source[name];
	    else
		return "${color red}?${color}"
	    end
	end
    elseif (online[server]) then
	if (c_timer == 0) then
	    result_check_adei_source[name] = check_adei_source(server, port, config, setup, db_server, db_name, ignore_list)
	end
        return result_check_adei_source[name];
    else
	return "${color red}?${color}"
    end
 end
 
 function check_adei_source(server, port, config, setup, db_server, db_name, ignore_list)
	ignore_list = ignore_list or ""
	cmd = string.format('ssh -x -p %i -o ConnectTimeout=%i root@%s /opt/scripts/check_adei_source.sh %s %s %s %s "%s" 2>&1', port, timeout, server, config, setup, db_server, db_name, ignore_list)
	cmdf = cmd_popen(server, port, cmd)
	if (cmdf == nil) then
	    return "${color red}?"
	end
	
	local res = {}
	line = cmdf:read("*l")
	while line do
	    local m1 = string.match(line, "^\(.*[^%s]\)%s*$")
	    if (m1) then
		table.insert(res, m1)
	    end
	    line = cmdf:read("*l")
	end
	cmdf:close()

	local info = table.remove(res)

	local t1, t2, t3 = string.match(info, "^\(%d+\)%s+\(%d+\)%s+\(%d+\)")
	
	local s = tonumber(t1)
	if (s == nil) then 
	    table.insert(res, info)
	    s = 0 
	end

	res = table.concat(res, "\n")
	
	local output
	if (s == 1) then 
	    output="${color green}*"
	else
--[[
	    table.insert(status, string.format("${color yellow}%s -- %s${color gray}\n%s\n", db_server, db_name, res))
--]]
	    if (s == 0) then output="${color red}*"
	    else output="${color yellow}*" end
	end
	
--	if (s ~= 0) then
	    local groups = tonumber(t2)
	    if (groups) then
		output = output .. string.format("${color white} %i groups", groups);
	    else
		output = output .. string.format("${color red} ? groups");
	    end

	    local size = tonumber(t3)	
	    if (groups and size) then
		output = output .. string.format("${color white}, %i GB", size);
	    else
		output = output .. string.format("${color red}, ? GB");
	    end
--	end

        if (string.match(res, "[%a%d]")) then
	    output = output .. "${color gray}\n   ${font Bitstream Vera Sans Mono:size=7}" .. string.gsub(res,"\n", "${font}\n   ${font Bitstream Vera Sans Mono:size=7}") .. "${font}${color white}"
	end
	
	return output
 end

 function conky_check_server_(service, server, port, ...)
    port = port or 22
    local name = string.format("%s:%i:%s", server, port, service)
    if (c_timer < 0) then
        if (c_timer == -1) then
            ignore_list = ignore_list or ""
            
            local fn = string.format("%s/.conky/requests/%s:%i.srv", home, server, port)
        
            local f = assert(io.open(fn, "a+"))
            local cmd = string.format("ssh -x -p %i -o ConnectTimeout=%i root@%s /opt/scripts/check_server_%s.sh 2>&1", port, timeout, server, service)
            f:write(cmd .. "\n")
            f:close()
        end
           
        if (result_check_server_[name] == nil) then
            return "${color yellow}?${color}"
        else
            if (online[server]) then
                return result_check_server_[name];
            else
                return "${color red}?${color}"
            end
        end
    elseif (online[server]) then
        if (c_timer == 0) then
            result_check_server_[name] = check_server_(service, server, port, arg)
        end
        return result_check_server_[name];
    else
        return "${color red}?${color}"
    end
 end

 function conky_check_service_(service, id, ...)
    local name = string.format("%s:%s", service, id)
    if (c_timer < 0) then
        if (c_timer == -1) then
            ignore_list = ignore_list or ""

	    tested[string.format("%s:%s", service, id)] = false;
            
            local fn = string.format("%s/.conky/requests/%s:%s.srv", home, service, id)
        
            local f = assert(io.open(fn, "a+"))
            local cmd = string.format("/etc/conky/service/check_%s.sh %s %s 2>&1", service, id, table.concat(arg, " "))
            f:write(cmd .. "\n")
            f:close()
        end
           
        if (result_check_server_[name] == nil) then
            return "${color yellow}?${color}"
        else
            return result_check_server_[name];
        end
    else
        if (c_timer == 0) then
            result_check_server_[name] = check_service_(service, id, arg)
        end
        return result_check_server_[name];
    end
 end


 function format_traffic(value, yellow, red)
    yellow = yellow or 100
    red = red or 1000
    
    local value = math.floor(tonumber(value) / 1073741824)
    
    local res
    if (value > red) then res="${color red}"
    elseif (value > yellow) then res="${color yellow}"
    else res="${color white}" end

    if (value < 10) then res = res .. "  " .. value
    elseif (value < 100) then res = res .. " " .. value
    else res = res .. value end
    
    return res .. " GB${color gray}"
 end
 
 function check_server_(service, server, port, opts)
        port = port or 22
	local cmd = string.format("ssh -x -p %i -o ConnectTimeout=%i root@%s /opt/scripts/check_server_%s.sh 2>&1", port, timeout, server, service)
	cmdf = cmd_popen(server, port, cmd)
	if (cmdf == nil) then
	    return "${color red}?"
	end

	local res = {}
	line = cmdf:read("*l")
	while line do
	    local m1 = string.match(line, "^\(.*[^%s]\)%s*$")
	    if (m1) then
		table.insert(res, m1)
	    end
	    line = cmdf:read("*l")
	end
	cmdf:close()
	
	if (service == "traffic") then
	    if (res[1]) then
		local t1, t2, t3 = string.match(res[1], "^\(%d+\)%s+\(%d+\)%s+\(%d+\)")
		
		if (t1 and t2 and t3) then
	    	    if ((opts) and (opts[1])) then yellow = tonumber(opts[1])
		    else yellow = nil end
		    if ((opts) and (opts[2])) then red = tonumber(opts[2])
		    else red = nil end
		
		    t1=format_traffic(t1,yellow,red)
		    t2=format_traffic(t2,yellow,red)
		    t3=format_traffic(t3,yellow,red)
		    return string.format("${color gray}i: %s, o: %s, f: %s", t1, t2, t3)
		else
		    return "${color red}" .. res[1]
		end
	    end
	end
	

	return ""
 end


 function check_service_(service, id, opts)
	local cmd = string.format("/etc/conky/service/check_%s.sh %s %s 2>&1", service, id, table.concat(opts, " "))
	cmdf = cmd_popen(service, id, cmd)
	if (cmdf == nil) then
	    return "${color red}?"
	end

	local res = {}
	local local_res = {}
	line = cmdf:read("*l")
	while line do
	    local t, m1 = string.match(line, "^\(\*?\)\(.*[^%s]\)%s*$")
	    if (m1) then
		if (t == nil) or (t == '') then
		    table.insert(res, m1)
		else
		    table.insert(local_res, string.sub(m1,1))
		end
	    end
	    line = cmdf:read("*l")
	end
	cmdf:close()

	local output
	local info = table.remove(res)
	local t1 = 0
	local t2 = nil
	local msg = ''

	if (info) then
	    t1, t2, msg = string.match(info, "^\(%d+\)%s+\(%d+\)\(.*\)")
	end
	
	local s = tonumber(t1)
	if (s == nil) then 
	    table.insert(res, info)
	    s = 0 
	end

	if (s == 1) then 
	    output="${color green}*"
	else
	    if (s == 0) then output="${color red}*"
	    else output="${color yellow}*" end
	end
	
	s = tonumber(t2)
	if (s == nil) then 
	    s = 0 
	else
	    if (s == 1) then 
		output=output .. " ${color green}*"
	    else
		if (s == 0) then output=output .. " ${color red}*"
		else output=output .. " ${color yellow}*" end
	    end
	end

	output = output .. " ${color white}" .. msg

	res = table.concat(res, "\n")
	local_res = table.concat(local_res, "\n")
	

	if (string.match(res, "[%a%d]")) then
	    table.insert(status, string.format("${color yellow}%s:%s${color gray}\n%s", service, id, res))
	end

	if (string.match(local_res, "[%a%d]")) then
	    output = output .. "${color gray}\n   ${font Bitstream Vera Sans Mono:size=7}" .. string.gsub(local_res,"\n", "${font}\n   ${font Bitstream Vera Sans Mono:size=7}") .. "${font}${color white}"
	end
	
	return output
 end


 
 function conky_print_server_errors(interval, tag)
    local res = table.concat(status, "\n")

    if (c_timer < 0) then
	tag = user .. "_" .. tag

	if (c_timer == -1) then
	    update_time = os.time()
	    
	    local result = 0;
	    while (result == 0) do
	        result = os.execute("ps x | grep conky_process_requests | grep " .. tag .. " | grep -v grep > /dev/null")
	    end

	    for item, s in pairs(tested) do
		os.execute("/etc/conky/scripts/conky_process_requests.pl \"" .. item .. ".srv\" " .. tag .. " &")
	    end
	end
	
	local result=os.execute("ps x | grep conky_process_requests | grep " .. tag .. " | grep -v grep > /dev/null")
	if (result == 0) then
	    c_timer = c_timer - 1;
	    local since = os.difftime(os.time(), update_time)
	    if (since > tonumber(interval)) then
		result_check_server_status = {}
		result_check_adei_source = {}
		result_check_server_ = {}
	    end
	else
	    outdate_time = os.time() + 2 * tonumber(interval)
	    c_timer = 0
	end
	return ""
    else 
	c_timer = c_timer + conky_info.update_interval
	if (c_timer > tonumber(interval)) then 
	    status = {}
	    tested = {}
	    c_timer = c_timer_init
	end
    end

    if (string.match(res, "[%a%d]")) then
	return string.format("\n\n%s", res)
    else
	return ""
    end
 end
 
 function conky_outcon(pos1, pos2)
    local n = tonumber(conky_parse('${tcp_portmon 32768 65535 count}'))
    local res = {}
    local str = ""
    for i=1,n do
	local val = tostring(conky_parse(string.format('${tcp_portmon 32768 65535 rhost %i}:${tcp_portmon 32768 65535 rport %i}',i - 1,i - 1)))
	
	if (res[val] == nil) then
	    res[val] = 1
	else
	    res[val] = res[val] + 1
	end
    end


    local names = {}
    for addr,num in pairs(res) do
	table.insert(names, addr)
    end

    table.sort(names, function(a,b) return res[a]>res[b] end)

    for i=1,#names do
	local name = names[i]
	str = str .. string.format("${goto %i}%s${goto %i}cnt  %3i\n",pos1,name,pos2,res[name])
    end
    
    return str
 end
end