--
-- LLRNet - network part of LLR
--
-- (C) 2004-2005 Vincent Penne
--
-- Released under GNU LIBRARY GENERAL PUBLIC LICENSE
-- (See file LICENSE that must be included with this software)
--
--

GUIport = 6999
maxConnections = 8


--local net_Recv = net_Recv


function SendStructure(socket, name, struct)
   local n, i, v
   n = 0
   for i, v in struct do
      if (type(i) == "string" or type(i) == "number") and
	 (type(v) == "string" or type(v) == "number" or type(v) == "table") then

	 n = n + 1
      end
   end
   
   net_Send(socket, "STRUCT")
   net_Send(socket, name)
   net_Send(socket, tostring(n))
   for i, v in struct do
      if (type(i) == "string" or type(i) == "number") and
	 (type(v) == "string" or type(v) == "number" or type(v) == "table") then
	 
	 if type(i) == "string" then
	    net_Send(socket, "A"..i)
	 else
	    net_Send(socket, "N"..tostring(i))
	 end
	 if type(v) == "string" then
	    net_Send(socket, "A"..v)
	 elseif type(v) == "number" then
	    net_Send(socket, "N"..tostring(v))
	 else
	    SendStructure(socket, "toto", v)
	 end
      end
   end
   
end

backLog = { }
local commands = {
   LOGIN = function(client, socket)
	      if net_Recv(socket) ~= GUIpassword then
		 net_Send("Exit", 1)
		 return
	      end

	      client.logged = 1

	      net_Send(socket, "STATUS")
	      net_Send(socket, statusStr)
	      --SendStructure(socket, "status", status)
	      SendStructure(socket, "results", results)
	      SendStructure(socket, "tosend", tosend)
	      local t, k, n, more = ReadWorkfile()
	      SendStructure(socket, "WUs", more or { })

	      local i, n
	      n = getn(backLog)
	      for i=1, n, 1 do
		 net_Send(socket, "MSG")
		 net_Send(socket, backLog[i])
	      end

	   end,
   PAUSE = function(client, socket)
	      paused = 1
	      if not sleeping then
		 stopSet()
	      end
	      UpdateStatus("Paused ...")
	      net_Recv(socket)
	   end,
   RESUME = function(client, socket)
	       paused = nil
	       sleeping = nil
	       stopReset()
	       net_Recv(socket)
	    end,
   KILL = function(client, socket)
	     sleeping = nil
	     paused = nil
	     stopSet()
	     UpdateStatus("Exiting ...")
	     net_Recv(socket)
	   end,
}

guiClients = { }
results = { }
function OnConnect(socket)
   -- create a new client structure
   local client = { socket = socket }
   guiClients[socket] = client

   net_Send(socket, "CONNECTED")

   -- Receive a command from the client
   while 1 do
      local command = net_Recv(socket)
      --print(command)

      if not command or command == "Exit" then
	 break
      end

      -- check we are logged on for any command except the Login one
      if command ~= "LOGIN" and not client.logged then
	 break
      end
      
      -- execute the command
      local f = commands[command]
      if f then
	 f(client, socket)
      else
	 print("llrclientserver: Unknown command", command)
	 -- try to skip the unknown command
	 local n = net_Recv(socket)
	 if not n then break end
	 n = tonumber(n)
	 if not n then break end
	 local i, error
	 for i=1, n, 1 do
	    if not net_Recv(socket) then
	       error = 1
	       break
	    end
	 end
	 if error then
	    break
	 end
	 print("llrclientserver: Skipped command succesfully")
      end
   end

   guiClients[socket] = nil
   
   -- WARNING : do not close the socket, it is closed automatically after
   -- OnConnect returns

end

status = { }
statusStr = "Initializing ..."

function UpdateStatus(str)
   if str == statusStr then
      return
   end
   statusStr = str
   local i, v
   for i, v in guiClients do
      if v.logged then
	 net_Send(i, "STATUS")
	 net_Send(i, str, 1)
      end
   end

   if trayIcon then
      TrayIconTip(trayIcon, "LLRnet : "..str)
   end
end

local ignoreNextPrint
function OnPrint(s, noparse)
   if ignoreNextPrint then
      ignoreNextPrint = nil
      return
   end
   if not noparse then -- and next(guiClients) then
      if string.find(s, "Time per iteration") then
	 return
      end
      local i, j, num, cur, total, percent = 
	 string.find(s, 
		     "(.*),.*teration : (%d*) / (%d*) %[(.*)%%%]")
      if percent then
	 status.curWU = num
	 status.curIteration = cur
	 status.totalIteration = total
	 status.percent = percent
	 return
      else
	 local i, j, tpi = string.find(s, 
				       "([%d%.]*) ms.")
	 if tpi then 
	    status.tpi = tpi 
	    
	    UpdateStatus(format("(%s%% complete, %sms per it.) %s", 
				status.percent or "?", status.tpi or "?", 
				status.curWU or "?"))

	    ignoreNextPrint = 1
	    return
	 end
      end
   end

   tinsert(backLog, s)
   if getn(backLog) > 100 then
      tremove(backLog, 1)
   end
   local i, v
   for i, v in guiClients do
      if v.logged then
	 net_Send(i, "MSG")
	 net_Send(i, s, 1)
      end
   end
   orig_print(string.sub(s, 1, -2))
end

if not MFC then
orig_print = print
local orig_print = print
function print(...)
   local s = arg[1] or ""
--   if not s then
--      return
--   end
   local i, n
   n = getn(arg)
   for i=2,n,1 do
      s = s.."\t"..tostring(arg[i])
   end
   OnPrint(s.."\n", 1)
   --orig_print(unpack(arg))
end
end

local orig_OutputBoth = OutputBoth
function OutputBoth(s)
   OnPrint(s.."\n", 1)
   orig_OutputBoth(s)
end

function SendStructureToAllGUIs(name, struct, flush)
   local i, v
   for i, v in guiClients do
      if v.logged then
	 SendStructure(v.socket, name, struct)
	 if flush then
	    net_Flush(v.socket)
	 end
      end
   end
end

function FlushAllGUIs()
   local i, v
   for i, v in guiClients do
      net_Flush(v.socket)
   end
end

function DisconnectAllGUIs()
   local i, v
   for i, v in guiClients do
      net_Send(v.socket, "Exit", 1)
   end
end

return 1
