--[[
	функции-помощники для скриптов уровня
]]

function log(str)
	print(str)
	io.flush()
end

local g_ThreadManager = qe.g_LuaThreadManager.Instance()
assert(g_ThreadManager)

local g_ThreadTable = {}
local g_RunningCoroutines = {}
local g_DeferredRunScripts = {}

local g_UniqueId = 0

local ResumeThread = function(_thread)
    _thread.running = true
    g_RunningCoroutines[#g_RunningCoroutines + 1] = _thread.uid
    local success, error_str = coroutine.resume(_thread.thread)
	table.remove(g_RunningCoroutines)
    _thread.running = false
    if (not success) and error_str then
        g_ThreadManager.Error(error_str.." thread status - "..coroutine.status(_thread.thread))
    end
end

function SkipThread(_thread_info)
    local resumed_thread = _thread_info
    if resumed_thread ~= nil and resumed_thread.thread ~= nil then
        local thread_state = coroutine.status(resumed_thread.thread)
        assert(thread_state ~= "running")
        assert(thread_state ~= "normal")
        if thread_state=="suspended" then
            while coroutine.status(resumed_thread.thread) ~="dead" do
                ResumeThread(resumed_thread)
            end
        end
        resumed_thread.thread = nil
    end

end

local ResumeCoroutine = function(_num, ...)
---__message("kill")
	local info = g_ThreadTable[_num] 
	if (not info) or (not info.thread) then 
		g_ThreadManager.Error("Trying to resume dead coroutine num ".._num) 
		return 
	end

	local status = coroutine.status(info.thread)
	if status~="dead" and (status~="normal" or info.start) and not info.running then
		info.start = false
        ResumeThread(info)
	end

	if info.thread ~= nil then
        status = coroutine.status(info.thread)
        if status=="dead" then
            g_ThreadTable[_num].thread = nil
        end
    end
end

function RunScript(_buffer)
	if not g_DeferredRunScripts then g_DeferredRunScripts = {} end
	g_DeferredRunScripts[#g_DeferredRunScripts + 1] = _buffer
end

function CreateScript(_funcname, ...)
	local new_thread = coroutine.create(
		function (...) 
			local chunk, err = loadstring(_funcname.."(...)")
			if chunk then chunk(...) else g_ThreadManager.Error(err) end
		end
	)
	g_ThreadTable[#g_ThreadTable + 1] = { thread = new_thread, resume_time = 0, start = true, uid = g_UniqueId  }
	g_UniqueId = g_UniqueId + 1
	ResumeCoroutine(#g_ThreadTable, ...)
end

function FindCoroutineByUID(_uid)
    for _,thread in pairs(g_ThreadTable) do
        if thread and thread.uid==_uid then return thread end
    end
end

function GetCurrentCoroutine() 
	if #g_RunningCoroutines==0 then g_ThreadManager.Error("Missing current coroutine") return end
	local thread_info = FindCoroutineByUID(g_RunningCoroutines[#g_RunningCoroutines])
    if not thread_info then g_ThreadManager.Error("Cant find current lua coroutine")  return nil end 
    return thread_info
end



function Wait(_time) 
	local thread_info = GetCurrentCoroutine()
	assert(thread_info.thread==coroutine.running())
	thread_info.resume_time = g_ThreadManager.GetElapsedTime() + _time
	coroutine.yield() 
end

function ManageThreads()
	local level_time = g_ThreadManager.GetElapsedTime()
	local i,size = nil,#g_ThreadTable
	for i = 1,size do
        local t = g_ThreadTable[i]
		if t and t.thread then
			if t.resume_time <= level_time then ResumeCoroutine(i) end
		end
	end
	
	if g_DeferredRunScripts then
		for i,b in ipairs(g_DeferredRunScripts) do
			local new_thread = coroutine.create(
				function() 
					local chunk, err = loadstring(b) 
					if chunk then chunk() else g_ThreadManager.Error(err) end 
				end
			)
			g_ThreadTable[#g_ThreadTable + 1] = { thread = new_thread, resume_time = 0, start = true, uid = g_UniqueId}
			g_UniqueId = g_UniqueId + 1
			ResumeCoroutine(#g_ThreadTable)
		end
	end
	g_DeferredRunScripts = nil
	
	local i = 1
	while i<=#g_ThreadTable do
		if not g_ThreadTable[i].thread then 
			table.remove(g_ThreadTable, i)
		else
			i = i + 1
		end
	end
end

threads_managment = threads_managment or {}

function threads_managment.InterruptClickScript()
	if not g_QuestState.GetCurrentClickThread() then return end
    
    SkipThread(g_QuestState.GetCurrentClickThread())
end

function threads_managment.IsClikThread()
    if g_QuestState.GetCurrentClickThread() ~= nil then
		return true
    end
    return false
end

function threads_managment.sleep(_number)
    Wait(_number)
end

function threads_managment.form_event(_value)
    RunScript(_value)
end

function PreClickEvent()
	g_QuestState.SetCurrentClickThread(GetCurrentCoroutine())
end

function PostClickEvent()
	g_QuestState.SetCurrentClickThread(nil)
end


 
