catch_objects = {}
catch_objects.fly_objects = {}
catch_objects.data = {}
catch_objects.data.point = {}

catch_objects.params = 
{
	-- количество монет
	coins_count = 15,
	
	-- количество камней
	stones_count = 8,
	
	-- горизонтальные плоскости, на которых могут располагаться монеты и камни
	planes = 
	{
		{p1 = sf.misc.FloatVector(106.0, 106.0), p2 = sf.misc.FloatVector(395.0, 121.0)},
		{p1 = sf.misc.FloatVector(474.0, 124.0), p2 = sf.misc.FloatVector(653.0, 128.0)},
		{p1 = sf.misc.FloatVector(204.0, 178.0), p2 = sf.misc.FloatVector(648.0, 168.0)},
		{p1 = sf.misc.FloatVector(6.0, 402.0), p2 = sf.misc.FloatVector(55.0, 399.0)},
		{p1 = sf.misc.FloatVector(135.0, 386.0), p2 = sf.misc.FloatVector(451.0, 391.0)},
		{p1 = sf.misc.FloatVector(569.0, 388.0), p2 = sf.misc.FloatVector(636.0, 380.0)},
		{p1 = sf.misc.FloatVector(3.0, 466.0), p2 = sf.misc.FloatVector(118.0, 464.0)},
		{p1 = sf.misc.FloatVector(10.0, 555.0), p2 = sf.misc.FloatVector(233.0, 567.0)},
		{p1 = sf.misc.FloatVector(499.0, 566.0), p2 = sf.misc.FloatVector(654.0, 582.0)}
	},
	
	-- скорость "хватальника"
	catcher_speed = 1.0,
	
	-- скорость падения камня
	stone_speed = 0.5,
	
	-- на сколько "хватальник" выступает относительно верхнего края
	catcher_offset = sf.misc.FloatVector(0.0, 50.0),
	
	-- звуки
	-- звук удара упавшего камня
	sound_stone_knock = "",
	-- звук взятия монеты или камня
	sound_take = ""
}

function catch_objects.CreateCells()

	local cell_width = math.max(
		math.max(catch_objects.coin_image.GetSize().X, catch_objects.stone1_image.GetSize().X), catch_objects.stone2_image.GetSize().X)
	
	catch_objects.cells = {}
	
	for _, p in pairs(catch_objects.params.planes) do
		local count = sf.misc.CalculateFloatVectorModule(p.p2-p.p1) / cell_width
		for i = 0, count do
			local cell = 
			{		
				pos = p.p1 + (p.p2 - p.p1) * (i / count),
				occupied = false
			}
			table.insert(catch_objects.cells, cell)			
		end	
	end
end

function catch_objects.GetFreeCells()
	local free_cells = {}
	if catch_objects.cells then
		for _, c in pairs(catch_objects.cells) do
			if c.occupied == false then
				table.insert(free_cells, c)
			end
		end
	end
	return free_cells
end

function catch_objects.GetRandomFreeCell()
	local free_cells = catch_objects.GetFreeCells()
	if #free_cells then
		return free_cells[math.random(#free_cells)]
	end
	return nil
end

function catch_objects.GetGoodObjects()
	local good_objects = {}
	for _, o in pairs(catch_objects.objects) do
		if o.group == "good" then
			table.insert(good_objects, o)
		end
	end
	return good_objects
end

function catch_objects.OnMouseMove(_owner, _pos, _button, _keyboard_state, _broadcast)
	if catch_objects.state == _T("move_h") and catch_objects.catcher and catch_objects.catcher.widget then
		catch_objects.catcher.widget.SetOffset(misc.Clamp(_pos.X - catch_objects.catcher.widget.GetSize().X / 2, 0, _owner.GetSize().X - catch_objects.catcher.widget.GetSize().X), catch_objects.catcher.widget.GetOffset().Y)
		return true
	end
	return false
end

function catch_objects.OnMouseDown(_owner, _pos, _button, _keyboard_state, _broadcast)
	if catch_objects.state == _T("move_h") then
		catch_objects.state = _T("move_v")
		return true
	end
	return false
end

function catch_objects.GetPlaceInArea(_place_array, _size)
	local place = {}
		place.current = {}
		place.best = false
		place.x = 0
		place.y = 0
		place.square = 0
	local repeat_count = 5
	for i = 1,repeat_count do
		-- Вычисление случайной позиции
		place.current.x = math.random(catch_objects.data.area.square)
		place.current.square = 0
		for place_index in pairs(_place_array) do
			if	_place_array[place_index] then
				if	place.current.x > _place_array[place_index].square then
					place.current.x = place.current.x - _place_array[place_index].square
				else
					place.current.y = (place.current.x - place.current.x % _place_array[place_index].width) / _place_array[place_index].width
					place.current.x = place.current.x - place.current.y * _place_array[place_index].width
					place.current.x = place.current.x + _place_array[place_index].x
					place.current.y = place.current.y + _place_array[place_index].y
					break
				end
			end
		end
		-- Определение занятой площади
		for index in pairs(catch_objects.objects) do
			if	catch_objects.objects[index] and catch_objects.objects[index].widget then
				place.current.square = place.current.square + misc.Intersection(misc.GetRect(catch_objects.objects[index].widget), sf.misc.FloatRect(place.current.x - _size.X / 2, place.current.y - _size.Y / 2,  _size.X, _size.Y))
			end
		end
		-- Определение лучшей позиции
		if	place.best == false or place.square > place.current.square then
			place.best = true
			place.x = place.current.x
			place.y = place.current.y
			place.square = place.current.square
			if	place.square == 0 then
				break
			end
		end
	end
	return place
end

function catch_objects.data.point.AddPoint(_x, _y)
	place_index = table.maxn(catch_objects.data.point.array) + 1
	catch_objects.data.point.array[place_index] = {}
	catch_objects.data.point.array[place_index].x = _x
	catch_objects.data.point.array[place_index].y = _y
end

function catch_objects.OnUpdate(_owner)
	if  sf.core.g_Application.GetTimeManager().GetTimer(_T("qe_level")).GetK() < 0.01 then
		return
	end

	current_time = catch_objects.timer.Get().GetTime()
	delta_time = current_time - catch_objects.last_update_time
	catch_objects.last_update_time = current_time
	
	shift = catch_objects.params.catcher_speed * delta_time
	update = 0
	
	for i = 1, #catch_objects.fly_objects do				
		local o = catch_objects.fly_objects[i]				
		local vector = {}
			
		vector.x = (o.cell.pos.X - o.widget.GetSize().X / 2.0) - o.widget.GetOffset().X
		vector.y = (o.cell.pos.Y - o.widget.GetSize().Y) - o.widget.GetOffset().Y
		
		length =  math.sqrt(vector.x*vector.x + vector.y*vector.y)
		k = delta_time * catch_objects.params.stone_speed
		
		if	catch_objects.params.stone_speed and k < length then
			vector.x = vector.x / length * k
			vector.y = vector.y / length * k
			vector.x = vector.x + o.widget.GetOffset().X 
			vector.y = vector.y + o.widget.GetOffset().Y
			o.widget.SetOffset(vector.x, vector.y)
		else
			vector.x = o.cell.pos.X - o.widget.GetSize().X / 2.0
			vector.y = o.cell.pos.Y - o.widget.GetSize().Y
			o.widget.SetOffset(vector.x, vector.y)
			
			sf.core.g_Application.GetAudioManager().Play(_T(catch_objects.params.sound_stone_knock), -2, -2, -2, -2, -2)
			
			table.remove(catch_objects.fly_objects, i)
			table.insert(catch_objects.objects, o)
			i = i - 1
		end
	end
	
	if #catch_objects.fly_objects == 0 then
		if	catch_objects.state == _T("move_v") then
			misc.MoveOn(catch_objects.catcher.widget, 0, shift)
			if	(catch_objects.catcher.widget.GetOffset().Y + catch_objects.catcher.widget.GetSize().Y >= _owner.GetSize().Y) then
				catch_objects.state = _T("back_v")
			end
		elseif catch_objects.state == _T("back_v") then
			shift = - shift 
			misc.MoveOn(catch_objects.catcher.widget, 0, shift)
			if	catch_objects.catcher.catched_object and catch_objects.catcher.catched_object.widget then
				misc.MoveOn(catch_objects.catcher.catched_object.widget, 0, shift)
			end		
			if	catch_objects.catcher.widget.GetOffset().Y <= catch_objects.catcher.info.start_position.y then
				catch_objects.state = _T("move_h")
				if	catch_objects.catcher.catched_object and catch_objects.catcher.catched_object.widget then
					if catch_objects.catcher.catched_object.group == "good" then
						_owner.RemoveWidget(catch_objects.catcher.catched_object.widget)						
						local good_objects = catch_objects.GetGoodObjects()
						end_game = (#good_objects == 0)
						if	end_game	then
							_owner.SetGameResult(1)
							_owner.OnEndGame()
						end						
						catch_objects.catcher.catched_object = nil						
					elseif catch_objects.catcher.catched_object.group == "bad" then						
						local cell = catch_objects.GetRandomFreeCell()
						if cell then
							cell.occupied = true
							catch_objects.catcher.catched_object.cell = cell														
						end
						table.insert(catch_objects.fly_objects, catch_objects.catcher.catched_object)
						catch_objects.catcher.catched_object = nil						
					end
				end
			end
			return
		end
	end
	
	if	catch_objects.catcher.widget then
		for i=1, #catch_objects.objects do
			local o = catch_objects.objects[i]
			local object_center = o.widget.GetOffset() + o.widget.GetSize() / 2.0
			if	catch_objects.catcher.widget.GetPoly().IsContains(object_center.X, object_center.Y) then
				sf.core.g_Application.GetAudioManager().Play(_T(catch_objects.params.sound_take), -2, -2, -2, -2, -2)
				catch_objects.catcher.catched_object = o
				o.cell.occupied = false
				table.remove(catch_objects.objects, i)
				catch_objects.state = _T("back_v")
				return
			end
		end
	end
end

function catch_objects.OnPreferredSize(_owner)
	return sf.misc.FloatVector(catch_objects.size.x, catch_objects.size.y)
end

function catch_objects.Load(_widget, _data)
	sminigames.SetStandartScriptName(_widget, catch_objects)
	
	catch_objects.size = _data.size

	catch_objects.objects = {} -- В эту таблицу будут добавлены объекты
	
	_widget.AddFlags(sf.gui.CBaseWidget.FlagClipDraw)
	
	catch_objects.state = _T("move_h")
	
	catch_objects.catcher = {}
	catch_objects.catcher.info = _data.catcher
	catch_objects.last_update_time = sf.core.g_Application.GetTimeManager().GetTime()
	math.randomseed(os.time())
	
	-- Загрузка объектов

	local objects = 
	{
		{count = catch_objects.params.stones_count, group = "bad", image = "stone1"},
		{count = catch_objects.params.coins_count, group = "good", image = "coin"}
	}
	
	for _, v in pairs(objects) do		
		for i=1, v.count do			
			local object = {}
			object.widget = sf.gui.CImageWidgetPtrT(sf.gui.CImageWidget(catch_objects[v.image..'_image'].GetImage(), _T(""), 5, 0))
			object.group = v.group
			local cell = catch_objects.GetRandomFreeCell()			
			if cell then
				cell.occupied = true
				local pos = sf.misc.FloatVector(cell.pos.X - object.widget.GetSize().X / 2.0, cell.pos.Y - object.widget.GetSize().Y)
				object.widget.SetOffset(pos.X, pos.Y)
				object.cell = cell
				object.type = _T("area")
			end			
			_widget.AddWidget(object.widget)
			table.insert(catch_objects.objects, object)
		end
	end
	
	-- Загрузка "захвата"
	catch_objects.catcher.widget = sf.gui.CImageWidgetPtrT(sf.gui.CImageWidget(_data.catcher.image, _T(""), 10, 0))
	_data.catcher.start_position.y = catch_objects.catcher.info.start_position.y - catch_objects.catcher.widget.GetSize().Y
	_widget.AddWidget(catch_objects.catcher.widget)
	catch_objects.catcher.widget.SetOffset(catch_objects.catcher.info.start_position.x, catch_objects.catcher.info.start_position.y)
	
	collectgarbage()
end

function catch_objects.Init(_widget)

    catch_objects.timer = __create_timer("", "qe_level")

	catch_objects.back_image = __cast(_widget.GetWidget(_T("back"), true), sf.gui.CImageWidget)
	assert(catch_objects.back_image)

	catch_objects.coin_image = __cast(_widget.GetWidget(_T("coin"), true), sf.gui.CImageWidget)
	assert(catch_objects.coin_image)
	catch_objects.coin_image.AddFlags(sf.gui.CWidget.FlagHidden)
	
	catch_objects.catcher_image = __cast(_widget.GetWidget(_T("catcher"), true), sf.gui.CImageWidget)
	assert(catch_objects.catcher_image)
	catch_objects.catcher_image.AddFlags(sf.gui.CWidget.FlagHidden)
	
	catch_objects.stone1_image = __cast(_widget.GetWidget(_T("stone1"), true), sf.gui.CImageWidget)
	assert(catch_objects.stone1_image)
	catch_objects.stone1_image.AddFlags(sf.gui.CWidget.FlagHidden)
	
	catch_objects.stone2_image = __cast(_widget.GetWidget(_T("stone2"), true), sf.gui.CImageWidget)
	assert(catch_objects.stone2_image)
	catch_objects.stone2_image.AddFlags(sf.gui.CWidget.FlagHidden)
	
	catch_objects.CreateCells()
	
	local data = {}
			
	-- Описание брошеных  объектов
	data.fly_objects = {}
		
	data.size = {}
	data.size.x = catch_objects.back_image.GetSize().X
	data.size.y = catch_objects.back_image.GetSize().Y
	
	data.catcher = {}
	data.catcher.image = catch_objects.catcher_image.GetImage()
	data.catcher.start_position = {}
	data.catcher.start_position.x = catch_objects.params.catcher_offset.X
	data.catcher.start_position.y = catch_objects.params.catcher_offset.Y

	catch_objects.Load(_widget, data)
end
