--[[
ģƣͨ
ģ鹦ܣ롢Ҷ
ģ޸ʱ䣺2017.02.20
]]

--ģ,
local base = _G
local string = require"string"
local table = require"table"
local sys = require"sys"
local ril = require"ril"
local net = require"net"
local pm = require"pm"
module(...)

--سõȫֺ
local ipairs,pairs,print,unpack,type = base.ipairs,base.pairs,base.print,base.unpack,base.type
local req = ril.request

--ײͨģǷ׼truefalsenilδ
local ccready = false
--ͨڱ־״̬ʱΪtrue
--кУУͨ
local callexist = false
--¼뱣֤ͬһ绰ֻʾһ
local incoming_num = nil 
--
local emergency_num = {"112", "911", "000", "08", "110", "119", "118", "999"}
--ͨб
local oldclcc,clcc = {},{}
--״̬仯֪ͨص
local usercbs = {}


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

--[[
dispatch
  ִÿڲϢӦûص
  
		evtϢ
		paraϢ
ֵ
]]
local function dispatch(evt,para)
	local tag = string.match(evt,"CALL_(.+)")
	if usercbs[tag] then usercbs[tag](para) end
end

--[[
regcb
  עһ߶Ϣûص
  
		evt1ϢͣĿǰ֧"READY","INCOMING","CONNECTED","DISCONNECTED","DTMF","ALERTING"
		cb1ϢӦûص
		...evtcbɶԳ
ֵ
]]
function regcb(evt1,cb1,...)
	usercbs[evt1] = cb1
	local i
	for i=1,arg.n,2 do
		usercbs[unpack(arg,i,i)] = unpack(arg,i+1,i+1)
	end
end

--[[
deregcb
  עһ߶Ϣûص
  
		evt1ϢͣĿǰ֧"READY","INCOMING","CONNECTED","DISCONNECTED","DTMF","ALERTING"
		...0߶evt
ֵ
]]
function deregcb(evt1,...)
	usercbs[evt1] = nil
	local i
	for i=1,arg.n do
		usercbs[unpack(arg,i,i)] = nil
	end
end

--[[
isemergencynum
  ǷΪ
  
		num
ֵtrueΪ룬falseΪ
]]
local function isemergencynum(num)
	for k,v in ipairs(emergency_num) do
		if v == num then
			return true
		end
	end
	return false
end

--[[
clearincomingflag
  
  
ֵ
]]
local function clearincomingflag()
	incoming_num = nil
end

--[[
discevt
  ͨϢ
  
		reasonԭ
ֵ
]]
local function discevt(reason)
	callexist = false -- ͨ ͨ״̬־
	if incoming_num then sys.timer_start(clearincomingflag,1000) end
	pm.sleep("cc")
	--ڲϢCALL_DISCONNECTED֪ͨûͨ
	dispatch("CALL_DISCONNECTED",reason)
	sys.timer_stop(qrylist,"MO")
end

--[[
anycallexist
  Ƿͨ
  
ֵͨtrue򷵻false
]]
function anycallexist()
	return callexist
end

--[[
qrylist
  ѯͨб
  
ֵ
]]
function qrylist()
	oldclcc = clcc
	clcc = {}
	req("AT+CLCC")
end

local function proclist()
	local k,v,isactive
	for k,v in pairs(clcc) do
		if v.sta == "0" then isactive = true break end
	end
	if isactive and #clcc > 1 then
		for k,v in pairs(clcc) do
			if v.sta ~= "0" then req("AT+CHLD=1"..v.id) end			
		end
	end
	
	if usercbs["ALERTING"] and #clcc >= 1 then
		for k,v in pairs(clcc) do
			if v.sta == "3" then
				--[[dispatch("CALL_ALERTING")
				break]]
				for m,n in pairs(oldclcc) do
					if v.id==n.id and v.dir==n.dir and n.sta~="3" then
						dispatch("CALL_ALERTING")
						break
					end
				end
			end
		end
	end
end

--[[
dial
  һ
  
		number
		delayʱdelay󣬲ŷatУĬϲʱ
ֵtrueʾatŲҷatfalseʾat
]]
function dial(number,delay)
	if number == "" or number == nil then
		return false
	end

	if ccready == false and not isemergencynum(number) then
		return false
	end

	pm.wake("cc")
	req(string.format("%s%s;","ATD",number),nil,nil,delay)
	callexist = true -- к

	return true
end

--[[
hangupnxt
  Ҷͨ
  
ֵ
]]
local function hangupnxt()
	req("AT+CHUP")
end

--[[
hangup
  Ҷͨ
  
ֵ
]]
function hangup()
	--audioģ
	if audio and type(audio)=="table" and audio.play then
		--ֹͣƵ
		sys.dispatch("AUDIO_STOP_REQ",hangupnxt)
	else
		hangupnxt()
	end
end

--[[
acceptnxt
  
  
ֵ
]]
local function acceptnxt()
	req("ATA")
	pm.wake("cc")
end

--[[
accept
  
  
ֵ
]]
function accept()
	--audioģ
	if audio and type(audio)=="table" and audio.play then
		--ֹͣƵ
		sys.dispatch("AUDIO_STOP_REQ",acceptnxt)
	else
		acceptnxt()
	end		
end

--[[
transvoice
  ͨзԶ,12.2K AMRʽ
  
ֵtrueΪɹfalseΪʧ
]]
function transvoice(data,loop,loop2)
	local f = io.open("/RecDir/rec000","wb")

	if f == nil then
		print("transvoice:open file error")
		return false
	end

	-- ļͷ12.2K֡
	if string.sub(data,1,7) == "#!AMR\010\060" then
	-- ļͷ12.2K֡
	elseif string.byte(data,1) == 0x3C then
		f:write("#!AMR\010")
	else
		print("transvoice:must be 12.2K AMR")
		return false
	end

	f:write(data)
	f:close()

	req(string.format("AT+AUDREC=%d,%d,2,0,50000",loop2 == true and 1 or 0,loop == true and 1 or 0))

	return true
end

--[[
dtmfdetect
  dtmfǷʹԼ
  
		enabletrueʹܣfalsenilΪʹ
		sensȣĬ3Ϊ1
ֵ
]]
function dtmfdetect(enable,sens)
	if enable == true then
		if sens then
			req("AT+DTMFDET=2,1," .. sens)
		else
			req("AT+DTMFDET=2,1,3")
		end
	end

	req("AT+DTMFDET="..(enable and 1 or 0))
end

--[[
senddtmf
  dtmfԶ
  
		strdtmfַ
		playtimeÿdtmfʱ䣬λ룬Ĭ100
		intvldtmfλ룬Ĭ100
ֵ
]]
function senddtmf(str,playtime,intvl)
	if string.match(str,"([%dABCD%*#]+)") ~= str then
		print("senddtmf: illegal string "..str)
		return false
	end

	playtime = playtime and playtime or 100
	intvl = intvl and intvl or 100

	req("AT+SENDSOUND="..string.format("\"%s\",%d,%d",str,playtime,intvl))
end

local dtmfnum = {[71] = "Hz1000",[69] = "Hz1400",[70] = "Hz2300"}

--[[
parsedtmfnum
  dtmf룬󣬻һڲϢAUDIO_DTMF_DETECTЯDTMFַ
  
		datadtmfַ
ֵ
]]
local function parsedtmfnum(data)
	local n = base.tonumber(string.match(data,"(%d+)"))
	local dtmf

	if (n >= 48 and n <= 57) or (n >=65 and n <= 68) or n == 42 or n == 35 then
		dtmf = string.char(n)
	else
		dtmf = dtmfnum[n]
	end

	if dtmf then
		dispatch("CALL_DTMF",dtmf)
	end
end

--[[
ccurc
  ģڡעĵײcoreͨ⴮ϱ֪ͨĴ
  
		dataַ֪ͨϢ
		prefix֪ͨǰ׺
ֵ
]]
local function ccurc(data,prefix)
	--ײͨģ׼
	if data == "CALL READY" then
		ccready = true
		dispatch("CALL_READY")
		req("AT+CCWA=1")
	--֪ͨͨ
	elseif data == "CONNECT" then
		qrylist()		
		dispatch("CALL_CONNECTED")
		sys.timer_stop(qrylist,"MO")
		--ֹͣƵ
		sys.dispatch("AUDIO_STOP_REQ")
	--ͨҶ֪ͨ
	elseif data == "NO CARRIER" or data == "BUSY" or data == "NO ANSWER" then
		qrylist()
		discevt(data)
	--
	elseif prefix == "+CLIP" then
		qrylist()
		local number = string.match(data,"\"(%+*%d*)\"",string.len(prefix)+1)
		callexist = true -- 
		if incoming_num ~= number then
			incoming_num = number
			dispatch("CALL_INCOMING",number)
		end
	elseif prefix == "+CCWA" then
		qrylist()
	--ͨбϢ
	elseif prefix == "+CLCC" then
		local id,dir,sta = string.match(data,"%+CLCC:%s*(%d+),(%d),(%d)")
		if id then
			table.insert(clcc,{id=id,dir=dir,sta=sta})
			proclist()
		end
	--DTMFռ
	elseif prefix == "+DTMFDET" then
		parsedtmfnum(data)
	end
end

--[[
ccrsp
  ģڡͨ⴮ڷ͵ײcoreATӦ
  
		cmdӦӦAT
		successATִнtruefalse
		responseATӦеִнַ
		intermediateATӦемϢ
ֵ
]]
local function ccrsp(cmd,success,response,intermediate)
	local prefix = string.match(cmd,"AT(%+*%u+)")
	--Ӧ
	if prefix == "D" then
		if not success then
			discevt("CALL_FAILED")
		else
			if usercbs["ALERTING"] then sys.timer_loop_start(qrylist,1000,"MO") end
		end
	--ҶͨӦ
	elseif prefix == "+CHUP" then
		discevt("LOCAL_HANG_UP")
	--Ӧ
	elseif prefix == "A" then
		incoming_num = nil
		dispatch("CALL_CONNECTED")
		sys.timer_stop(qrylist,"MO")
	end
	qrylist()
end

--ע֪ͨĴ
ril.regurc("CALL READY",ccurc)
ril.regurc("CONNECT",ccurc)
ril.regurc("NO CARRIER",ccurc)
ril.regurc("NO ANSWER",ccurc)
ril.regurc("BUSY",ccurc)
ril.regurc("+CLIP",ccurc)
ril.regurc("+CLCC",ccurc)
ril.regurc("+CCWA",ccurc)
ril.regurc("+DTMFDET",ccurc)
--עATӦ
ril.regrsp("D",ccrsp)
ril.regrsp("A",ccrsp)
ril.regrsp("+CHUP",ccrsp)
ril.regrsp("+CHLD",ccrsp)

--,æ
req("ATX4") 
--urcϱ
req("AT+CLIP=1")
dtmfdetect(true)
