--------------------------------------------------------------------------------
--      Copyright (c) 2015 - 2016 , 蒙占志(topameng) topameng@gmail.com
--      All rights reserved.
--      Use, modification and distribution are subject to the "MIT License"
--------------------------------------------------------------------------------
local create = coroutine.create
local running = coroutine.running
local resume = coroutine.resume
local yield = coroutine.yield
local error = error
local unpack = unpack
local debug = debug
local FrameTimer = FrameTimer
local CoTimer = CoTimer

local comap = {}
local pool = {}
setmetatable(comap, {__mode = "kv"})

function coroutine.start(f, ...)	
	local co = create(f)
	
	if running() == nil then
		local flag, msg = resume(co, ...)
	
		if not flag then					
			error(debug.traceback(co, msg))
		end					
	else
		local args = {...}
		local timer = nil		
		
		local action = function()												
			comap[co] = nil
			timer.func = nil
			local flag, msg = resume(co, unpack(args, 1, table.maxn(args)))						
			table.insert(pool, timer)
	
			if not flag then	
				timer:Stop()														
				error(debug.traceback(co, msg))						
			end		
		end
			
		if #pool > 0 then
			timer = table.remove(pool)
			timer:Reset(action, 0, 1)
		else
			timer = FrameTimer.New(action, 0, 1)
		end
		
		comap[co] = timer
		timer:Start()		
	end

	return co
end

function coroutine.wait(t, co, ...)
	local args = {...}
	co = co or running()		
	local timer = nil
		
	local action = function()		
		comap[co] = nil		
		timer.func = nil
		local flag, msg = resume(co, unpack(args, 1, table.maxn(args)))
		
		if not flag then	
			timer:Stop()						
			error(debug.traceback(co, msg))			
			return
		end
	end
	
	timer = CoTimer.New(action, t, 1)
	comap[co] = timer	
	timer:Start()
	return yield()
end

function coroutine.step(t, co, ...)
	local args = {...}
	co = co or running()		
	local timer = nil
	
	local action = function()	
		comap[co] = nil					
		timer.func = nil
		local flag, msg = resume(co, unpack(args, 1, table.maxn(args)))
		table.insert(pool, timer)
	
		if not flag then	
			timer:Stop()																			
			error(debug.traceback(co, msg))
			return	
		end		
	end
				
	if #pool > 0 then
		timer = table.remove(pool)
		timer:Reset(action, t or 1, 1)
	else
		timer = FrameTimer.New(action, t or 1, 1)
	end

	comap[co] = timer
	timer:Start()
	return yield()
end

function coroutine.www(www, co)			
	co = co or running()			
	local timer = nil			
			
	local action = function()				
		if not www.isDone then		
			return		
		end		
				
		comap[co] = nil
		timer:Stop()		
		timer.func = nil
		local flag, msg = resume(co)			
		table.insert(pool, timer)	
			
		if not flag then												
			error(debug.traceback(co, msg))			
			return			
		end				
	end		
				
	if #pool > 0 then
		timer = table.remove(pool)
		timer:Reset(action, 1, -1)
	else	
		timer = FrameTimer.New(action, 1, -1)	
	end
	comap[co] = timer	
 	timer:Start()
 	return yield()
end

function coroutine.stop(co)
 	local timer = comap[co] 	 	

 	if timer ~= nil then
 		comap[co] = nil
 		timer:Stop()  	
 		timer.func = nil	
 	end
end
