--
-- 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") or string.find(s, "Time per bit") then
--    if string.find(s, "Time per bit") then
      return
    end

    local i, j, num, cur, total,percent = string.find(s,"(.*),.*it: (%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

    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

--    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
