categorize_stuff = {}

categorize_stuff.params = 
{
	inaccuracy = 30.0,
	
	item_size = 40.0,
	
	categories =
	{
		{
			cols = 2,
			rows = 3,
			rect = sf.misc.FloatRect(248.0, 92.0, 88.0, 134.0)
		},
		{
			cols = 2,
			rows = 3,
			rect = sf.misc.FloatRect(246.0, 319.0, 88.0, 134.0)
		}
	},
	
	moving_effect = 
	{
		speed = 0.8
	},
	
	sound_take_put = "take_put_item"
}

-- находит вещь по позиции
function categorize_stuff.FindItemByPos(_owner, _pos)
	local w = _owner.GetWidgets()
	while not w.IsEnd() do
		local widget = w.Get()
		if widget.GetPoly().IsContains(_pos.X, _pos.Y) then
			for _,info in pairs(categorize_stuff.items) do		
				if widget.GetId()==info.widget.GetId() then 
					return info.widget 
				end
			end
			break
		end
		w.Next()
	end
end

-- находит область по позиции
function categorize_stuff.FindCategoryByPos(_pos)
	for name,info in pairs(categorize_stuff.categories) do
		if info.widget.GetPoly().IsContains(_pos.X, _pos.Y) then
			return name
		end
	end
end

function categorize_stuff.CheckEnd(_owner)
	local inaccuracy = categorize_stuff.params.inaccuracy * categorize_stuff.params.inaccuracy
	for i, cells in pairs(categorize_stuff.cells) do
		for j, cell in pairs(cells) do
			local it = nil
			for _, item in pairs(categorize_stuff.items) do
				if item.cat == i and (item.widget.GetOffset() + item.widget.GetSize() / 2.0  - cell.pos).ModSqr() <= inaccuracy then
					it = item
					break
				end
			end
			if not it then
				return
			end
		end
	end
	
	_owner.SetGameResult(1)
	_owner.OnEndGame()
end

function categorize_stuff.OnUpdate(_owner)	
	
	local i, size = 1, #categorize_stuff.effects
	while i <= size  do		
		local e = categorize_stuff.effects[i]		
		e:Update(categorize_stuff.timer.Get().GetTime())
		if e.is_dead == true then
			table.remove(categorize_stuff.effects, i)
			size = size - 1
		else
			i = i + 1
		end		
	end
end

function categorize_stuff.CMovingEffect(_widget, _from, _to, _time_create)
	
	return
	{
		widget = _widget,
		from = sf.misc.FloatVector(_from),
		to = sf.misc.FloatVector(_to),
		dist = sf.misc.CalculateFloatVectorModule(_to - _from),
		time_create = _time_create,	
		is_dead = false,
		
		Update = function(_self, _time)			
			local speed = categorize_stuff.params.moving_effect.speed
			local k = (_time - _self.time_create) * speed / _self.dist
			
			if _self.widget then
				if k >= 1.0 then
					sf.core.g_Application.GetAudioManager().Play(categorize_stuff.params.sound_take_put, -2, -2, -2, -2, -2)
					_self.widget.SetOffset(_self.to.X, _self.to.Y)
					_self.is_dead = true	
				else
					local pos = _self.from + (_self.to - _self.from) * k
					_self.widget.SetOffset(pos.X, pos.Y)
				end
			end
		end
	}	
end

function categorize_stuff.add_moving_effect(_widget, _to)
	local effect = categorize_stuff.CMovingEffect(_widget, _widget.GetOffset(), _to, categorize_stuff.timer.Get().GetTime())
	table.insert(categorize_stuff.effects, effect)
end


function categorize_stuff._DropItem(_owner, _pos)
	assert(categorize_stuff.move_item)
	
	local inaccuracy = categorize_stuff.params.inaccuracy * categorize_stuff.params.inaccuracy
	local widget = categorize_stuff.move_item
	local found = false
	for i, cells in pairs(categorize_stuff.cells) do
		found = false
		for j, cell in pairs(cells) do
			if (widget.GetOffset() + widget.GetSize() / 2.0 - cell.pos).ModSqr() <= inaccuracy then
				local target_pos = cell.pos - widget.GetSize() / 2.0
				-- проверяем, есть ли в ячейке другой элемент
				local already_occupied = false
				for _, item in pairs(categorize_stuff.items) do		
					if item.widget ~= widget and sf.misc.CalculateFloatVectorModule(item.widget.GetOffset()-target_pos) < 0.001 then
						already_occupied = true
						break
					end
				end
				if not already_occupied then
					-- если ячейка свободна, перемещаем элемент в ячейку
					categorize_stuff.add_moving_effect(widget, target_pos)
					found = true
				else
					-- если ячейка занята, возвращаем элемент на его последнию позицию
					categorize_stuff.add_moving_effect(widget, categorize_stuff.last_widget_pos)					
				end
				break
			end
		end
		if found then break end
	end
	
	if not found then sf.core.g_Application.GetAudioManager().Play(categorize_stuff.params.sound_take_put, -2, -2, -2, -2, -2) end
	
	categorize_stuff.move_item = nil	
	categorize_stuff.last_widget_pos = nil
	categorize_stuff.last_mdown_pos = nil
	
	categorize_stuff.CheckEnd(_owner)
	
	return true 
end
		
function categorize_stuff.OnMouseDown(_owner, _pos, _button, _state, _broadcast)
	if categorize_stuff.move_item then
		-- если перетаскивали вещь
		return categorize_stuff._DropItem(_owner, _pos)
	else
		local item = categorize_stuff.FindItemByPos(_owner, _pos)
		if item then
			sf.core.g_Application.GetAudioManager().Play(categorize_stuff.params.sound_take_put, -2, -2, -2, -2, -2)
			
			categorize_stuff.move_item = item

			assert(categorize_stuff.top_item)
			item.LayInFront(categorize_stuff.top_item)
			categorize_stuff.top_item = item
			
			categorize_stuff.last_widget_pos = sf.misc.FloatVector(categorize_stuff.move_item.GetOffset())
			categorize_stuff.last_mdown_pos = sf.misc.IntVector(_pos)

			categorize_stuff.OnMouseMove(_owner, _pos, _state, _broadcast)
			
			return true
		end
	end
	return false
end

function categorize_stuff.OnMouseMove(_owner, _pos, _state, _broadcast)
	if categorize_stuff.move_item then	
		categorize_stuff.move_item.SetOffset(
			categorize_stuff.last_widget_pos.X + (_pos.X - categorize_stuff.last_mdown_pos.X),
			categorize_stuff.last_widget_pos.Y + (_pos.Y - categorize_stuff.last_mdown_pos.Y))
		return true
	end
	return false
end

local inacc = 5
function categorize_stuff.OnMouseUp(_owner, _pos, _button, _state, _broadcast)
	if categorize_stuff.move_item then
		local delta = _pos - categorize_stuff.last_mdown_pos
		if delta.ModSqr() > inacc*inacc then
			return categorize_stuff._DropItem(_owner, _pos)
		end
		return true
	end
	return false
end

function categorize_stuff.OnPreferredSize(_owner)
	return sminigames.OnPreferredSize(_owner)
end

function categorize_stuff.Init(_owner)
	categorize_stuff.categories = {}
	categorize_stuff.items = {}
	categorize_stuff.cells = {}
	categorize_stuff.move_item = nil
	categorize_stuff.top_item = nil
	categorize_stuff.dragging = false
	categorize_stuff.last_mdown_pos = nil
	
	sminigames.SetStandartScriptName(_owner, categorize_stuff)
	
	-- находим изображения, которые нужно разместить по ячейкам
	local w = _owner.GetWidgets()
	while not w.IsEnd() do
		local widget = w.Get()
		local cat = string.match(widget.GetId().c_str(), "(%d+)_(%d+)")
		if cat and categorize_stuff.params.categories[tonumber(cat)] then
			if not categorize_stuff.top_item then 
				categorize_stuff.top_item = widget 
			end
			table.insert(categorize_stuff.items, {cat = tonumber(cat), widget = widget} )
		end
		w.Next()
	end	
	
	-- высчитываем ячейки
	local cell_size = categorize_stuff.params.item_size
	for i, cat in pairs(categorize_stuff.params.categories) do
		categorize_stuff.cells[i] = {}
		local indent_x = 0.0
		if cat.cols > 1 then indent_x = (cat.rect.Width - cat.cols * cell_size) / (cat.cols - 1) end
		local indent_y = 0.0
		if cat.rows > 1 then indent_y = (cat.rect.Height - cat.rows * cell_size) / (cat.rows - 1) end
		for r = 1, cat.rows do
			for c = 1, cat.cols do
				local cell = 
				{
					pos = sf.misc.FloatVector(
						cat.rect.X + (c - 1) * (cell_size + indent_x) + cell_size / 2.0, 
						cat.rect.Y + (r - 1) * (cell_size + indent_y) + cell_size / 2.0)
				}
				table.insert(categorize_stuff.cells[i], cell)
			end
		end
	end
	
	categorize_stuff.timer = sf.core.CTimerWrapper(sf.core.g_Application.GetTimeManager().AttachTimer(_T(""), nil))
	
	categorize_stuff.effects = {}

end
