-- This file is generated by x-studio 10.0.5900.509 © 2019, All rights reserved.
-- Module: http_client, <please write module description>
-- Author: halx99
-- Create Date: [2020-02-03 17:46:47]

local _M = {}
local yasio = require 'yasio'

--[[
parse a url
retval: {
  protocol = 'http', -- or 'https'
  host = 'ip138.com'
  path = '/xxx/xxx',
  port = '80', -- or 443 for https, or specificed by url: http://ip138.com:80/index.htm
}
]]
function _M:parseUrl(url)
    local params = {}
    local colon = url:find(':')
    if not colon then return nil end

    params.protocol = url:sub(1, colon - 1)

    -- host start, skip '://'
    local start = colon + 3 -- 

    -- Finally, predicated is path offset or nil
    local predicated = url:find('[:/]', start)
    if predicated then
        params.host = url:sub(start, predicated - 1)

        local ch = url:sub(predicated, predicated)
        if ch == ':' then -- url have specificed port
            colon = predicated
            predicated = url:find('/', predicated + 1)
            if predicated then
                params.port = tonumber(url:sub(colon + 1, predicated - 1))
            else
                params.port = tonumber(url:sub(colon + 1))
            end
        end
    else
        params.host = url:sub(start)
    end

    if predicated then 
        params.path = url:sub(predicated)
    else 
        params.path = '/'
    end
    
    -- No port present in url, set default port for protocol
    if params.port == nil then
        if params.protocol == 'http' then
            params.port = 80
        elseif params.protocol == 'https' then
            params.port = 443
        else
            params.port = 80
        end
    end
    
    return params
end

function _M:ctor(count)

    local channelIndexs = {}
    for i=1,count do
        channelIndexs[#channelIndexs + 1] = i - 1
    end
    self.channelIndexs = channelIndexs

    self.requests = {}
    
    local service = yasio.io_service.new(count)
    service:start(function(ev)
            local t = ev:kind()
            local cindex = ev:cindex()
            local requestItem = self.requests[cindex]
            if requestItem == nil then return end
            if t == yasio.YEK_PACKET then
                print(string.format("yasio.BUFFER_RAW=%d", yasio.BUFFER_RAW))
                local str = ev:packet(yasio.BUFFER_RAW)
                requestItem.responseData = requestItem.responseData .. str
            elseif(t == yasio.YEK_CONNECT_RESPONSE) then -- connect responseType
                if(ev:status() == 0) then
                    local transport = ev:transport()
                    service:write(transport, requestItem.requestData)
                else
                    print("connect server failed!")
                    self.requests[cindex] = nil
                end
            elseif(t == yasio.YEK_CONNECTION_LOST) then -- connection lost event
                print("The http connection is lost!")
                requestItem.requestCallback(requestItem.responseData)
                self.requests[cindex] = nil
            end
        end)

    self.service = service
end

function _M:sendHttpGetRequest(url, callback)
    -- find a idle channel to send request

    local params = self:parseUrl(url)
    if(params == nil) then
        print('yasio.http_client: invalid url: ' .. url)
        return false
    end
    
    local channelKind
    if params.protocol == 'http' then
        channelKind = yasio.YCK_TCP_CLIENT
    elseif params.protocol == 'https' then
        channelKind = yasio.YCK_SSL_CLIENT -- only present when natvie yasio compiled with YASIO_SSL_BACKEND
    end
    
    if not channelKind then
        print('yasio.http_client: unsupported protocol, url=' .. url)
        return false 
    end

    local idleChannelIndex = -1
    for _,v in ipairs(self.channelIndexs) do
        if(self.requests[v] == nil) then
            idleChannelIndex = v
            break
        end
    end

    if(idleChannelIndex ~= -1) then
        local requestItem = {
            requestData = string.format("GET %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36\r\nAccept: */*;q=0.8\r\nConnection: Close\r\n\r\n",
                params.path,
                params.host
            ),
            requestCallback = callback,
            responseData = ""
        }
        self.requests[idleChannelIndex] = requestItem
        self.service:set_option(yasio.YOPT_C_REMOTE_ENDPOINT, idleChannelIndex, params.host, params.port)
        self.service:open(idleChannelIndex, channelKind)
        return true
    else
        print('yasio.http_client: no idle channel to send http request for url: ' .. url)
        return false
    end
end

function _M:update()
    self.service:dispatch(128)
end

_M:ctor(20)

return _M
