--  ========================================================================
--
--  FILE: fetch.lua
--
--  SERVICES: 
--    HTTP messaging,
--    Scheduling and Executing the payload (script accompanying data downloaded) 
--    to put the payload into the data store.
--
--  ========================================================================
--  ========================================================================
--
--               Copyright  1999-2006 QUALCOMM Incorporated
--                     All Rights Reserved.
--                   QUALCOMM Proprietary/GTDR
--
--  ========================================================================
--  ========================================================================

-------------------------------------------------------------------------------
--
--
--
--
--
--
--
--
--        +---------------------------------------------------------+
--        |                                                  FETCH  |
--        |                                                         |
--        | +-----------------------------------------------------+ |
--        | |                                                     | |
--        | |                      SCHEDULER                      | |
--        | |                                                     | |
--        | +-----------------------------------------------------+ |
--        | +----------------+ +----------------------------------+ |
--        | |                | |                                  | |
--        | |                | |            TIMED HTTP            | |
--        | |                | |                                  | |
--        | |    INSTALL     | |               +------------------+ |
--        | |                | |               | +----------------+ |
--        | |                | |               | |                | |
--        | |                | |               | |      HTTP      | |
--        | |                | |               | |                | |
--        | +----------------+ +---------------+ +----------------+ |
--        +---------------------------------------------------------+
--
--
--
--
--
--                           Fig 1. Block Diagram
--
--
-------------------------------------------------------------------------------

---------------------
-- load lnet library
---------------------
loadlib("lsys")
loadlib("lutil")
loadlib("lfile")
loadlib("lnet")

require("datastore.lua")
-------------------------------------------------------------------------------
--
-- 1. HTTP Module
-- --------------
--
--  This module is responcible for adding HTTP and application specific headers
--  and send the HTTP request to the server via lnet library.
--  Calls back the caller using the callback provided when sending the request
--
-------------------------------------------------------------------------------

-- http_headers
--    - Table that contains all http headers received in the response.
--    - status_code - is the HTTP status code

local http_webrequest_table = {}
local http_pcs_token
local http_pcs_ver
local http_timeout
local http_path_name = {}
local http_callback = {}
local http_http_method = {}
local http_request_type = {}
local http_headers = {}
local fetch_config = {}
local http_timeout_table = {}


-- Proxy-Authorization
function get_proxy_authorization()
   local data_string

   data_string = sys.get_config_string(CFGI_NETWORK_ACCESS_IDENTIFIER) .. ":pcs"

   return "Proxy-Authorization: Basic " .. base64.encode(data_string, string.len(data_string)) .. "\r\n"
end

-- Accept
function get_accept()
   return "Accept: " .. "x-pcs/ondemand.content;text/plain,x-pcs/ondemand.content;application/zip,text/plain\r\n"
end

-- Accept-Language
function get_accept_language()
   return "Accept-Language: " .. "en-us\r\n"
end

-- X-wap-profile
function get_wap_profile()
   print("WAP Profile is .. " .. (fetch_config.wap_profile_url or "nil"))
   return "X-wap-profile: " .. fetch_config.wap_profile_url .. "\r\n"
end

-- X-pcs-ver
function get_pcs_ver()
   local http_pcs_ver = datastore.get_pcs_ver()
   local pcs_ver = "X-pcs-ver: "

   if http_pcs_ver then
      pcs_ver = pcs_ver .. http_pcs_ver .. ","
   end

   pcs_ver = pcs_ver .. "miuibase=" .. datastore.get_miui_base()
   pcs_ver = pcs_ver .. ",miuitrig=" .. datastore.get_miui_triglet()
   pcs_ver = pcs_ver .. ",ondemandtrig=" .. datastore.get_ondemand_triglet()
   pcs_ver = pcs_ver .. "\r\n"

   return pcs_ver
end

-- X-pcs-cmid
function get_pcs_cmid()
   local data_string

   data_string = fetch_config.mdn

   local out_string, nErr = sha1.hash(data_string, string.len(data_string))
   print("Hash string = ")
   print(out_string)

   local hash_string = base64.encode(out_string, string.len(out_string))
   print("Base64 encoded hash string = ")
   print(hash_string)

   return "X-pcs-cmid: " .. hash_string .. "\r\n"
end

-- X-pcs-lv
function get_pcs_lv()
   -- TODO:
   -- Should we follow as below?
   -- If UI Active, use current-time and
   -- If UI Inactive, use last_view
   -- Update last_view when UI goes to inactive?
   return "X-pcs-lv: " .. (fetch_config.last_view or "nil") .. "\r\n"
end

-- X-pcs-token
function get_pcs_token()
   if http_pcs_token then
      return "X-pcs-token: " .. http_pcs_token .. "\r\n"
   else
      return "X-pcs-token: \r\n"
   end
end

-- Content-Type for POST only
function get_content_type()
   -- Handmark Integration
   return "Content-Type: " .. "application/x-www-form-urlencoded" .. "\r\n"

end

-- Content-Length for POST only
function get_content_length(body)
   return "Content-Length: " .. string.len(body) .. "\r\n"
end

------------------------------------------------------------------------------
-- fetch_http_write
-- (
--    <string> pathname,
--    <string> data
-- )
--
-- Utiliy function to write data into a file.
--
------------------------------------------------------------------------------
function fetch_http_write(pathname, data)
   print("Entering fetch_http_write\(\) ...")

   local fobj, err
   local err_str, err_num

   err = file.test(pathname)
   if true == err then
      print(pathname .. "file exists ...")
      print("Removing the file ...")
      err = file.remove(pathname)
   end

   fobj, err_str, err_num = io.open(pathname, "w")
   print("After io.open, fobj: " .. tostring(fobj) .. " err_str: " .. tostring(err_str) .. " err_num: " .. tostring(err_num))

   if fobj then

      -- Write to file
      err, err_str, err_num = fobj:write(data)
      print("After fptr.write, err: " .. tostring(err) .. " err_str: " .. tostring(err_str) .. " err_num: " .. tostring(err_num))

      fobj:flush()

      -- Close the file
      fobj:close() 
   end

   print("Leaving fetch_http_write\(\) ...")
   return err_num
end

------------------------------------------------------------------------------
-- fetch_http_header_callback
-- (
--    <number> webreq,
--    <string> headername,
--    <string> headervalue
-- )
--
-- Callback function called for each header received by lnet
--
------------------------------------------------------------------------------
function fetch_http_header_callback(webreq, headername, headervalue)
   print("Entering fetch_http_header_callback\(\) ...")

   local url = http_webrequest_table[webreq]

   if url then
      -- Copy the HTTP headers
      http_headers[url][headername] = headervalue
   end

   -- print header to stdout
   print("** hdr  " .. headername .. ": " .. headervalue)
   print("Leaving fetch_http_header_callback\(\) ...")
end

------------------------------------------------------------------------------
-- fetch_http_readcomplete_callback
-- (
--    <number> webreq,
--    <string> data,
--    <number> readErr
-- )
--
-- Callback function called on completion of read by lnet
--
------------------------------------------------------------------------------

function fetch_http_readcomplete_callback(webreq, data, readErr)
   print("Entering fetch_http_readcomplete_callback\(\) ...")

   local url = http_webrequest_table[webreq]
   local result = readErr
   local headers = {} 
   local err

   headers = http_headers[url]
   http_headers[url] = {}

   -- Log
   print("fetch_http: fetch_http_readcomplete_callback")
   print("Printing pay load")
   print(data)

   print("readErr is ..." .. (readErr or "nil"))

   if url then

      webrequest.stop(webreq)
      http_webrequest_table[webreq] = nil

      if readErr >= 0 then
      -- Successfully read

         result = 0
         print("String length of data : " .. string.len(data))

         if 200 == headers.status_code then
            if string.find(headers["Content-Type"], "x-pcs/ondemand.content;application/zip") then

               -- Write the data into a file.
               err = fetch_http_write(http_path_name[url], data)
               data = nil
               if nil ~= err then
               -- File error occured
                  result = 0 - err
                  headers = nil
               end
            end
         end
      end

      -- Update Timed HTTP with pay_load and HTTP headers
      http_callback[url](url, result, headers, data)

   end

   print("Leaving fetch_http_readcomplete_callback\(\) ...")
   return
end

------------------------------------------------------------------------------
-- http_check_mandatory_headers
-- (
--    <table> http_headers
-- )
--
-- Function to test if we received the mandatory HTTP headers
--
------------------------------------------------------------------------------
function http_check_mandatory_headers(http_headers)
   print("Entering http_check_mandatory_headers\(\) ...")

   local result = true
   
   print("Content-Type is : " .. tostring(http_headers["Content-Type"]))

   if nil == http_headers["Content-Type"] then
      result = false
   elseif http_headers.status_code > 299 and http_headers.status_code < 400 and nil == http_headers["Location"] then
      result = false
   end

   print("Leaving http_check_mandatory_headers\(\) ...")
   return result
end

------------------------------------------------------------------------------
-- fetch_http_connect_callback
-- (
--    <number> webreq,
--    <number> conErr
-- )
--
-- Callback function called on completion of connection to server by lnet
--
------------------------------------------------------------------------------
function fetch_http_connect_callback(webreq, conErr)  
   print("Entering fetch_http_connect_callback\(\) ...")

   local url = http_webrequest_table[webreq]
   local result
   local headers = {}

   -- Log
   print("fetch_http: webreq = ")
   print(webreq)

   print("fetch_http: conErr = ")
   print(conErr)

   if url then

      -- Cancelling X-pcs-http-timeout timer
      for timer_id in pairs(http_timeout_table) do
         if webreq == http_timeout_table[timer_id] then
            err = sys.canceltimer(timer_id)
            http_timeout_table[timer_id] = nil
            break
         end
      end

      if conErr < 0 then
      -- Failed to connect to the server

         -- Clear the webrequest
         webrequest.stop(webreq)
         http_webrequest_table[webreq] = nil

         result = conErr

         http_headers[url] = {}

         -- Report the failure to Timed HTTP
         http_callback[url](url, result, nil, nil)

      elseif conErr > 0 then
      -- Got response from the server

         -- Store HTTP Status code
         http_headers[url].status_code = conErr

         local result = http_check_mandatory_headers(http_headers[url])

	 if false == result then
         -- Mandatory headers missing

            print("Mandatory headers missing in the response ...")

            -- Clear the webrequest
            webrequest.stop(webreq)
            http_webrequest_table[webreq] = nil

            result = -640

            http_headers[url] = {}

            -- Report the failure to Timed HTTP
            http_callback[url](url, result, nil, nil)

	    return
         end

         datastore.set_http_status_code(conErr)

         -- Store received token
         http_pcs_token = http_headers[url]["X-pcs-token"]
         datastore.set_pcs_token(http_pcs_token)

         -- Store received pcs version
         http_pcs_ver = http_headers[url]["X-pcs-ver"]
         --datastore.set_pcs_ver(http_pcs_ver)

         -- Store received HTTP time-out value
         local timeout = http_headers[url]["X-pcs-http-timeout"]

         if timeout then
         -- X-pcs-http-timeout header is present in the response
            if "" == timeout then
            -- Value is empty, revert back to default value i.e. 10 seconds
               print("X-pcs-http-timeout header is empty")
               http_timeout = 10
               datastore.set_http_timeout(http_timeout)
            elseif tonumber(timeout) then
            -- Value is a proper number. Convert to number and update
               http_timeout = tonumber(timeout)
               datastore.set_http_timeout(http_timeout)
            end
         end

         if 1 == http_http_method[url] then
         -- GET response

            if 200 == http_headers[url].status_code then
               -- read bytes from the connection
               nErr = webrequest.read(webreq, -1, fetch_http_readcomplete_callback)
            elseif 301 == http_headers[url].status_code or 307 == http_headers[url].status_code then
               webrequest.stop(webreq)
               http_webrequest_table[webreq] = nil

               print("Resending the request using url " .. http_headers[url]["Location"])
               -- Send the request using the URL present in the Location header.
               http_send_request(url, http_http_method[url], http_request_type[url], http_path_name[url], http_callback[url], http_headers[url]["Location"])

               http_headers[url] = {}
            else
            -- Not required to read in case of other status codes

               -- Clear the webrequest
               webrequest.stop(webreq)
               http_webrequest_table[webreq] = nil

               result = 0

               headers = http_headers[url]
               http_headers[url] = {}

               -- Report the failure to Timed HTTP
               http_callback[url](url, result, headers, nil)
            end
         else
         -- POST response
            if 301 == http_headers[url].status_code or 307 == http_headers[url].status_code then
               webrequest.stop(webreq)
               http_webrequest_table[webreq] = nil

               print("Resending the request using url " .. http_headers[url]["Location"])
               -- Send the request using the URL present in the Location header.
               http_send_request(url, http_http_method[url], http_request_type[url], http_path_name[url], http_callback[url], http_headers[url]["Location"])

               http_headers[url] = {}
            else
               -- Clear the webrequest
               webrequest.stop(webreq)
               http_webrequest_table[webreq] = nil

               result = 0

               headers = http_headers[url]
               http_headers[url] = {}

               -- Report the failure to Timed HTTP
               http_callback[url](url, result, headers, nil)

            end
         end
      else
      -- Unexpected error from lnet.
      end
   end

   print("Leaving fetch_http_connect_callback\(\) ...")
   return
end


-------------------------------------------------------------------------------
--
-- Callback function for X-pcs-http-timeout
--
-------------------------------------------------------------------------------
function http_timeout_callback(timer_id)
   print("Entering http_timeout_callback\(\) ...")
   local err, connectreq

   connectreq = http_timeout_table[timer_id]
   print("connectreq : " .. tostring(connectreq))

   if connectreq then
      local url = http_webrequest_table[connectreq]
      print("url is " .. tostring(url))

      err = webrequest.stop(connectreq)
         -- Report the failure to Timed HTTP
      if url then
         -- Notify Timed HTTP with -530 as the error
         http_callback[url](url, -530, nil, nil)
      end
   end
   print("Leaving http_timeout_callback\(\) ...")
end

-------------------------------------------------------------------------------
-- http_send_request
-- (
--    <string> url,
--    <number> http_method,
--    <number> request_type,
--    <string> path_name,
--    <function> callback
-- )
--
-- - Sends HTTP request to the server via lnet library functions
-- - Adds required headers and sends the request by calling multiple lnet
--   library functions
--
-- url - url of the object to be fetched
-- http_method - is the HTTP request method. Could be one of GET=1 and POST=2
-- request_type - If this is a manual or automatic update. Could be one of
--                Manual=1 and Automatic=2
-- path_name - Location in the FS, where the fetched object need to be stored.
-- callback - Function provided by SCHEDULER to call on receving a response
--            (Failure/Success).
-- tmp_url - In case of re-send for HTTP status code 301 and 307
--
-------------------------------------------------------------------------------
function http_send_request(url, http_method, request_type, path_name, callback, tmp_url)
   print("Entering http_send_request\(\) ...")

   local err = 0

   print("URL being attempted is..")
   print(url)
   -- create a new webrequest
   connectreq = webrequest.new()
   if not connectreq then
      print("fetch_http: webrequest.new returns nil")
      return 1
   end

   print("fetch_http: connectreq = ")
   print(connectreq)

   -- Proxy-Authorization
   header_value = get_proxy_authorization()

   -- Accept
   header_value = header_value .. get_accept()

   -- Accept-Language
   header_value = header_value .. get_accept_language()

   -- X-wap-profile
   header_value = header_value .. get_wap_profile()

   -- X-pcs-ver
   header_value = header_value .. get_pcs_ver()

   -- X-pcs-cmid
   header_value = header_value .. get_pcs_cmid()

   -- X-pcs-update-mode
   if 1 == request_type then
      header_value = header_value .. "X-pcs-update-mode: manual\r\n"
   else
      header_value = header_value .. "X-pcs-update-mode: automatic\r\n"
   end

   -- X-pcs-token
   header_value = header_value .. get_pcs_token()

   if 2 == http_method then
   -- POST

      path_name = "zipcode=" .. path_name
      -- For POST, path_name contains the zipcode
      err = webrequest.addopt(connectreq, WEBOPT_BODY, path_name) 

      -- Content-Length for POST only
      err = webrequest.addopt(connectreq, WEBOPT_CONTENTLENGTH, string.len(path_name))

      -- Setting method as POST
      print("Calling webrequest.addopt ...")
      err = webrequest.addopt(connectreq, WEBOPT_METHOD, "POST")

      -- Content-Type for POST only
      header_value = header_value .. get_content_type()
   else
   -- GET

      -- X-pcs-lv
      header_value = header_value .. get_pcs_lv()
   end

   header_value = header_value .. "Cache-Control: no-cache\r\n"

   -- get serving system info
   local tssinfo, err, nw_type_str

   tssinfo, err = sys.get_servingsysinfo()

   if nil ~= tssinfo then
      print("network type is : " .. tostring(tssinfo.sys_mode))

      if (tssinfo.sys_mode == AEET_SYS_MODE_CDMA) then
         nw_type_str = "IS2000"
      elseif (tssinfo.sys_mode == AEET_SYS_MODE_HDR) then
         nw_type_str = "EVDO"
      elseif (tssinfo.sys_mode == AEET_SYS_MODE_WCDMA) then
         nw_type_str = "WCDMA"
      elseif (tssinfo.sys_mode == AEET_SYS_MODE_WLAN) then
         nw_type_str = "WLAN"
      else
         nw_type_str = "OTHER"
      end
   end
   
   if nil == nw_type_str then
      nw_type_str = "none"
   end

   header_value = header_value .. "X-network-type: " .. nw_type_str .. "\r\n"

   print("Calling webrequest.addopt ...")
   err = webrequest.addopt(connectreq, WEBOPT_HEADER, header_value)

   -- Adding PROXY SPEC
   print("proxy_gw_url is " .. tostring(fetch_config.proxy_gw_url))
   if nil ~= fetch_config.proxy_gw_url then
      print("Adding PROXY SPEC", fetch_config.proxy_gw_url)
      err = webrequest.addopt(connectreq, WEBOPT_PROXYSPEC, fetch_config.proxy_gw_url)
   end

   -- Adding User-Agent
   user_agent_value = fetch_config.manufacturer_name .. "/" .. fetch_config.model_name .. "/" .. "OnDemand"
   err = webrequest.addopt(connectreq, WEBOPT_USERAGENT, user_agent_value)

   print("Calling webrequest.addopt ...")
   err = webrequest.addopt(connectreq, WEBOPT_HEADERHANDLER, fetch_http_header_callback)

   print("Calling webrequest.getresponse ...")
   -- Connect to OnDemand Server
   if tmp_url then
      err = webrequest.getresponse(connectreq, tmp_url, fetch_http_connect_callback)
   else
      err = webrequest.getresponse(connectreq, url, fetch_http_connect_callback)
   end
   print("err after getresponse")
   print(err)

   if 0 ~= err then
      http_path_name[url] = path_name
      http_callback[url] = callback
      http_http_method[url] = http_method
      http_request_type[url] = request_type
      http_webrequest_table[connectreq] = url
      local timer_id
      print("Starting HTTP Timeout timer ... " .. tostring(http_timeout))
      timer_id, err = sys.settimer (http_timeout * 1000, http_timeout_callback)
      http_timeout_table[timer_id] = connectreq
   else
      http_path_name[url] = nil
      http_callback[url] = nil
      http_http_method[url] = nil
      http_webrequest_table[connectreq] = nil

      -- TODO: Release the webconnect resource
      err = webrequest.stop(connectreq)
      http_webrequest_table[connectreq] = nil
   end

   http_headers[url] = {}

   print("Leaving http_send_request\(\) ...")
end


------------------------------------------------------------------------------
-- http_cancel_request
-- (
--    <string> url
-- )
--
-- - Cancels the fetch initiated in last call to http_send_request for object
--   located at the given URL
--
-- url - url of the object to be fetched
--
------------------------------------------------------------------------------
function http_cancel_request(url)
   print("Entering http_cancel_request\(\) ...")

   local err = 0

   for conn_id in pairs(http_webrequest_table) do
      if url == http_webrequest_table[conn_id] then
         err = webrequest.stop(conn_id)
         http_webrequest_table[conn_id] = nil
      end
   end

   print("Leaving http_cancel_request\(\) ...")
   return err
end

-------------------------------------------------------------------------------
--
-- 2. TIMED HTTP Module
-- --------------------
--
--  This module is responcible for setting timers for sending the HTTP request.
--  On timer expiry will call the HTTP module functions to send the request.
--
-- time is a list of next-get times
--
-------------------------------------------------------------------------------

-- thttp_requesttime_table
--    - Table maintains all URLs in the Automatic list, with key as timer_id
--      returned by call to settimer() for next-get-time
local thttp_requesttime_table = {}

-- thttp_time_index
--    - Table maintains current index in thttp_time_list for each URL
local thttp_time_index = {}

-- thttp_time_list
--    - Table maintains list of next-get-times for each URL, with key as URL
--      This is a multi-dimensional table or table of arrays.
local thttp_time_list = {}

-- thttp_http_method
--    - Table maintains http_method for each URL, indexed using URL
local thttp_http_method = {}

-- thttp_request_type
--    - Table maintains request_type for each URL, indexed using URL
local thttp_request_type = {}

-- thttp_pathname
--    - Table maintains path_name for each URL, indexed using URL
local thttp_pathname = {}

-- thttp_callback
--    - Table maintains callback function for each URL, indexed using URL
local thttp_callback = {}

-- thttp_automatic_request
--    - Variable maintains state of the automatic request
local thttp_automatic_request

-------------------------------------------------------------------------------
-- thttp_send_request
-- (
--    <string> url,
--    <array> time_list,
--    <number> http_method,
--    <number> request_type,
--    <string> path_name,
--    <function> callback
-- )
--
-- Fetches the object located at the given URL at the specified time.
--
-- url - url of the object to be fetched
-- time_list - List of times when thttp should initiate a request to the server
-- http_method - is the HTTP request method. Could be one of GET=1 and POST=2
-- request_type - If this is a manual or automatic update. Could be one of
--                Manual=1 and Automatic=2
-- path_name - Location in the FS, where the fetched object need to be stored.
-- callback - Function provided by SCHEDULER to call on receving a response
--            (Failure/Success).
--
-------------------------------------------------------------------------------
function thttp_send_request (url, time_list, http_method, request_type, path_name, callback)
   print("Entering thttp_send_request \(\) ...")

   local timer_id
   local err = 0

   if not http_method then
      print("http_method is nil ...")
   end

   print("url is .." .. (url or "nil"))
   if 2 == http_method then
   -- POST

      err = http_send_request (url, http_method, request_type, path_name, thttp_http_callback, nil)
   else
   -- GET

      -- Cancel, if any, outstanding request present in THTTP
      thttp_cancel_request(url)

      -- Call timer with first time that falls after current time in time_list
      if time_list then
         print("time_list is not nil")
      else
         print("time_list is nil")
      end
      
      --print("time_list is ..." .. (time_list or "nil"))
      if time_list then
         local i = 1

         print("Next-get-time :")
         print(net.utc_to_http(time_list[1]))

         -- Assuming the timestamps are in chronological order
         while time_list[i] and time_list[i] < net.getutctime() do
            i = i + 1
         end

         print("Value of i is .. " .. i)
         print("Value of time_list[i] is .. " .. (time_list[i] or "nil"))
         if time_list[i] then
            timer_id, err = sys.settimer ((time_list[i] - net.getutctime()) * 1000, thttp_requesttime_callback)

            print("timer_id after sys.settimer : " .. timer_id)

         -- if err is SUCCESS
            thttp_requesttime_table[timer_id] = url

            print("thttp_requesttime_table at timer_id is .." .. (thttp_requesttime_table[timer_id] or "nil"))
            thttp_time_index[url] = i
            for index in pairs(time_list) do
               thttp_time_list[url][index] = time_list[index]
            end
         else
            datastore.set_nextgettime(nil)
            return 2 -- All time-stamps fall in the past
         end
      else
         err = http_send_request (url, http_method, request_type, path_name, thttp_http_callback, nil)
      end
   end

   -- if err is SUCCESS
      thttp_http_method[url] = http_method
      thttp_request_type[url] = request_type
      thttp_pathname[url] = path_name
      thttp_callback[url] = callback

   print("Leaving thttp_send_request \(\) ...")
   return err
end

-------------------------------------------------------------------------------
-- thttp_cancel_request
-- (
--    <string> url,
-- )
--
-- Cancels the previously started fetch
--
-- url - url of the object who's fetch is to be cancelled
--
-------------------------------------------------------------------------------
function thttp_cancel_request(url)
   print("Entering thttp_cancel_request\(\) ...")

   local found

   for timer_id in pairs(thttp_requesttime_table) do
      if url == thttp_requesttime_table[timer_id] then
         err = sys.canceltimer(timer_id)

         thttp_requesttime_table[timer_id] = nil
         found = true
      end
   end

   http_cancel_request(url)

   thttp_time_index[url] = nil
   thttp_time_list[url] = {}

   thttp_http_method[url] = nil
   thttp_request_type[url] = nil
   thttp_pathname[url] = nil
   thttp_callback[url] = nil

   print("Leaving thttp_cancel_request\(\) ...")
   return
end

-------------------------------------------------------------------------------
-- thttp_requesttime_callback
-- (
--    <number> timer_id
-- )
--
-- Callback function for next-get-time time-out
--
-- timer_id - Handle for the timer callback.
--
-------------------------------------------------------------------------------
function thttp_requesttime_callback(timer_id)
   print("Entering thttp_requesttime_callback\(\) ...")

   local url

   url = thttp_requesttime_table[timer_id]
   print("URL is .. " .. (url or "nil"))
   print("timer_id is .. " .. (timer_id or "nil"))

   if url then
      thttp_requesttime_table[timer_id] = nil

      if true == fetch_config.automatic_enable then
         print("thttp_automatic_request" .. tostring(thttp_automatic_request))
         if not thttp_automatic_request then
            err = http_send_request (url, thttp_http_method[url], thttp_request_type[url], thttp_pathname[url], thttp_http_callback, nil)
            thttp_automatic_request = true
         end

         local i = thttp_time_index[url] + 1
         local time_list = thttp_time_list[url]

         -- Assuming the timestamps are in chronological order
         while time_list[i] and time_list[i] < net.getutctime() do
            i = i + 1
         end

         if time_list[i] then
            timer_id, err = sys.settimer ((time_list[i] - net.getutctime()) * 1000, thttp_requesttime_callback)

            -- if err is SUCCESS
               thttp_requesttime_table[timer_id] = url
            -- if FAILURE, call the scheduler supplied callback to notify
         else
            datastore.set_nextgettime(nil)
         end
         thttp_time_index[url] = i
      else
      -- TODO: Add any cleaning to be done here
      end
   end
   -- if FAILURE, call the scheduler supplied callback to notify

   print("Leaving thttp_requesttime_callback\(\) ...")
end

-------------------------------------------------------------------------------
-- thttp_http_callback
-- (
--    <string> url,
--    <number> result,
--    <table> http_headers,
--    <string> data
-- )
--
-- Callback function called by HTTP to indicate success/failure to fetch an
-- object specified by the URL
--
-- url - url of the object to be fetched
-- result - SUCCESS if successful in fetching the response, else the error code
-- http_headers - List of required HTTP headers from the response.
-- data - String in case of full-story or any erro message from the server
--        Ignore in case of Lua code in a zip file.
--
-------------------------------------------------------------------------------
function thttp_http_callback(url, result, http_headers, data)
   print("Entering thttp_http_callback\(\) ...")

   local table = {}

   table.http_method = thttp_http_method[url]
   table.request_type = thttp_request_type[url]
   table.pathname = thttp_pathname[url]


   if 2 == thttp_http_method[url] then
      thttp_time_index[url] = nil
      thttp_time_list[url] = {}
      thttp_http_method[url] = nil
      thttp_request_type[url] = nil
      thttp_pathname[url] = nil
   else
      local time_list = thttp_time_list[url]
      local i = thttp_time_index[url]

      if 2 == thttp_request_type[url] then
      -- Automatic Request

         thttp_automatic_request = nil
         print("thttp_automatic_request is set to nil")
      end

      if not time_list[i] then
         thttp_time_index[url] = nil
         thttp_time_list[url] = {}
         thttp_http_method[url] = nil
         thttp_request_type[url] = nil
         thttp_pathname[url] = nil
      end
   end

   -- Call the scheduler supplied callback to notify about failure/success
   thttp_callback[url](url, result, http_headers, data, table)

   print("Leaving thttp_http_callback\(\) ...")
end

-------------------------------------------------------------------------------
--
-- 3. INSTALL Module
-- -----------------
--
--  This module is responcible for installing the content received from the
--  server onto the Data store.
--
-------------------------------------------------------------------------------
local install = {}
install.showtime = {}
install.expiretime = {}

-------------------------------------------------------------------------------
-- install_expiretime_callback
-- (
--    <number> timer_id,
-- )
--
-- Callback function for expire_time timer
--
-------------------------------------------------------------------------------
function install_expiretime_callback(timer_id)
   print("Entering install_expiretime_callback\(\) ...")

   if timer_id ~= install.expiretime.timer_id then
      -- Log an error statement
   else
      if false == fetch_config.ui_active then
         datastore.removeContent()
         install.expiretime = {}
         datastore.set_expiretime(nil)
      else
         install.expiretime.timer_id = nil
         install.expiretime.timer_fired = true
         datastore.set_expiretime(install.expiretime)
      end
   end

   print("Leaving install_expiretime_callback\(\) ...")
end

------------------------------------------------------------------------------
-- install_showtime_callback
-- (
--    <number> timer_id,
-- )
--
-- Callback function for show_time timer
--
------------------------------------------------------------------------------
function install_showtime_callback(timer_id)
   print("Entering install_showtime_callback\(\) ...")

   if timer_id ~= install.showtime.timer_id then
      -- Log an error statement
      print("timer_id mismatch -> timer_id :" .. timer_id .. ", install.showtime.timer_id :" )
   else
      if false == fetch_config.ui_active then
         install_applyto_datastore(install.showtime.url, install.showtime.path_name, install.showtime.zip_file, true, install.showtime.pcs_ver)
         install.showtime = {}
         datastore.set_showtime(nil)
      else
         install.showtime.timer_id = nil
         install.showtime.timer_fired = true
         datastore.set_showtime(install.showtime)
      end
   end

   print("Leaving install_showtime_callback\(\) ...")
end

function purge_files(name)
   for fn in file.enum(name) do
      file.remove(fn)
   end
end
------------------------------------------------------------------------------
-- install_applyto_datastore
-- (
--    <string> url,
--    <string> path_name,
--    <boolean> zip_file,
--    <boolean> persist,
--    <string> pcs_ver
-- )
--
-- Installs the payload onto datastore
--
-- path_name - Location of the file residing on the FS
--
-- zip_file - Indicates whether the file is a text file or zip file
--            true = zip file, false = text file
--
------------------------------------------------------------------------------
function install_applyto_datastore(url, path_name, zip_file, persist, pcs_ver)
   print("Entering install_applyto_datastore\(\) ...")

   local err
   local datapackagename = nil
   local datapackagefound = false

   if zip_file then

      -- Remove already existing files in the archive
      for archfile in zip.enum(path_name) do
         err = file.remove("fs:/~/" .. archfile)
         print("err from file.remove for " .. archfile .. " (archive case) is .." .. (err or "nil"))

         -- Look for datapackage.lua file in the zip - this will be the name of the datapackage
         if not datapackagefound then
            if string.find(archfile, ".[Ll][Uu][Aa]") then
               datapackagename = "fs:/~/" .. archfile
               datapackagefound = true
            end
         end
      end

      -- Unzip the contents if zip_file is true
      print("Install : Unzipping the file " .. path_name)
      err = zip.uncompress(path_name, "fs:/~/")

      print("Install : After unzipping the file, err is ")
      print(err)

      -- Run the payload script
      if (datapackagefound == true) then
         print("Install : Executing the payload")
         local result = datastore.run_payload (datapackagename, url, persist)

         if 0 == result then
            datastore.set_pcs_ver(pcs_ver)
         end

         for archfile in zip.enum(path_name) do
            err = file.test("fs:/~/" .. archfile)
   
            if false == err then
               zip.uncompressfile(path_name, archfile, "fs:/~/")
            end
         end

         -- Delete the datapackage lua file from the FS
         err = file.remove(datapackagename)
      end

      print("path_name is : " .. path_name)

      -- Delete the zip file from the FS
      print("Install : Removing the ZIP file " .. path_name)
      err = file.remove(path_name)

      print("err from file.remove is .." .. (err or "nil"))
   else

      -- TODO: Move the file to application root directory if the file is in
      -- some other directory
      -- OR
      -- make sure the file is created in the applicatin root directory
      err = file.test("datapackage.lua")

      if true == err then
         file.remove("datapackage.lua")
      end

      file.move(path_name, "datapackage.lua")

      -- Run the payload script
      print("Install : Executing the payload")
      datastore.run_payload("datapackage.lua", url, persist)
   end

   -- datastore.set_last_update_time(net.getutctime())
   -- Fetch is not supposed to delete contents unzipped. They would be
   -- over-written if the same file comes in.

   print("Leaving install_applyto_datastore\(\) ...")
   return
end


------------------------------------------------------------------------------
-- install_update_showtime
-- (
-- )
--
-- Updates the install.showtime table
--
------------------------------------------------------------------------------
function install_update_showtime(url, path_name, zip_file, show_time, pcs_ver)
   print("Entering install_update_showtime\(\) ...")

   local err
   local timer_id

   print("Show time is from now " .. (show_time - net.getutctime()))
   print("Current time is ... " .. net.utc_to_http(net.getutctime()))
   print("X-pcs-next-showtime is ... " .. net.utc_to_http(show_time))

   if 0 == show_time then
      -- Starting timer with 0 milli seconds
      print("Starting timer with 0 milli seconds ...")
      timer_id, err = sys.settimer (0, install_showtime_callback)
      show_time = net.getutctime()
   else
      timer_id, err = sys.settimer ((show_time - net.getutctime()) * 1000, install_showtime_callback)
   end

   print("timer_id after sys.settimer : " .. timer_id)
   if not err then
   -- Timer is set up succesfully
      if install.showtime.timer_id then
         -- Cancel the timer started earlier
         err = sys.canceltimer(install.showtime.timer_id)
      end

      -- File might exist, even though timer is nil.
      if install.showtime.path_name then

         -- Delete files from the FS
         err = file.remove(install.showtime.path_name)
      end

      -- Re-initializing showtime
      install.showtime = {}
      install.showtime.path_name = path_name
      install.showtime.zip_file = zip_file
      install.showtime.timer_id = timer_id
      install.showtime.url = url
      install.showtime.time = show_time
      install.showtime.pcs_ver = pcs_ver
      install.showtime.timer_fired = false

      -- Update datastore with new showtime
      datastore.set_showtime(install.showtime)
      print("install.showtime.timer_id : " .. install.showtime.timer_id)
   else
      err = 2 -- FAILED_TO_SCHEDULE
   end

   print("Leaving install_update_showtime\(\) ...")
   return err
end

------------------------------------------------------------------------------
-- install_update_expiretime
-- (
-- )
--
-- Updates the install.expiretime table
--
------------------------------------------------------------------------------
function install_update_expiretime(expire_time)
   print("Entering install_update_expiretime\(\) ...")

   local err
   local timer_id

   timer_id, err = sys.settimer ((expire_time - net.getutctime()) * 1000, install_expiretime_callback)

   -- TODO: Would sys.settimer() return nil or 0 in case of success?
   -- Assuming 0 in case of success
   if not err then
      if install.expiretime.timer_id then
         -- Cancel the timer started earlier
         err = sys.canceltimer(install.expiretime.timer_id)
      end

      -- Re-initializing expiretime
      install.expiretime = {}
      install.expiretime.timer_id = timer_id
      install.expiretime.timer_fired = false
      install.expiretime.time = expire_time
      datastore.set_expiretime(install.expiretime)

   else
      err = 2 -- FAILED_TO_SCHEDULE
   end

   print("Leaving install_update_expiretime\(\) ...")
   return err
end

------------------------------------------------------------------------------
-- install_response
-- (
--    <string> url,
--    <string> path_name,
--    <number> zip_file, 
--    <number> show_time,
--    <number> request_type,
--    <string> pcs_ver
-- )
--
-- Installs response onto the data store at the specified time.
--
-- show_time and expire_time, represented in integers, are number of seconds
--     that have elapsed since midnight, Jan 6, 1980 GMT.
--
------------------------------------------------------------------------------
function install_response(url, path_name, zip_file, show_time, request_type, pcs_ver)
   print("Entering install_response\(\) ...")

   local err

   if 0 == show_time then
      show_time = nil
   end

   print("path_name : " .. path_name)

   if 1 == request_type then
   -- Response to a Manual request
      install_applyto_datastore(url, path_name, zip_file, false, pcs_ver)
   else
   -- Response to an Automatic request
      if not show_time then                                -- Is show_time nil?
         err = install_update_showtime(url, path_name, zip_file, 0, pcs_ver)
      else
         if show_time > net.getutctime() then
            err = install_update_showtime(url, path_name, zip_file, show_time, pcs_ver)
         else
            err = install_update_showtime(url, path_name, zip_file, 0, pcs_ver)
         end
      end
   end
   print("Leaving install_response\(\) ...")
end

-------------------------------------------------------------------------------
--
-- 4. SCHEDULER Module
-- -------------------
--
--  This module is responcible for scheduling
--   - scheduling to send HTTP requests.
--   - scheduling installation of content received from the server as HTTP
--     response
--
-------------------------------------------------------------------------------
local fetch_url_state

local fetch_callback

local fetch_next_get_url

-- Template of the callback provided to fetch_send_request()
-- client_fetch_callback(url, result, http_headers)
-- http_headers contain the required headers

function scheduler_print_headers(url, http_headers)
   print("Entering scheduler_print_headers\(\) ...")

   if url then
      print("scheduler_print_headers called, url = " .. url)
   end

   if http_headers.status_code then
      print("HTTP Status Code = " .. http_headers.status_code)
   end

   if http_headers["Location"] then
      print("Location :" .. http_headers["Location"])
   end

   if http_headers["Content-Type"] then
      print("Content-Type :" .. http_headers["Content-Type"])
   end

   if http_headers["Content-Length"] then
      print("Content-Length :" .. http_headers["Content-Length"])
   end

   if http_headers["X-pcs-next-get-time"] then
      print("X-pcs-next-get-time :" .. http_headers["X-pcs-next-get-time"])
   end

   if http_headers["X-pcs-next-get-url"] then
      print("X-pcs-next-get-url :" .. http_headers["X-pcs-next-get-url"])
   end

   if http_headers["X-pcs-next-show-time"] then
      print("X-pcs-next-show-time :" .. http_headers["X-pcs-next-show-time"])
   end

   if http_headers["X-pcs-ver"] then
      print("X-pcs-ver :" .. http_headers["X-pcs-ver"])
   end

   if http_headers["X-pcs-expire"] then
      print("X-pcs-expire :" .. http_headers["X-pcs-expire"])
   end

   if http_headers["X-pcs-token"] then
      print("X-pcs-token :" .. http_headers["X-pcs-token"])
   end

   if http_headers["X-pcs-http-timeout"] then
      print("X-pcs-http-timeout :" .. http_headers["X-pcs-http-timeout"])
   end

   print("Leaving scheduler_print_headers\(\) ...")
end

-- Returns the pathname
function scheduler_get_pathname()
   print("Entering scheduler_get_pathname\(\) ...")

   local last_path_id = datastore.get_last_pathid()
   print("last_path_id is .. " .. last_path_id)

   if last_path_id and last_path_id < 429496 then
      last_path_id = last_path_id + 1
   else
      last_path_id = 1
   end

   datastore.set_last_pathid(last_path_id)
   last_path_id = datastore.get_last_pathid()
   print("last_path_id is .. " .. last_path_id)

   print("Leaving scheduler_get_pathname\(\) ...")
   return "fs:/~/od_" .. last_path_id
end

-------------------------------------------------------------------------------
-- scheduler_thttp_callback
-- (
--    <string> url,
--    <number> result,
--    <table> http_headers,
--    <string> data
-- )
--
-- Callback function called by Timed HTTP to indicate success/failure to fetch
-- an object specified by the URL
--
-- url - url of the object to be fetched
-- result - SUCCESS if successful in fetching the response, else the error code
-- http_headers - List of required HTTP headers from the response.
-- data - String in case of full-story or any erro message from the server
--        Ignore in case of Lua code in a zip file.
-- table - Request information.
--
-------------------------------------------------------------------------------
function scheduler_thttp_callback(url, result, http_headers, data, table)
   print("Entering scheduler_thttp_callback\(\) ...")

   local err

   fetch_url_state[url] = nil

   -- If result is SUCCESS
   if 0 == result then
   -- Received a response from the server.

      result = http_headers.status_code
      scheduler_print_headers(url, http_headers)

      if 302 == http_headers.status_code then
         data = http_headers["Location"]
      end

      -- Update X-pcs-next-get-url
      fetch_next_get_url = http_headers["X-pcs-next-get-url"]
      datastore.set_next_url(fetch_next_get_url)

      -- Do we need to do anything with Content-Length?

      if 2 == table.http_method then
      -- If requrest was POST

      elseif 1 == table.http_method then
      -- If requrest was GET

         if http_headers["X-pcs-expire"] then
            local expire_time

            expire_time = net.http_to_utc(http_headers["X-pcs-expire"])

            if expire_time > net.getutctime() then
               install_update_expiretime(expire_time)
            end
         else
            if false == install.expiretime.timer_fired then
               if install.expiretime.timer_id then
                  local err = sys.canceltimer(install.expiretime.timer_id)
                  install.expiretime.timer_id = nil
               end
            else
               install.expiretime.timer_fired = false
            end
            -- TODO: Add script here to cancel the expire-time
         end

         -- Store response headers like last-update-time and
         -- HTTP-response-code on to Data Store. Anything else?
         datastore.set_http_status_code(http_headers.status_code)

         -- if X-pcs-next-get-time is not NULL
         print("X-pcs-next-get-time")
         print(http_headers["X-pcs-next-get-time"])

         if http_headers["X-pcs-next-get-time"] and "" ~= http_headers["X-pcs-next-get-time"] and true == fetch_config.automatic_enable then
            local path_name = scheduler_get_pathname()
            print("scheduler: path_name .. " .. path_name)
            local temp_url = fetch_next_get_url or fetch_config.automatic_url
            local next_get_time = http_headers["X-pcs-next-get-time"]
            local time_list = {}
            local start = 1
            local stop
            local seconds
            local last = string.len(next_get_time)
            local i = 1

            while next_get_time do
               stop = string.find(next_get_time, ";", start)

               if not stop then
                  seconds = net.http_to_utc(string.sub(next_get_time, start, last))
                  if 0 ~= seconds then
                     time_list[i] = seconds
                  end
                  break
               else
                  seconds = net.http_to_utc(string.sub(next_get_time, start, stop - 1))
                  if 0 ~= seconds then
                     time_list[i] = seconds
                     i = i + 1
                  end
               end

               start = stop + 1
            end

            if time_list[1] then
               for index=1,i,1 do
                  print("time_list .." .. (time_list[index] or "nil"))
               end

               local next_get_time_table = {}

               next_get_time_table.url = temp_url
               next_get_time_table.time_list = time_list
               next_get_time_table.path_name = path_name
               datastore.set_nextgettime(next_get_time_table)

               thttp_send_request(temp_url, time_list, 1, 2, path_name, scheduler_thttp_callback)
            else
               print("Empty X-pcs-next-get-time ...")
            end
         end

         if 200 == http_headers.status_code then
         -- If HTTP 200 OK
            local show_time

            if http_headers["X-pcs-next-show-time"] then
               show_time = net.http_to_utc(http_headers["X-pcs-next-show-time"])
            end

            if string.find(http_headers["Content-Type"], "x-pcs/ondemand.content;application/zip") then
               install_response(url, table.pathname, true, show_time, table.request_type, http_headers["X-pcs-ver"])
            elseif string.find(http_headers["Content-Type"], "x-pcs/ondemand.content;text/plain") then
               -- install_response(url, table.pathname, false, show_time, table.request_type, http_headers["X-pcs-ver"])
            elseif string.find(http_headers["Content-Type"], "text/plain") then
            -- if Content-Type is text/plain
            -- (Means an error message is received. Is this true all the time?)
               fetch_url_state[url] = 2
            else

            end
         else
         -- All other HTTP status codes

         end
      else
      -- HTTP Method is neither POST nor GET
         -- Nothing much to do here.
      end
   else
   -- Failed to receive response from the server

   end

   for k in pairs(fetch_callback) do
      print("callback for url " .. k .. " is " .. tostring(fetch_callback[k]))
   end

   -- Delete the entry of this URL from the Outstanding URLs
   local callback = fetch_callback[url]

   print("url = " .. tostring(url))
   print("fetch_callback = " .. tostring(fetch_callback))

   fetch_callback[url] = nil
   fetch_url_state[url] = nil
   print("Callback is .." .. tostring(callback))

   if callback then
      callback(url, result, data)
   end

   print("Leaving scheduler_thttp_callback\(\) ...")
   return
end

------------------------------------------------------------------------------
-- scheduler_run_install_timers
-- (
--    <boolean> persist
-- )
--
-- Runs the next-show-time and expire-time
--
-- persist - Boolean flag indicating whether to persist or not
--         - true : persist
--         - false : not persist
------------------------------------------------------------------------------
function scheduler_run_install_timers(persist)
   print("Entering scheduler_run_install_timers\(\) ...")

   if install.expiretime.timer_fired then
      datastore.removeContent()
      if install.showtime.timer_fired then
         if install.showtime.time > install.expiretime.time then
            install_applyto_datastore(install.showtime.url, install.showtime.path_name, install.showtime.zip_file, persist, install.showtime.pcs_ver)
         else
            -- Show time before Expire time. Delete the file
            print("Show time before Expire time. Delete the file")
            file.remove(install.showtime.path_name)
         end
         install.showtime = {}
         datastore.set_showtime(nil)
      end
      install.expiretime = {}
      datastore.set_expiretime(nil)
   else
      if install.showtime.timer_fired then
         install_applyto_datastore(install.showtime.url, install.showtime.path_name, install.showtime.zip_file, persist, install.showtime.pcs_ver)
         install.showtime = {}
         datastore.set_showtime(nil)
      else
         if true == persist then
            -- Persisting, data updated during Foreground request
            print("Persisting, data updated during Foreground request")
            datastore.persist()
         end
      end
   end

   print("Leaving scheduler_run_install_timers\(\) ...")
end
-------------------------------------------------------------------------------
--
-- 5. FETCH External Functions
-- ---------------------------
--
-------------------------------------------------------------------------------


-------------------------------------------------------------------------------
--
-- fetch_url_state - Maintains states of each URL requested. States are namely
--                   INIT, REQ_SENT = 1, RESP_RCVD = 2 and
--                   RESP_RCVD_REQ_SENT = 3
--
--
--
--
--                          +----------+
--                          |REQ_SENT=1|
--                          +----------+                           response
--                       _               \                           received
--                       /|      |         \                            with
--                     /         |           \                      X-pcs-next
--                   /           |      response received with        -get-time
--                 /             |         X-pcs-next-get-time     _______
--         request sent          |                 \              /       \
--             /                 |                   \           /         \
--           /                   |                    _|         |         |
--     +--------+   response received without +------------------------+   |
--     |INIT=nil|        X-pcs-next-get-time  |RESP_RCVD_AND_REQ_SENT=3|   |
--     +--------+                |            +------------------------+   |
--          _                    |                               /\        /
--         |\                    |                     /          \_______/
--            \                  |                   /
--              \                |      response received without
--                \              |         X-pcs-next-get-time
--          response installed   |             /
--                    \          |           /
--                      \        |         /
--                               \/     |_
--                         +-----------+
--                         |RESP_RCVD=2|
--                         +-----------+
--
--
--
--
--                           Fig 2. State Diagram
--
-------------------------------------------------------------------------------

------------------------------------------------------------------------------
-- fetch_init()
--
-- Initializes Fetch module
--
------------------------------------------------------------------------------
function fetch_init()
   print("Entering fetch_init\(\) ...")

   if not fetch_config.init_done then

      fetch_callback = {}

      fetch_url_state = {}

      -- Read the config items and place them into a table.

      -- Making a local copy of MDN
      fetch_config.mdn = sys.get_deviceinfo_string(AEE_DEVICEITEM_MDN)
      print(fetch_config.mdn)

      -- Making a local copy of MANUFACTURER NAME
      fetch_config.manufacturer_name = sys.get_deviceinfo_string(AEE_DEVICEITEM_MANUFACTURER_NAME)
      print(fetch_config.manufacturer_name)

      -- Making a local copy of MODEL NAME
      fetch_config.model_name = sys.get_deviceinfo_string(AEE_DEVICEITEM_MODEL_NAME)
      print(fetch_config.model_name)

      -- Making a local copy of WAP PROFILE
      fetch_config.wap_profile_url = sys.get_config_string(CFGI_WAP_PROFILE_URL)
      print(fetch_config.wap_profile_url)

      -- Making a local copy of ONDEMAND SERVER NAME
      fetch_config.server_name = sys.get_config_string(CFGI_OD_SERVER_NAME)
      print(fetch_config.server_name)

      -- Making a local copy of NAI
      fetch_config.nai = sys.get_config_string(CFGI_NETWORK_ACCESS_IDENTIFIER)
      print(fetch_config.nai)

      -- Making a local copy of ONDEMAND SERVER PORT
      fetch_config.server_port = sys.get_config_number(CFGI_OD_SERVER_PORT)
      print(fetch_config.server_port)

      -- Making a local copy of ONDEMAND GATEWAY SERVER NAME
      fetch_config.gw_server_name = sys.get_config_string(CFGI_GW_SERVER_NAME)
      print(tostring(fetch_config.gw_server_name))

      -- Making a local copy of ONDEMAND GATEWAY SERVER PORT
      fetch_config.gw_server_port = sys.get_config_number(CFGI_GW_SERVER_PORT)
      print(tostring(fetch_config.gw_server_port))

      if nil ~= fetch_config.gw_server_name and "" ~= fetch_config.gw_server_name then
         fetch_config.proxy_gw_url = "http:///http://" .. fetch_config.gw_server_name
         if nil ~= fetch_config.gw_server_port then
	    fetch_config.proxy_gw_url = fetch_config.proxy_gw_url .. ":" .. fetch_config.gw_server_port
         end
	 fetch_config.proxy_gw_url = fetch_config.proxy_gw_url .. "/"
      end

      fetch_config.automatic_url = "http://" .. fetch_config.server_name .. "/od2/channels?id=all"

      if not datastore.get_last_pathid() then
         datastore.set_last_pathid(1)
      end

      -- Initialize X-pcs-next-get-url
      fetch_next_get_url = datastore.get_next_url()

      -- Initialize Last View Time Stamp from Datastore
      local last_view = datastore.get_last_view()
      if nil == last_view then
         last_view = ""
      end
      fetch_config.last_view = last_view
      print("Last view is .. " .. tostring(last_view))

      fetch_config.ui_active = false

      -- Initialize X-pcs-token
      http_pcs_token = datastore.get_pcs_token()

      -- Initialize X-pcs-ver
      http_pcs_ver = datastore.get_pcs_ver()

      -- Initialize X-pcs-http-timeout
      http_timeout = datastore.get_http_timeout() or 10

      -- Initialize Automatic Enable Flag from Datastore
      local automatic_enable = datastore.get_automatic_enable()
      if nil == automatic_enable then
         automatic_enable = true
      end
      fetch_config.automatic_enable = automatic_enable

      print("Autoupdate flag is .. " .. tostring(automatic_enable))

      -- Start timers if they fall after the current time
      local show_time = datastore.get_showtime()
      local expire_time = datastore.get_expiretime()
      local next_get_time = datastore.get_nextgettime()

      -- print("current time: " .. net.utc_to_http(net.getutctime()))

      -- Updating Show Time
      if show_time then
         print("show_time: " .. net.utc_to_http(show_time.time))
         if false == show_time.timer_fired then
            if (net.getutctime() ~= nil) and (show_time.time > net.getutctime()) then
               show_time.timer_id, err = sys.settimer ((show_time.time - net.getutctime()) * 1000, install_showtime_callback)
            else
               show_time.timer_fired = true
            end
         end
         install.showtime = show_time
      end

      -- Updating Expire Time
      if expire_time then
         print("expire_time: " .. net.utc_to_http(expire_time.time))
         if false == expire_time.timer_fired then
            if (net.getutctime() ~= nil) and (expire_time.time > net.getutctime()) then
               expire_time.timer_id, err = sys.settimer ((expire_time.time - net.getutctime()) * 1000, install_expiretime_callback)
            else
               expire_time.timer_fired = true
            end
         end
         install.expiretime = expire_time
      end

      -- Execute time-outs, if any
      scheduler_run_install_timers(false)

      -- Starting Automatic GET request for next-get-time
      if next_get_time then

         local i = 1
         while next_get_time.time_list[i] do
            print("next_get_time " .. i .. " : " .. net.utc_to_http(next_get_time.time_list[i]))
            i = i + 1
         end

         thttp_send_request(next_get_time.url, next_get_time.time_list, 1, 2, next_get_time.path_name, scheduler_thttp_callback)
      end

      fetch_config.init_done = 1
   end

   print("Leaving fetch_init\(\) ...")
end

------------------------------------------------------------------------------
-- fetch_register
-- (
--    <string> url,
--    <string> zipcode,
--    <function> callback
-- )
--
-- Sends the zipcode URL to the server as a Manual request
--
------------------------------------------------------------------------------
function fetch_register(url, zipcode, callback)
   print("Entering fetch_register\(\) ...")

   if not fetch_url_state[url] then
      if not fetch_config.init_done then
         print("Init failed. ...")
         return
      end

      print("Callback is .." .. tostring(callback))
      thttp_send_request(url, nil, 2, 1, zipcode, scheduler_thttp_callback)

      fetch_url_state[url] = 1
      fetch_callback[url] = callback
      print("fetch_callback = " .. tostring(fetch_callback))
   else
      return -5
   end

   print("Leaving fetch_register\(\) ...")
end

------------------------------------------------------------------------------
-- fetch_send_request
-- (
--    <string> url,
--    <number> http_method,
--    <number> request_type,
--    <function> callback
-- )
--
-- Fetches the object located at the given URL
--
-- url - url of the object to be fetched
-- http_method - is the HTTP request method. Could be one of GET=1 and POST=2
-- request_type - If this is a manual or automatic update. Could be one of
--                Manual=1 and Automatic=2
-- callback - Function provided by the user(calling module of this function)
--            to call on receving a response (Failure/Success).
--
------------------------------------------------------------------------------
function fetch_send_request(url, http_method, request_type, callback)
   print("Entering fetch_send_request\(\) ...")

   if not fetch_url_state[url] then
      if not fetch_config.init_done then
         print("Init failed. ...")
         return
      end

      if not http_method then
         print("http_method is nil ...")
      end

      print("Callback is .." .. tostring(callback))

      -- Forming the path name
      path_name = scheduler_get_pathname()
      thttp_send_request(url, nil, http_method, request_type, path_name, scheduler_thttp_callback)

      fetch_url_state[url] = 1
      fetch_callback[url] = callback
   else
      return -5
   end

   print("Leaving fetch_send_request\(\) ...")
end

------------------------------------------------------------------------------
-- fetch_cancel_request
-- (
--    <string> url
-- )
--
-- Cancels the outstanding fetch initiated in last call to send_request for
-- object located at the given URL
--
-- url - url of the object to be fetched
--
------------------------------------------------------------------------------
function fetch_cancel_request(url)
   print("Entering fetch_cancel_request\(\) ...")

   if not fetch_config.init_done then
      print("Init failed. ...")
      return
   end

   if fetch_url_state[url] then
      thttp_cancel_request(url)
      fetch_url_state[url] = nil
   end

   print("Leaving fetch_cancel_request\(\) ...")
   return
end

------------------------------------------------------------------------------
-- fetch_ui_active
-- (
--    <boolean> active
-- )
--
-- To update UI active/inactive status
--
-- active - true, indicates the UI is active
--        - false, indicates the UI is in-active
--
------------------------------------------------------------------------------
function fetch_ui_active(active)
   print("Entering fetch_ui_active\(\) ...")

   local old_active = fetch_config.ui_active

   fetch_config.ui_active = active

   if false == fetch_config.ui_active and true == old_active then
   -- UI Inactive
      scheduler_run_install_timers(true)
   elseif true == fetch_config.ui_active and false == old_active then
   -- UI Active
      -- TODO: Should we update last_view when UI goes to inactive?
      fetch_config.last_view = net.utc_to_http(net.getutctime())
      datastore.set_last_view(fetch_config.last_view)
   end

   print("Leaving fetch_ui_active\(\) ...")
end

------------------------------------------------------------------------------
-- fetch_automatic_enable
-- (
--    <boolean> enable
-- )
--
-- To enable or disable the Automatic requests
--
-- enable - true - Enable Automatic requests
--        - false - Disable Automatic requests
--
------------------------------------------------------------------------------
function fetch_automatic_enable(enable)
   print("Entering fetch_automatic_enable\(\) ...")

   local old_enable = fetch_config.automatic_enable

   fetch_config.automatic_enable = enable

   if false == fetch_config.automatic_enable and true == old_enable then
   -- Disable
      datastore.set_automatic_enable(enable)

      for timer_id in pairs(thttp_requesttime_table) do
         url = thttp_requesttime_table[timer_id]

         err = sys.canceltimer(timer_id)

         thttp_requesttime_table[timer_id] = nil

         http_cancel_request(url)

         thttp_time_index[url] = nil
         thttp_time_list[url] = {}

         thttp_http_method[url] = nil
         thttp_request_type[url] = nil
         thttp_pathname[url] = nil
         thttp_callback[url] = nil
      end
   elseif true == fetch_config.automatic_enable and false == old_enable then
   -- Enable
      datastore.set_automatic_enable(enable)
   end

   print("Leaving fetch_automatic_enable\(\) ...")
end
