-----------------------------------------------------------------------------
-- JSONRPC4Lua: JSON RPC server for exposing Lua objects as JSON RPC callable
-- objects via http.
-- json.rpcserver Module.
-- Author: Craig Mason-Jones
-- Homepage: http://github.com/craigmj/json4lua/
-- Version: 1.0.0
-- This module is released under the MIT License (MIT).
-- Please see LICENCE.txt for details.
--
-- USAGE:
-- This module exposes one function:
--   server(luaClass, packReturn)
--     Manages incoming JSON RPC request forwarding the method call to the given
--     object. If packReturn is true, multiple return values are packed into an
--     array on return.
--
-- IMPORTANT NOTES:
--   1. This version ought really not be 0.9.10, since this particular part of the
--      JSONRPC4Lua package is very first-draft. However, the JSON4Lua package with which
--      it comes is quite solid, so there you have it :-)
--   2. This has only been tested with Xavante webserver, with which it works
--      if you patch CGILua to accept 'text/plain' content type. See doc\cgilua_patch.html
--      for details.
----------------------------------------------------------------------------

module ('json.rpcserver')

---
-- Implements a JSON RPC Server wrapping for luaClass, exposing each of luaClass's
-- methods as JSON RPC callable methods.
-- @param luaClass The JSON RPC class to expose.
-- @param packReturn If true, the server will automatically wrap any
-- multiple-value returns into an array. Single returns remain single returns. If
-- false, when a function returns multiple values, only the first of these values will
-- be returned.
--
function serve(luaClass, packReturn)
    cgilua.contentheader('text','plain')
    require('cgilua')
    require ('json')
    local postData = ""

    if not cgilua.servervariable('CONTENT_LENGTH') then
        cgilua.put("Please access JSON Request using HTTP POST Request")
        return 0
    else
        postData = cgi[1]	-- SAPI.Request.getpostdata()  --[[{ "id":1, "method":"echo","params":["Hi there"]}]]  --
    end
    -- @TODO Catch an error condition on decoding the data
    local jsonRequest = json.decode(postData)
    local jsonResponse = {}
    jsonResponse.id = jsonRequest.id
    local method = luaClass[ jsonRequest.method ]

    if not method then
        jsonResponse.error = 'Method ' .. jsonRequest.method .. ' does not exist at this server.'
    else
        local callResult = { pcall( method, unpack( jsonRequest.params ) ) }
        if callResult[1] then	-- Function call successfull
        table.remove(callResult,1)
        if packReturn and table.getn(callResult)>1 then
            jsonResponse.result = callResult
        else
            jsonResponse.result = unpack(callResult)	-- NB: Does not support multiple argument returns
        end
        else
            jsonResponse.error = callResult[2]
        end
    end

    -- Output the result
    -- TODO: How to be sure that the result and error tags are there even when they are nil in Lua?
    -- Can force them by hand... ?
    cgilua.contentheader('text','plain')
    cgilua.put( json.encode( jsonResponse ) )
end