cursor_lua_widget = cursor_lua_widget or {}

quest.current_cursor = nil

cursor_lua_widget.hint_font = "hint_base_font"

cursor_lua_widget._text_font = sf.core.g_Application.GetResourceManager().GetFont(cursor_lua_widget.hint_font)

cursor_lua_widget.ring_object_width = 50

cursor_lua_widget.object_offset = sf.misc.FloatVector(0, 0)

cursor_lua_widget.object_scale = sf.misc.FloatVector(1, 1)

cursor_lua_widget.hint_offset = sf.misc.FloatVector(10, 10)

cursor_lua_widget.allow_sleep = true

cursor_lua_widget.say_cursor_id = ""
cursor_lua_widget.say_cursor_image = nil

cursor_lua_widget.actions = cursor_lua_widget.actions or {}

-- переменая, в которой хранится новый объект для взятия в курсор,
-- который может быть установленн во время выполенния скрипта и 
-- будет применен по его завершению
cursor_lua_widget._new_cursor_object = nil

cursor_lua_widget.actions.cancel = 
{
	pressed = function(_window) 
		_window.AddFlags(_window.FlagDead) 
	end
}

cursor_lua_widget.mouse_in_window_flag = true

function cursor_lua_widget.__CreateInstance()
    return "cursor_lua_widget"
end

function cursor_lua_widget.Show(_objects, _window)
end

function DrawHintToObject(_renderer, _pos, _hint_text)
    for i,o in pairs(cursor_lua_widget.scenes_table) do
        local left_top = o.pos
        local right_bottom = o.pos + o.size
        if _pos.X > left_top.X and _pos.Y > left_top.Y and _pos.X < right_bottom.X and _pos.Y < right_bottom.Y then
            return 
        end
    end
    _hint_text = sf.misc.g_StringTable.Instance().FormatByStringsID(_hint_text)
    if cursor_lua_widget._text_font then
    
        local text_width = cursor_lua_widget._text_font.GetStringWidth(_hint_text);

		local hint_x_pos = _pos.X
		if text_width + hint_x_pos > 1024 then
			hint_x_pos = 1024 - text_width
        end
        _renderer.RenderString(cursor_lua_widget._text_font, _hint_text, hint_x_pos, _pos.Y, -1, -1, 1, sf.graphics.Color(255, 255, 255, 255), 0)
    end

end

cursor_lua_widget.show_cheat_hints = 0

function show_all_hints_on_scene(_renderer, _scene, _pos)
    _renderer.PushState()
    _renderer.ApplyMatrix(sf.misc.MatrixTranslation(_pos.X, _pos.Y))
    local current_child = _scene.GetObjects()
    while not current_child.IsEnd() do
        local object = current_child.Get()
        if not object.ReadObjectFlag(qe.CBaseSceneObject.ObjectFlagRemoved) and  not object.ReadObjectFlag(qe.CBaseSceneObject.ObjectFlagHidden)  and  not object.ReadObjectFlag(qe.CBaseSceneObject.ObjectFlagDisable) then

            local object_type = object.GetType()
            if object_type == qe.CBaseSceneObject.GroupType then
                local group_hint = object.GetHint().c_str()


                local child_hint_text = nil            
                local child_hint_pos = nil            
                local visible_child = false
                local group = __cast(object.get(), qe.CSceneGroup)
                if group then
                    local current_group_child = group.GetChilds()
                    while not current_group_child.IsEnd() do
                        local child_object = current_group_child.Get()
                        if not child_object.ReadObjectFlag(qe.CBaseSceneObject.ObjectFlagHidden) then
                           visible_child = true                  
                        end
                        if not child_object.ReadObjectFlag(qe.CBaseSceneObject.ObjectFlagHidden)  and  not child_object.ReadObjectFlag(qe.CBaseSceneObject.ObjectFlagDisable) then
                            local child_hint = child_object.GetHint().c_str()
        
                            if child_hint ~= "" then
                                child_hint_text = child_hint            
                                child_hint_pos = child_object.GetPos()
                            end
                        end
                        current_group_child.Next()
                    end 
                end
                if child_hint_text then
                    DrawHintToObject(_renderer, child_hint_pos, child_hint_text)
                else
                    if group_hint ~= "" and visible_child then
                        local pos = object.GetPos()
                        DrawHintToObject(_renderer, pos, group_hint)
                    end

                end
            else
                local hint = object.GetHint().c_str()
                if hint ~= "" then
                    local pos = object.GetPos()
                    DrawHintToObject(_renderer, pos, hint)
                end
            end
        end
        current_child.Next()
    end

    local current_area = _scene.GetAreas()

    while not current_area.IsEnd() do
        local current_area_object = current_area.Get()
        if not current_area_object.ReadObjectFlag(qe.CBaseSceneObject.ObjectFlagHidden)  and  not current_area_object.ReadObjectFlag(qe.CBaseSceneObject.ObjectFlagDisable) then
            local area_hint = current_area_object.GetHint().c_str()
            if area_hint ~= "" then
                DrawHintToObject(_renderer, current_area_object.GetPos(), area_hint)
            end
        end
        current_area.Next()
    end
    _renderer.PopState()
end

-- функция которая устанавливает флаг, который запрещает менять курсор полсе выполнения скрипта
function cursor_lua_widget.DoNotChangeCursor()
	quest.do_not_change_cursor_flag = true
end

-- функция для взятия в курсор объекта со сцены
function cursor_lua_widget.TakeToCursor(_id)
	-- находим объект, который добавляется в курсор
	local object = quest.FindRootObjectById(_id)
	if not object then
		-- если объект не найден, то ругаемся и ничего не делаем
		__message("TakeToCursor: Объект ".._id.." не найден.")
		return
	end
	-- если объект найден, то запоминаем его 
	cursor_lua_widget._new_cursor_object = object
	-- делаем действие нейтральным
	neutral_click()
end

-- функция применения нового объекта, если он был установлен в скрипте
function cursor_lua_widget.ApplyObjectToCursor()
	-- если нового объекта для курсора нет, то выходим
	if not cursor_lua_widget._new_cursor_object then return end
	-- иначе устанавливаем найденный объект как объект в курсоре
	quest.global_cursor.SetCursorObject(cursor_lua_widget._new_cursor_object)
	cursor_lua_widget.UpdateCursorsTable()
	-- сбрасываем переменую где хранился новый объект
	cursor_lua_widget._new_cursor_object = nil
end

function cursor_lua_widget.DoDraw(_this, _renderer)
    cursor_lua_widget.scenes_table = {}
    if cursor_lua_widget.show_cheat_hints == 1 then
        local current_widget = quest.global_scene_widget.GetWidgets()
        while not current_widget.IsEnd() do
            local scene_widget = __cast(current_widget.Get(), qe.CSceneWidget)     
            if scene_widget ~= nil then
                local scene_id = scene_widget.GetSceneId().c_str()
                local _scene_pos = scene_widget.GetAbsPos(false)
                local _scene_size = scene_widget.GetSize()
                table.insert(cursor_lua_widget.scenes_table, {pos = _scene_pos, size = _scene_size})
                show_all_hints_on_scene(_renderer, quest.global_played_level.GetSceneById(scene_id), _scene_pos)
                
            end
            current_widget.Next()
        end            
        show_all_hints_on_scene(_renderer, quest.global_current_main_scene, sf.misc.FloatVector(0, 0))
    end
    quest.global_cursor.Draw(_renderer)
    return true
end

function cursor_lua_widget.UpdateCursorsTable()
	local cursors_table = level_hints.GetCursorsTable()
	cursors_table = cursors_table or {}
	cursor_lua_widget.SetCursorsTable(cursors_table)
end

function cursor_lua_widget.SetCursorsTable(_table)
    cursor_lua_widget._cursor_table = _table
    if cursor_lua_widget.current_cursor_object ~= nil then
        cursor_lua_widget.SetGameCursor(cursor_lua_widget.current_cursor_object)
    end
end

function cursor_lua_widget.GetCursorsTable()
    return cursor_lua_widget._cursor_table
end

function cursor_lua_widget.SetSayCursor(_item_id)
    if _item_id and cursor_lua_widget.say_cursor_image then
        quest.say_cursor = cursor_lua_widget.say_cursor_image
        sf.gui.g_Cursor.Instance().SetCustomCursor( cursor_lua_widget.say_cursor_image )
    else
        quest.say_cursor = nil
        cursor_lua_widget.DropCursor()
    end
end

function cursor_lua_widget.SetGameCursor(_item_id)
    cursor_lua_widget.current_cursor_object = _item_id
    if threads_managment.IsClikThread() == false or quest.allow_game_cursor == true then
        local cursor_id = nil
        for i,o in pairs(cursor_lua_widget._cursor_table) do
            if o[_item_id] then
                cursor_id = i
            end
        end
        if cursor_id then
            quest.game_cursor = sf.core.g_Application.GetResourceManager().GetTexture(cursor_id)
            sf.gui.g_Cursor.Instance().SetCustomCursor( quest.game_cursor )
        else
            cursor_lua_widget.DropGameCursor()
        end
	end
end

function cursor_lua_widget.DropGameCursor()
    quest.game_cursor = nil
    cursor_lua_widget.current_cursor_object = nil
end

function cursor_lua_widget.UpdateCursor()
    if  quest.current_cursor ~= nil then
        sf.gui.g_Cursor.Instance().SetCursor(quest.current_cursor)    
    elseif quest.say_cursor ~= nil then
        sf.gui.g_Cursor.Instance().SetCustomCursor(quest.say_cursor  )
    elseif quest.game_cursor ~= nil then
		sf.gui.g_Cursor.Instance().SetCustomCursor(quest.game_cursor  )
    else
        quest.current_cursor = nil
        sf.gui.g_Cursor.Instance().SetCursor(sf.gui.CCursor.CursorPointer)    
    end
end

function cursor_lua_widget.DropCursor()
    quest.current_cursor = nil
    quest.script_time = nil
    sf.gui.g_Cursor.Instance().SetCursor(sf.gui.CCursor.CursorPointer)
end

cursor_lua_widget.stil_flag = false
cursor_lua_widget.stil_start_time = 0
cursor_lua_widget.stil_sleep_delay = 3000
cursor_lua_widget.need_wake_up = false



function cursor_lua_widget.DoUpdate(_this)
	local time = quest.level_timer.Get().GetTime()
    if cursor_lua_widget.allow_sleep then
        if cursor_lua_widget.stil_flag == false then
            cursor_lua_widget.stil_start_time = time
            cursor_lua_widget.stil_flag = true
            --if cursor_lua_widget.need_wake_up then
                if avatar_widget.GetCurrentState() == "sleep" then
                    avatar_widget.ChangeState("normal")
                end
            --end
            --cursor_lua_widget.need_wake_up = false

        --elseif cursor_lua_widget.need_wake_up == false then
        elseif avatar_widget.GetCurrentState() ~= "sleep" then
            if time - cursor_lua_widget.stil_start_time > cursor_lua_widget.stil_sleep_delay then
                if threads_managment.IsClikThread() then
                    cursor_lua_widget.stil_start_time = time
                else
                    avatar_widget.ChangeState("sleep", 0)
                end
                --cursor_lua_widget.need_wake_up = true
            end
        end
    end
    if quest.do_not_change_curosor then return true end
	
	if threads_managment.IsClikThread() == true then
		if quest.current_cursor == nil then
			if quest.script_time == nil then
				quest.script_time = time
			else
				if time - quest.script_time > quest.go_to_hourglass_delay then
					quest.current_cursor = sf.gui.CCursor.CursorHourglass
					sf.gui.g_Cursor.Instance().SetCursor(quest.current_cursor)    
				end
			end
		end
	elseif quest.script_time ~= nil then
		quest.script_time = nil

		quest.current_cursor = nil
		sf.gui.g_Cursor.Instance().SetCursor(sf.gui.CCursor.CursorPointer)
	end

    return true
end

function cursor_lua_widget.OnChar(_this, _char, _keyboard_state, _state, _broadcast)
	return false
end

function cursor_lua_widget.OnKeyDown(_this, _key, _keyboard_state, _state, _broadcast)
	return _this.SuperOnKeyDown( _key, _keyboard_state, _state, _broadcast)
end

function cursor_lua_widget.OnKeyUp(_this, _key, _keyboard_state, _state, _broadcast)
	return _this.SuperOnKeyUp( _key, _keyboard_state, _state, _broadcast)
end

function cursor_lua_widget.OnMouseMove(_this, _pos, _state, _broadcast)
    cursor_lua_widget.stil_flag = false
    cursor_lua_widget.UpdateCursor()    
    
    if objects_box_lua_widget.mouse_down_info ~= nil then
        local distantion = sf.misc.CalculateFloatVectorModule((objects_box_lua_widget.abs_pos + objects_box_lua_widget.mouse_down_info.pos) - _pos)
        if distantion > objects_box_lua_widget.drag_distance then
            objects_box_lua_widget.mouse_down_info = nil
            quest.global_cursor.SetIsDrag(true)
        end
    end
	return false
end

function cursor_lua_widget.OnMouseDown(_this, _pos, _button, _state, _broadcast)
	return false
end

function cursor_lua_widget.OnMouseUp(_this, _pos, _button, _state, _broadcast)
	return false
end

function cursor_lua_widget.OnDoubleClick(_this, _pos, _state, _broadcast)
	return false
end

function cursor_lua_widget.OnMouseWheel(_this, _pos, _delta, _state, _broadcast)
	return false
end

function cursor_lua_widget.OnChildAction(_this, _action, _child)
	if not _child then return false end
	local handler = cursor_lua_widget.actions[_child.GetId().c_str()]
	if handler then handler = handler[_action.c_str()] end
	if handler then handler(_this, _child) end
end

function cursor_lua_widget.LoadConstants(_constants)
	local self = cursor_lua_widget
	
	local avatars = _constants.GetChild("avatars", false)
    if avatars then
        if avatars.GetValue("allow_sleep").c_str() == "false" then
            cursor_lua_widget.allow_sleep = false
        end
        local res = tonumber(avatars.GetValue("time_before_sleep").c_str())
        if res~= nil then
            cursor_lua_widget.stil_sleep_delay = res
        end
    end    
    

	local cursors = _constants.GetChild("cursors", false)
    self.object_offset.X = tonumber(cursors.GetValue("object_offset_x").c_str()) or self.object_offset.X
	self.object_offset.Y = tonumber(cursors.GetValue("object_offset_y").c_str()) or self.object_offset.Y
    quest.global_cursor.SetObjectOffset(self.object_offset)
	
	self.object_scale.X = tonumber(cursors.GetValue("object_scale_x").c_str()) or self.object_scale.X
	self.object_scale.X = tonumber(cursors.GetValue("object_scale_y").c_str()) or self.object_scale.Y
    quest.global_cursor.SetCursorObjectScale(self.object_scale)
	
	quest.go_to_hourglass_delay = tonumber(cursors.GetValue("go_to_hourglass_delay").c_str())

	local res = cursors.GetValue("say_cursor_id").c_str()
    if res ~= "" then
        cursor_lua_widget.say_cursor_id = res
    end
    cursor_lua_widget.say_cursor_image = sf.core.g_Application.GetResourceManager().GetTexture(cursor_lua_widget.say_cursor_id)
	
	local hints = _constants.GetChild("hints", false)
    self.hint_offset.X = tonumber(hints.GetValue("hint_offset_x").c_str()) or self.hint_offset.X
	self.hint_offset.Y = tonumber(hints.GetValue("hint_offset_y").c_str()) or self.hint_offset.Y
    quest.global_cursor.SetHintOffset(self.hint_offset)

    local res = hints.GetValue("hint_font").c_str()
    if res ~= "" then
        cursor_lua_widget.hint_font = res
    end

    cursor_lua_widget._text_font = sf.core.g_Application.GetResourceManager().GetFont(cursor_lua_widget.hint_font)

    quest.global_cursor.SetHintFont(cursor_lua_widget.hint_font)

    local ring_offset_X = tonumber(cursors.GetValue("ring_offset_x").c_str())
	local ring_offset_Y = tonumber(cursors.GetValue("ring_offset_y").c_str())
	cursor_lua_widget.ring_object_width = tonumber(cursors.GetValue("ring_object_width").c_str()) or cursor_lua_widget.ring_object_width

    quest.global_cursor.SetPreObjectOffset(sf.misc.FloatVector(ring_offset_X, ring_offset_Y))


	local ring_id = cursors.GetValue("ring_id").c_str()
	if ring_id ~= "" then
        quest.global_cursor.SetPreObject(ring_id)
    end
    quest.global_cursor.SetObjectWidth(cursor_lua_widget.ring_object_width)
    

end

function cursor_lua_widget.Load(_info, _templates)
    return true
end

cursor_lua_widget._cursor_table = {}
