-- Copyright (C) idevz (idevz.org)

local singletons = require "motan.singletons"
local response = require "motan.core.response"
local utils = require "motan.utils"
local consts = require "motan.consts"
local setmetatable = setmetatable
local math = math

local _M = {
    _VERSION = "0.1.0"
}

local mt = {__index = _M}

function _M.new(self, url)
    local motan_provider = {
        url = url,
        service_obj_arr = {},
        service = {}
    }
    return setmetatable(motan_provider, mt)
end

function _M.initialize(self)
end

function _M.set_service(self, service)
    self.service = service
end

function _M.get_url(self)
    return self.url
end

function _M.set_url(self, url)
    self.url = url
end

function _M.get_path(self)
    return self.url.path
end

function _M.is_available(self)
    return true
end

function _M.destroy(self)
end

function _M.get_service_obj(self, url)
    local service_obj_key = url:get_identity()
    local service_obj = self.service_obj_arr[service_obj_key] or {}
    if not utils.is_empty(service_obj) then
        return service_obj
    end
    local service_path_conf = singletons.config.conf_set["SERVICE_PATH"] or nil
    if service_path_conf == nil then
        ngx.log(ngx.ERR, "SERVICE_PATH didn't set.\n")
        return
    end
    local service_file
    local service_prefix
    service_prefix = singletons.config.conf_set["MOTAN_LUA_SERVICE_PERFIX"]
    if service_prefix ~= nil then
        local ss = url.path
        local s, e = string.find(ss, service_prefix)
        if not s then
            return nil, "build service Err: service path didn't contain service_prefix."
        end
        service_file = service_path_conf .. "/" .. string.sub(ss, e + 1)
    else
        service_file = service_path_conf .. "/" .. url.path
    end

    local service_pkg = assert(require(service_file), "Load service package err. File:\n" .. service_file)
    service_obj = assert(service_pkg:new(), "Init Service object err. File:\n" .. service_file)
    self.service_obj_arr[service_obj_key] = service_obj
    return service_obj
end

function _M.call(self, req)
    local start_time = ngx.now()
    local exception, value = nil
    local service = self:get_service_obj(self.url)
    motan_ctx().metadata = req:get_attachments()
    motan_ctx().request_id = req:get_request_id()

    local method = req:get_method()
    local ok, res_or_err
    if req.args_num < 2 then
        ok, res_or_err = pcall(service[method], service, req:get_arguments())
    else
        ok, res_or_err = pcall(service[method], service, unpack(req:get_arguments()))
    end
    local request_id = req:get_request_id()
    local process_time = ngx.now() - start_time
    local attachments = req:get_attachments()

    if ok then
        local serialization =
        singletons.motan_ext:get_serialization(consts.MOTAN_SERIALIZE_ARR[req:get_serialize_num()])
        value = serialization.serialize(res_or_err)

        return response:new {
            request_id = request_id,
            value = value,
            exception = exception,
            process_time = math.floor((process_time * 100) + 0.5) * 0.01,
            attachments = attachments
        }
    else
        ngx.log(ngx.ERR, "provider call error", res_or_err)
        exception = "provider call error"
        return response:new {
            request_id = request_id,
            exception = exception
        }
    end
end

return _M
