--[[
ģƣԶ(ͨhttpget)
ģ鹦ܣֻÿοʱ߸ûʱ㣬°汾libӦýűԶ
ģ޸ʱ䣺2018.02.08
]]

--ģ,
local base = _G
local string = require"string"
local io = require"io"
local os = require"os"
local rtos = require"rtos"
local sys  = require"sys"
local link = require"link"
local misc = require"misc"
local common = require"common"
module(...)

--سõȫֺ
local print = base.print
local send = link.send
local dispatch = sys.dispatch

--Զģʽmain.luaУUPDMODEδõĻĬΪ0
--0ԶģʽԶ
--1ûԶģʽ󣬻һϢUP_END_INDûűǷҪ
local updmode = base.UPDMODE or 0

--PROTOCOLЭ飬ֻ֧TCP
--SERVER,PORTΪַͶ˿
local PROTOCOL,SERVER,PORT,getURL = "TCP","iot.openluat.com",80,"/api/site/firmware_upgrade"
--ǷʹûԶ
local usersvr
--·
local UPDATEPACK = "/luazip/update.bin"
local rcvBuf = ""

-- GETȴʱ
local CMD_GET_TIMEOUT = 10000
-- GETԴ
local CMD_GET_RETRY_TIMES = 5
--socket id
local lid,updsuc
--öʱʱڣλ룬0ʾرնʱ
local period = 0
--״̬״̬
--IDLE״̬
--CHECKѯǷ°汾״̬
--UPDATE״̬
local state = "IDLE"
--getretriesѾԵĴ
local getretries = 0
local contentLen,saveLen = 0,0


--[[
print
  ӡӿڣļедӡupdatehttpǰ׺
  
ֵ
]]
local function print(...)
	base.print("updatehttp",...)
end

--[[
save
  ݰļ
  
		dataݰ
ֵɹtruenil
]]
local function save(data)
	--ļ
	local f = io.open(UPDATEPACK,"a+")

	if f==nil then
		print("save:file nil")
		return
	end
	--дļ
	if f:write(data)==nil then
		print("write:file nil")
		f:close()
		return
	end
	f:close()
	return true
end

--[[
retry
  еԶ
  
		paramΪSTOPֹͣԣִ
ֵ
]]
local function retry(param)
	--״̬ѽֱ˳
	if state~="CONNECT" and state~="UPDATE" and state~="CHECK" then
		return
	end
	--Դ1
	getretries = getretries + 1
	if getretries < CMD_GET_RETRY_TIMES then
		link.close(lid)
		lid = nil
		connect()		
	else
		-- Դ,ʧ
		upend(false)
	end
end

--[[
upend
  
  
		succtrueΪɹΪʧ
ֵ
]]
function upend(succ)
	print("upend",succ,state,updmode)
	if not succ then os.remove(UPDATEPACK) end
	updsuc = succ
	local tmpsta = state
	state = "IDLE"
	rcvBuf = ""
	--ֹͣԶʱ
	sys.timer_stop(retry)
	--Ͽ
	link.close(lid)
	lid = nil
	getretries = 0
	sys.setrestart(true,1)
	sys.timer_stop(sys.setrestart,true,1)
	--ɹԶģʽ
	if succ == true and updmode == 0 then
		sys.restart("update.upend")
	end
	--ԶģʽһڲϢUP_END_INDʾԼ
	if updmode == 1 and tmpsta ~= "IDLE" then
		dispatch("UP_EVT","UP_END_IND",succ)
	end
	--һڲϢUPDATE_END_INDĿǰģʽʹ
	dispatch("UPDATE_END_IND")
	if period~=0 then sys.timer_start(connect,period*1000,"period") end
end

--[[
reqcheck
  ͡Ƿ°汾ݵ
  
ֵ
]]
function reqcheck()
	print("reqcheck",usersvr)
	state = "CHECK"
	local url = getURL.."?project_key="..base.PRODUCT_KEY
		.."&imei="..misc.getimei().."&device_key="..misc.getsn()
		.."&firmware_name="..base.PROJECT.."_"..rtos.get_version().."&version="..base.VERSION
	if not send(lid,"GET "..url.." HTTP/1.1\r\nConnection: keep-alive\r\nHost: "..SERVER.."\r\n\r\n") then
		sys.timer_start(retry,CMD_GET_TIMEOUT)
	end
	os.remove(UPDATEPACK)
	rcvBuf = ""	
end

--[[
nofity
  socket״̬Ĵ
  
        idsocket idԺԲ
        evtϢ¼
		val Ϣ¼
ֵ
]]
local function nofity(id,evt,val)
	--ӽ
	if evt == "CONNECT" then
		state = "CONNECT"
		--һڲϢUPDATE_BEGIN_INDĿǰģʽʹ
		dispatch("UPDATE_BEGIN_IND")
		--ӳɹ
		if val == "CONNECT OK" then
			reqcheck()
		--ʧ
		else
			sys.timer_start(retry,CMD_GET_TIMEOUT)
		end
	elseif evt == "SEND" then
		sys.timer_start(retry,CMD_GET_TIMEOUT)
	--ӱϿ
	elseif evt == "STATE" and val == "CLOSED" then		 
		upend(false)
	end
end

--[[
recv
  socketݵĴ
  
        id socket idԺԲ
        dataյ
ֵ
]]
local function recv(id,data)
	--ֹͣԶʱ
	sys.timer_stop(retry)
	--ѯǷ°汾״̬
	if state == "CHECK" then
		rcvBuf = rcvBuf..data
		local _,d = string.find(rcvBuf,"\r\n\r\n")
		if d then
			local statusCode = string.match(rcvBuf,"HTTP/1.1 (%d+)")
			if statusCode~="200" then
				print("statusCode error",statusCode)
				local msg = string.match(rcvBuf,"\"msg\":%s*\"(.-)\"")
				if msg and msg:len()<=200 then
					print("error msg",common.ucs2betoutf8(common.hexstobins(msg:gsub("\\u",""))))
				end
				upend(false)
				return
			end
			
			contentLen = string.match(rcvBuf,"Content%-Length: (%d+)")
			if not contentLen or contentLen=="0" then print("contentLen error",contentLen) sys.timer_start(retry,CMD_GET_TIMEOUT) return end
			contentLen = base.tonumber(contentLen)
			
			state = "UPDATE"
			local buf = string.sub(rcvBuf,d+1,-1)
			if string.len(buf)>0 and not save(buf) then print("save error") sys.timer_start(retry,CMD_GET_TIMEOUT) return end			
			saveLen = string.len(buf)
			rcvBuf = ""
		end		
	--С״̬
	elseif state == "UPDATE" then
		if string.len(data)>0 and not save(data) then print("save error") sys.timer_start(retry,CMD_GET_TIMEOUT) return end			
		saveLen = saveLen+string.len(data)
		if saveLen == contentLen then
			upend(true)
		end
	else
		upend(false)
	end	
end


function connect()
	print("connect",lid,updsuc)
	if not lid and not updsuc then
		lid = link.open(nofity,recv,"update")
		link.connect(lid,PROTOCOL,SERVER,PORT)
	end
end

local function defaultbgn()
	print("defaultbgn",usersvr)
	if not usersvr then
		base.assert(base.PRODUCT_KEY and base.PROJECT and base.VERSION,"undefine PRODUCT_KEY or PROJECT or VERSION in main.lua")
		base.assert(not string.match(base.PROJECT,","),"PROJECT in main.lua format error")
		base.assert(string.match(base.VERSION,"%d%.%d%.%d") and string.len(base.VERSION)==5,"VERSION in main.lua format error")
		connect()
	end
end

--[[
setup
  ÷ĴЭ顢ַͶ˿
  
        prot Э飬֧TCP
		serverַ
		port˿
		getURLGETURL"/api/site/firmware_upgrade",ע⣬GETʱڴURL֮ԶĲ
				"?project_key="..base.PRODUCT_KEY
				"&imei="..misc.getimei()
				"&device_key="..misc.getsn()
				"&firmware_name="..base.PROJECT.."_"..rtos.get_version()
				"&version="..base.VERSION
ֵ
]]
function setup(prot,server,port,url)
	if prot and server and port and url then
		PROTOCOL,SERVER,PORT,getURL = prot,server,port,url
		usersvr = true
		base.assert(base.PROJECT and base.VERSION,"undefine PROJECT or VERSION in main.lua")		
		connect()
	end
end

--[[
setperiod
  öʱ
  
        prdnumberͣʱڣλ룻0ʾرնʱܣֵҪڵ60
ֵ
]]
function setperiod(prd)
	base.assert(prd==0 or prd>=60,"setperiod prd error")
	print("setperiod",prd)
	period = prd
	if prd==0 then
		sys.timer_stop(connect,"period")
	else
		sys.timer_start(connect,prd*1000,"period")
	end
end

--[[
request
  ʵʱһ
  
ֵ
]]
function request()
	print("request")
	connect()
end

sys.timer_start(defaultbgn,10000)
sys.setrestart(false,1)
sys.timer_start(sys.setrestart,300000,true,1)
