import ulsp
import json

global work_items

#############################
# JRPC server Calculator
#############################
class JRPC_Calc(jrpc_server)

   method  start(addr)
      local sock, msg
      if not (jrpc_server := JRPC_HTTPSocket(addr,"n")) then
         write("server open(",addr,") ERROR: ", \&errortext | "Unknown") & fail

      repeat {
         msg := jrpc_server.get_msg() | next
         case msg.get_kind() of {
            "request" : thread handle_request(msg)
            default:
               write("jrpc:msg: " || msg.get_kind(), image(msg.get_content()))
         }
      }
   end

   method handle_request(msg)
      local id := msg.get_id(),
            x := integer(msg.get_params()[1]),
            y := integer(msg.get_params()[2])

      # uncomment to trigger some test failures
      #if x = 9 then fail
      case msg.get_method() of {
         "+" : {jrpc_server.send_msg(msg.make_result_response(x + y))}
         "-" : jrpc_server.send_msg(msg.make_result_response(x - y))
         "*" : jrpc_server.send_msg(msg.make_result_response(x * y))
         "/" : jrpc_server.send_msg(msg.make_result_response(x / y))
         default: write("jrpc:request:unsupported: ", msg.get_method())
      }

   end
end

###############################
# client
###############################
class JRPC_client(jrpc_client)

   method listen(addr)
      if not (jrpc_client := JRPC_HTTPSocket(addr,"na")) then
         stop("client open(", addr, ") ERROR: ", \&errortext | "Unknown")
   end

   method test(op, params, answer)
      local id
      static idx := 0, mtx := mutex()
      critical mtx: id := idx +:=1
      jrpc_client.send_msg(JRPC_Message().make_request(id, op, params))
      work_items[id] := [op, params, answer]
   end

   method  start()
      local x := ?9, y := ?8+1
      test("+", [x, y], x+y)
      test("-", [x, y], x-y)
      test("*", [x, y], x*y)
      test("/", [x, y], x/y)
   end

end

global port
procedure main()
   local calc, client, jobset, addr, id, op, x, y, answer,
         workers, i, response, job

   addr := ":" || 5000 + ?1000
   if &features == ("MacOS" | "MS Windows NT") then
      addr := "127.0.0.1" || addr

   client := JRPC_client()
   calc := JRPC_Calc()
   thread calc.start(addr)
   client.listen(addr)
   workers:=[]
   work_items := mutex(table())
   every !10 do put(workers, thread client.start())
   every wait(!workers)
   jobset:=set()
   every insert(jobset, !*work_items)

   every i := !(*work_items*2) do {
      if *jobset = 0 then break
      if response := client.jrpc_client.get_msg(100) then {
         delete(jobset, id:=response.get_id())
         job := work_items[id]
         op:=job[1]; x:=job[2][1]; y:=job[2][2]; answer := job[3]
         write(left(id, 2), ":   ", x, " ", op, " ", y, " = ", right(response.get_result(), 3),
               "   ", if response.get_result()=answer then "Pass" else "Fail")
      }
   }

   every job := work_items[id:=!jobset] do {
      op:=job[1]; x:=job[2][1]; y:=job[2][2]
      write(left(id, 2), ":   ", x, " ", op, " ", y, " =  Failed to get a response")
   }

end