task_list = task_list or {}
quest.global_tasks = {}
quest.global_tasks_by_id = {}

tasks_lua_widget = {}

local state = { disabled = 1, normal = 2, completed = 3 }

function task_list.Save(_element)
    for i,o in pairs(quest.global_tasks_by_id)do
        local task_info = sf.misc.CXmlElement ( _element, "task")
        task_info.Attr("task_id", i )
        task_info.Attr("task_state", tostring(o.state) )
        task_info.Flush()
    end
end

task_list.labels_list = {}
task_list.go_visible_time = 700
task_list.go_color_time = 700
task_list.go_compl_color_time = 300
task_list.go_compl_alpha_time = 300
task_list.go_compl_size_time = 300
task_list.begin_task_update = nil

task_list.timer = sf.core.CTimerWrapper(sf.core.g_Application.GetTimeManager().GetTimer(_T("qe_level")).AttachTimer(_T("")))
task_list.visible_task_count = 0

function task_list.Load(_group)
    __assert(_group.GetId().c_str() ~= "", "Неверная группа для загрузки состояния действий")
    local task_group = _group.GetFirstChildRef()
    local items_objects_list  = {}
    while task_group do
        local task_id = task_group.GetValue(_T("task_id")).c_str()
        local task_state = task_group.GetValue(_T("task_state")).c_str()
        task = quest.global_tasks_by_id[task_id]
        __assert(task ~= nil, "Загружаемый таск не существует для уровня")
        if task then
            task.state = tonumber(task_state)
        end
        task_group = task_group.GetNextSiblingRef()
    end
    task_list.begin_task_update = true

    tasks_lua_widget.UpdateTasksLabels()
end


function add_task(_id, _text, ...)
    _id = tostring(_id)
	if type(_text)=='number' then
		_text = sf.misc.g_StringTable.Instance().FormatByStringsID("$"..tostring(_text))
	end
	
	__assert(not quest.global_tasks_by_id[_id], "Действие ".._id.." уже существует!", true)
	local dependencies = {...}
	local task = { id = _id,  text = _text, dependencies = dependencies, state = #dependencies>0 and state.disabled or state.normal }
    task.label_index = nil
	quest.global_tasks_by_id[_id] = task
	table.insert(quest.global_tasks, task)
	
	tasks_lua_widget.UpdateTasksLabels()
end

local function update_tasks_dependencies()
	for _,task in ipairs(quest.global_tasks) do
		if task.state==state.disabled then
			local all_completed = true
			for _,id in ipairs(task.dependencies) do
				if quest.global_tasks_by_id[tostring(id)].state~=state.completed then 
					all_completed = false
					break
				end
			end
			if all_completed then task.state = state.normal end
		end
	end
end

function complete_task(_id)
    _id = tostring(_id)
	local task = quest.global_tasks_by_id[_id]
	__assert(task, 'Действие '.._id..' не существует!', true)
	__assert(task.state ~= state.disabled, 'Действие '.._id..' заблокированно и не может быть выполнено!', true)
	if task.state == state.completed then return end
	task.state = state.completed
	
	update_tasks_dependencies()
	
	tasks_lua_widget.UpdateTasksLabels()
	
	sound("task_complete");
end

function reopen_task(_id)
	_id = tostring(_id)
	local task = quest.global_tasks_by_id[_id]
	__assert(task, 'Действие '.._id..' не существует!', true)
	
	__assert(#task.dependencies==0, "Нельзя заново открыть действие, зависящее от других ('".._id.."')", true)
	for _,t in ipairs(quest.global_tasks) do
		for _,id in ipairs(t.dependencies) do
			if tostring(id)==_id then
				__message("Нельзя заново открыть действие, от которого зависят другие ('".._id.."')", "Ошибка")
				return
			end
		end
	end
	task.state = state.normal
	tasks_lua_widget.UpdateTasksLabels()
end

function is_task_completed(_id)
	_id = tostring(_id)
	local task = quest.global_tasks_by_id[_id]
	__assert(task, 'Действие '.._id..' не существует!', true)
	return task.state == state.completed
end

tasks_lua_widget = 
{
	UpdateTasksLabels = function()
        if not task_list.begin_task_update then return end
		if not tasks_lua_widget.font then return end
        for _,task in ipairs(quest.global_tasks) do
            if task.text ~= "" then
                if task.state==state.normal then
                    if task.label_index == nil or task_list.labels_list[task.label_index].status == "dead"  then
                        local labels_count = #task_list.labels_list
                        local y = 0
                        if task_list.labels_list[labels_count] then
                            y = task_list.labels_list[labels_count].offset.Y + task_list.labels_list[labels_count].size.Y
                        end
                        

                        local label = sf.gui.CLabelWidget(tasks_lua_widget.font, task.text, "", 0, 0)
                        local string_width =  tasks_lua_widget.font.GetStringWidth(task.text)
                        
                        local width = tasks_lua_widget.this.GetSize().X
                        if width > string_width then
                            width = string_width + 1
                        end
                        label.SetSize(width, 0)
                        label.SetOffset(0, y)
                        label.SetWordBreak(true)
                        label.ResizeToFitText(true)
                        local color = sf.graphics.Color(tasks_lua_widget.colors[4]) --start_color
                        color.Alpha = 0
                        label.SetColor(color)
                        tasks_lua_widget.this.AddWidget(label)

                        local new_label_row = {widget = label, offset = sf.misc.FloatVector(0, y), size = sf.misc.FloatVector(label.GetPreferredSize()), global_task_index = _, status = "new" }
                        task_list.labels_list[labels_count + 1] = new_label_row
                        task.label_index = labels_count + 1
                    end
                elseif task.state==state.completed then
                    if task.label_index ~= nil then
                        if task_list.labels_list[task.label_index].status == "normal" then
                            task_list.labels_list[task.label_index].status = "completed_color"
                        end
                    end
                end 
            end
        end
		tasks_lua_widget.UpdateCompletedTasksCount()
	end,
	--[[
	UpdateTasksLabelsColors = function()
		for _,label in ipairs(tasks_lua_widget.labels) do
			label.widget.SetColor(tasks_lua_widget.colors[label.task.state])
		end
	end,
	]]
	UpdateCompletedTasksCount = function()
		assert(tasks_lua_widget.this)
		if not tasks_lua_widget.completed_tasks_label then
			tasks_lua_widget.completed_tasks_label = __cast(tasks_lua_widget.this.GetParentWidget().GetWidget("completed_tasks_label", true).get(), sf.gui.CLabelWidget)
			__assert(tasks_lua_widget.completed_tasks_label, "Не могу найти label_widget 'completed_tasks_label' в окне 'quest_window'")
			tasks_lua_widget.completed_tasks_label_text = tasks_lua_widget.completed_tasks_label_text or tasks_lua_widget.completed_tasks_label.GetText().c_str()
		end
		
		-- подсчитываем кол-во выполненных тасков
		local complete_count = 0
		for _,task in ipairs(quest.global_tasks) do
			if task.state==state.completed then complete_count = complete_count + 1 end
		end
		tasks_lua_widget.completed_tasks_label.SetText(string.format(tasks_lua_widget.completed_tasks_label_text, complete_count, #quest.global_tasks))
	end,
	
	DoDraw = function(_this, _renderer)
        tasks_lua_widget._pre_draw_effects_list:PreDraw(_renderer)
        tasks_lua_widget._pre_draw_effects_list:PostDraw(_renderer)
		return false
	end,

	DoUpdate = function(_this)
        local current_time = task_list.timer.Get().GetTime()
        local labels_ofset = sf.misc.FloatVector(0, 0)
        for _,task in ipairs(quest.global_tasks) do
            if task.state==state.completed then
                if task.label_index ~= nil then
                    if task_list.labels_list[task.label_index].status == "normal" then
                        task_list.labels_list[task.label_index].status = "completed_color"
                        task_list.labels_list[task.label_index].start_stage_time = nil
                    end
                end
            end 
        end

        local dead_effects = false
        for i,label_row in ipairs(task_list.labels_list) do
            label_row.offset.Y = labels_ofset.Y
            if label_row.status == "completed_color" then
                if label_row.start_stage_time == nil then
                    label_row.start_stage_time = current_time

                    label_row.effect = tasks_effects_lua_widget.visual_effects_list:CreateEffect("CloseTaskPost", label_row.offset + label_row.size/2)
                    local rect_effect = label_row.effect:GetChildEffect("rect_systems")
                    if rect_effect then
                        rect_effect:SetEmiterSize(label_row.size)
                    end

                    label_row.pre_effect = tasks_effects_lua_widget.visual_effects_list:CreateEffect("CloseTaskPre", label_row.offset + label_row.size/2)
                    local rect_effect = label_row.pre_effect:GetChildEffect("rect_systems")
                    if rect_effect then
                        rect_effect:SetEmiterSize(label_row.size)
                    end
                end
    
                dead_effects = true
                if label_row.widget then
                    local koef = (current_time - label_row.start_stage_time)/task_list.go_compl_color_time
                    if koef > 1 then
                        koef = 1
                    end

                    local color = sf.graphics.Color(
                            tasks_lua_widget.colors[5].Alpha - (tasks_lua_widget.colors[5].Alpha - tasks_lua_widget.colors[6].Alpha)* koef,
                            tasks_lua_widget.colors[5].Red - (tasks_lua_widget.colors[5].Red - tasks_lua_widget.colors[6].Red)* koef,
                            tasks_lua_widget.colors[5].Green - (tasks_lua_widget.colors[5].Green - tasks_lua_widget.colors[6].Green)* koef,
                            tasks_lua_widget.colors[5].Blue - (tasks_lua_widget.colors[5].Blue - tasks_lua_widget.colors[6].Blue)* koef )

                    if koef == 1 then
                        color = sf.graphics.Color(tasks_lua_widget.colors[6])
                        label_row.status = "completed_alpha"
                        label_row.start_stage_time = current_time
                    end
                    label_row.widget.SetColor(color)
                end

            elseif label_row.status == "completed_alpha" then
                dead_effects = true
                if label_row.widget then
                    local color = sf.graphics.Color(label_row.widget.GetColor())
                    local koef = (current_time - label_row.start_stage_time)/task_list.go_compl_alpha_time
                    if koef > 1 then
                        koef = 1
                    end
                    color.Alpha = 255 * (1-koef)
                    if koef == 1 then
                        color.Alpha = 0
                        label_row.status = "completed_size"
                        label_row.start_stage_time = current_time
                        label_row.effect:Kill(false)
                        label_row.pre_effect:Kill(false)

                    end
                    label_row.widget.SetColor(color)
                end

            elseif label_row.status == "completed_size" then
                if label_row.old_size == nil then
                    label_row.old_size = label_row.size.Y
                end
                dead_effects = true
                local koef = (current_time - label_row.start_stage_time)/task_list.go_compl_size_time
                if koef > 1 then
                    koef = 1
                end
                label_row.size.Y = label_row.old_size * (1-koef)
                local a = #task_list.labels_list
                if koef == 1 or i == task_list.visible_task_count then
                    label_row.size.Y = 0
                    label_row.status = "dead"
                    tasks_lua_widget.this.RemoveWidget(label_row.widget)
                    label_row.widget = nil
                    task_list.visible_task_count = task_list.visible_task_count - 1
                end
            elseif label_row.status == "new" and not dead_effects then
                label_row.effect = tasks_effects_lua_widget.visual_effects_list:CreateEffect("NewTaskPost", label_row.offset + label_row.size/2)
                local rect_effect = label_row.effect:GetChildEffect("rect_systems")
                if rect_effect then
                    rect_effect:SetEmiterSize(label_row.size)
                end

                label_row.pre_effect = tasks_effects_lua_widget.visual_effects_list:CreateEffect("NewTaskPre", label_row.offset + label_row.size/2)
                local rect_effect = label_row.pre_effect:GetChildEffect("rect_systems")
                if rect_effect then
                    rect_effect:SetEmiterSize(label_row.size)
                end
                task_list.visible_task_count = task_list.visible_task_count + 1
                label_row.status = "new_alpha" 
                label_row.start_stage_time = current_time

            elseif label_row.status == "new_alpha" then
                if label_row.widget then
                    local color = sf.graphics.Color(label_row.widget.GetColor())
                    local koef = (current_time - label_row.start_stage_time)/task_list.go_visible_time
                    if koef > 1 then
                        koef = 1
                    end
                    color.Alpha = 255 * koef
                    if koef == 1 then
                        color.Alpha = 255
                        label_row.status = "new_color"
                        label_row.effect:Kill(false)
                        label_row.pre_effect:Kill(false)
                        label_row.start_stage_time = current_time
                    end
                    label_row.widget.SetColor(color)
                end
            elseif label_row.status == "new_color" then
                if label_row.widget then
                    local koef = (current_time - label_row.start_stage_time)/task_list.go_color_time
                    if koef > 1 then
                        koef = 1
                    end

                    local color = sf.graphics.Color(
                            tasks_lua_widget.colors[4].Alpha - (tasks_lua_widget.colors[4].Alpha - tasks_lua_widget.colors[5].Alpha)* koef,
                            tasks_lua_widget.colors[4].Red - (tasks_lua_widget.colors[4].Red - tasks_lua_widget.colors[5].Red)* koef,
                            tasks_lua_widget.colors[4].Green - (tasks_lua_widget.colors[4].Green - tasks_lua_widget.colors[5].Green)* koef,
                            tasks_lua_widget.colors[4].Blue - (tasks_lua_widget.colors[4].Blue - tasks_lua_widget.colors[5].Blue)* koef )

                    if koef == 1 then
                        color = sf.graphics.Color(tasks_lua_widget.colors[5])
                        label_row.status = "normal"
                        label_row.start_stage_time = nil
                    end
                    label_row.widget.SetColor(color)
                end
            end
            if label_row.widget then
                label_row.widget.SetOffset(label_row.offset.X, label_row.offset.Y)
            end
            
            labels_ofset.Y = labels_ofset.Y + label_row.size.Y
            
        end

        local size = #(task_list.labels_list)
        if size ~= 0 then
            local i = 1
            local remove_flag = nil
            while i <= size do
                if task_list.labels_list[i].status=="dead" then
                    quest.global_tasks[task_list.labels_list[i].global_task_index].label_index = nil
                    table.remove(task_list.labels_list, i)
                    size = size - 1
                    i = i - 1
                    remove_flag = true
                elseif remove_flag then
                    quest.global_tasks[task_list.labels_list[i].global_task_index].label_index = i
                end
                i = i + 1
            end
        end

        tasks_lua_widget._pre_draw_effects_list:Update()
		return false
	end,

	Load = function(_this, _info, _templates)
		tasks_lua_widget.this = _this
		tasks_lua_widget.font = nil
		tasks_lua_widget.completed_tasks_label = nil
		tasks_lua_widget.colors = 
		{ 
			sf.graphics.Color(255, 255, 255, 255), 
			sf.graphics.Color(255, 255, 255, 255), 
			sf.graphics.Color(255, 255, 255, 255) 
		}
		tasks_lua_widget.labels = {}
		
		local constants = quest.game_resources.GetChild("Constants", false).GetChildRef("task_list", false)
		__assert(constants, "'task_list' не найден в 'properties\\constants.xml'")
		local font_name,font = constants.GetValue("font").c_str(), nil
		if font_name~='' then font = sf.core.g_Application.GetResourceManager().GetFont(font_name) end
		__assert(font_name~='' and font, "Шрифт для списка действий не найден ('"..font_name.."')!")
		tasks_lua_widget.font = font
		
--[[
		local states = {"disabled", "normal", "completed"}
		for i,_ in ipairs(tasks_lua_widget.colors) do
			tasks_lua_widget.colors[i] = string_to_color(constants.GetValue(states[i]..'_color').c_str())
		end	
]]

        tasks_lua_widget.colors[4] = string_to_color(constants.GetValue('start_color').c_str())
        tasks_lua_widget.colors[5] = string_to_color(constants.GetValue('normal_color').c_str())
        tasks_lua_widget.colors[6] = string_to_color(constants.GetValue('end_color').c_str())

        local create_group = quest.game_resources.GetChild("Constants", false).GetChildRef("create_task_effect", false)
        if create_group then
            local res = tonumber(create_group.GetValue("visible_time").c_str())
            if res ~= nil then task_list.go_visible_time = res end
            res = tonumber(create_group.GetValue("color_time").c_str())
            if res ~= nil then task_list.go_color_time = res end
        end

        local complete_group = quest.game_resources.GetChild("Constants", false).GetChildRef("complete_task_effect", false)
        if complete_group then
            local res = tonumber(complete_group.GetValue("color_time").c_str())
            if res ~= nil then task_list.go_compl_color_time = res end
            res = tonumber(complete_group.GetValue("alpha_time").c_str())
            if res ~= nil then task_list.go_compl_alpha_time = res end
            res = tonumber(complete_group.GetValue("size_time").c_str())
            if res ~= nil then task_list.go_compl_size_time = res end
        end

        tasks_lua_widget._pre_draw_effects_list = visual_effects.CreateEffectsList()
	    return true
	end,
	
	__CreateInstance = function() return "tasks_lua_widget" end
}

__inherite(tasks_lua_widget, null_lua_widget_handler())

tasks_effects_lua_widget = 
{
	DoDraw = function(_this, _renderer)
        tasks_effects_lua_widget.visual_effects_list:PreDraw(_renderer)
        tasks_effects_lua_widget.visual_effects_list:PostDraw(_renderer)
		return false
	end,

	DoUpdate = function(_this)
        tasks_effects_lua_widget.visual_effects_list:Update()
		return false
	end,

	Load = function(_this, _info, _templates)
        tasks_effects_lua_widget.visual_effects_list = visual_effects.CreateEffectsList()
	    return true
	end,
	
	__CreateInstance = function() return "tasks_effects_lua_widget" end
}

__inherite(tasks_effects_lua_widget, null_lua_widget_handler())