--[[
Исходные данные: есть 10 ячеек, есть 4 объекта цвета A и 4 объекта цвета B. Объекты располагаются в ячейках начиная с первой, чередуясь по цветам.
Т.е, например так:
1 2 3 4 5 6 7 8 9 10
A B A B A B A B _ _

За один ход, игрок может перемещать 2 объекта (неважно каких цветов). Реализовать так, чтобы при наведении на один объект, выделялся объект следующий
за ним ( если он есть), либо предыдущий, если следующего нет.

Цель игры: за 5 ходов переместить объекты одного цвета в одну сторону, другого - в другую:
1 2 3 4 5 6 7 8 9 10
A A A A _ _ B B B B
]]

split_figures_by_type = {}
local self = split_figures_by_type

self.params = {
	image_prefix = "pos0", -- начало id-шников в dsfrontend'е для всех объектов
	clip_under_tile = "minigame_book_shine", -- клип под "книжку"
	clip_types = { -- для книжек разных видов, кладется поверх
		"minigame_book_shine_fire", -- первый тип
		"minigame_book_shine_water" -- второй тип
	},
	speed = 15, -- скорость движения каретки
	turns = 5, -- количество ходов, которые сделаны
	game_over_clip = { -- клипы, проигрывающийся при поражении
		{layer = 2, clip="minigame_book_game_over_02", offset = sf.misc.FloatVector(-9, 377)},
		{layer = 5, clip="minigame_book_game_over_03", offset = sf.misc.FloatVector(0, 0)}
	}, 
	clip_progress = "minigame_book_sun", -- клипы отображающие прогресс игры
	sound_move = "carriage_move", -- звук движения каретки
	sound_place_item = "shift_item_01", -- звук опускания фигурок в игре
	sound_take_item = "selection_of_item", -- звук выделения фигурок
	clamp_pos_diff = sf.misc.FloatVector(-17, -19), -- сдвиг зажима относительно верхнего угла левой фишки
	layer_on_move = 3, -- слой фишки при движении
	init_layer = 2, -- изначальный слой фишки
	sun_centers = { -- центры солнышек, к которым летят партикли при конце хода
		 sf.misc.FloatVector(140, 329),
		 sf.misc.FloatVector(292, 212),
		 sf.misc.FloatVector(500, 155),
		 sf.misc.FloatVector(717, 233),
		 sf.misc.FloatVector(852, 331)
	},
	particle_id = "minigame_sunrise",
	positions = {
		{ -- 1
			obj_type = 1,
			end_type = 2
		},
		{ -- 2
			obj_type = 2,
			end_type = 2
		},
		{ -- 3
			obj_type = 1,
			end_type = 2
		},
		{ -- 4
			obj_type = 2,
			end_type = 2
		},
		{ -- 5
			obj_type = 1,
			end_type =0 -- будет пусто
		},
		{ -- 6
			obj_type = 2,
			end_type = 0
		},
		{ -- 7
			obj_type = 1,
			end_type = 1
		},
		{ -- 8
			obj_type = 2,
			end_type = 1
		},
		{ -- 1
			obj_type = 0,
			end_type = 1
		},
		{ -- 10
			obj_type = 0,
			end_type = 1
		}
	}
}

self.Init = function(_owner)
	sminigames.SetStandartScriptName(_owner, split_figures_by_type) 
	
	self.LoadInfo(_owner)
end

function self.LoadInfo(_owner)
	self.pos_amount = #self.params.positions -- количество позиций
	
	self.timer = __create_timer("", "qe_level") -- создаем таймер
		
	self.turns = 0 -- еще не сделано ни одного хода
	--  создадим массив виджетов с рисунками передвигаемых объектов
	self.init_objects = {}
	self.objects = {}
	for i = 1, self.pos_amount do
		local img = __cast(_owner.GetWidget(self.params.image_prefix..i , true), sf.gui.CImageWidget)
		local id = "book_down_" -- id для клипа с опусканием книжечек
		if (i<10) then
			id = id.. 0
		end
		id = id .. i
		local o = {image = img, obj_type = self.params.positions[i].obj_type, clip_id = id}
		table.insert(self.objects, o)
		table.insert(self.init_objects, {image = img, obj_type = self.params.positions[i].obj_type, X = img.GetOffset().X, Y = img.GetOffset().Y })
	end
	self.selected = {}
	self.selection_clips = {}
	
	self.left_turns = __cast(_owner.GetWidget("turns", true), sf.gui.CLabelWidget)
	local left = self.params.turns - self.turns
	self.left_turns.SetText("   "..tostring(left).."  ")
	self.BurningSun(_owner)	
	
	-- вращающиеся и невращающиеся шестеренки
	self.gears_moving = __cast(_owner.GetWidget("gears_moving", true), sf.gui.CClipWidget)
	self.gears_moving.GetClip().Pause()
	-- штука, которая захватывает две фишки
	self.clamp = __cast(_owner.GetWidget("clamp", true), sf.gui.CImageWidget)
	self.clamp_init_pos = {X = self.clamp.GetOffset().X, Y = self.clamp.GetOffset().Y}
	self.selecting = nil -- флаг о том, что штука сейчас ползет к выделяемым фишкам
	self.SelectObjects(_owner, 1)
	self.AddSelectionClips(_owner)
end
-- проигрываем клип с подсветкой солнышка, показывая таким образом количество ходов
function self.BurningSun(_owner)
	if self.progress_clip then
		_owner.RemoveWidget(self.progress_clip)
	end
	self.progress_start = self.timer.Get().GetTime()
	self.progress_clip = sf.gui.CClipWidget("", 3, 0)
	local clip_id 
	if self.turns == 0 then
		clip_id = self.params.clip_progress
		self.progress_clip.SetLayer(3)
	else
		clip_id = self.params.particle_id
		self.progress_clip.SetLayer(0)
	end
		if self.turns < 10 then
			clip_id = clip_id .. 0
		end
		clip_id = clip_id .. (self.turns + 1)
		self.progress_clip.GetClip().Load(clip_id, true)
		self.progress_clip.GetClip().Stop()
		_owner.AddWidget(self.progress_clip)
		self.progress_clip.GetClip().Play()
		self.progress_time = qe.GetClipTime(self.progress_clip.GetClip())
	
	--self.need_delete = true
end
-- если закончились ходы =)
function self.BackToStart(_owner)
	self.turns = 0
	local left = self.params.turns - self.turns
	self.left_turns.SetText("   "..tostring(left).."  ")
	self.Deselect(_owner)
	
	self.game_over = {}
	-- клипы на поражение общие
	for i = 1, #self.params.game_over_clip do
		local clip1 = sf.gui.CClipWidget("", self.params.game_over_clip[i].layer, 0)
		clip1.GetClip().Load(self.params.game_over_clip[i].clip, true)
		local offset = self.params.game_over_clip[i].offset
		clip1.SetOffset(offset.X, offset.Y)
		clip1.GetClip().Stop()
		_owner.AddWidget(clip1)
		clip1.GetClip().Play()
		table.insert(self.game_over, clip1)
	end
	-- клипы на уезжание пластинок вниз
	for i = 1, #self.objects do
		local id = self.objects[i].clip_id
		local clip = sf.gui.CClipWidget("", self.objects[i].image.GetLayer(), 0)
		clip.GetClip().Load(id, true)
		clip.GetClip().Stop()
		_owner.AddWidget(clip)
		table.insert(self.game_over, clip)
		local offset = self.objects[i].image.GetOffset()
		clip.SetOffset(offset.X, offset.Y)
		clip.GetClip().Play()
	end
	self.start_clip = self.timer.Get().GetTime()
	
	for i = 1, #self.objects do
		self.objects[i].image.AddFlags(sf.gui.CWidget.FlagHidden)
	end
	
	self.clamp_start = self.clamp.GetOffset()
	self.clamp_finish = { X = self.clamp_init_pos.X, Y = self.clamp_init_pos.Y }
	-- двигаем шестеренки
	self.gears_moving.GetClip().Play()
end
-- подвинуть каретку в соответствии с ее скоростью к выделяемым объектам
function self.MoveClampToObject(_owner)
	-- рассчитываем сколько надо пройти
	
	local dist_x = (self.clamp_start.X - self.clamp_finish.X) * (self.clamp_start.X - self.clamp_finish.X)
	local dist_y = (self.clamp_start.Y - self.clamp_finish.Y) * (self.clamp_start.Y - self.clamp_finish.Y)
	local dist = math.sqrt(dist_x + dist_y) 
	local need_time = dist/self.params.speed * 1000 -- сколько нужно времени
	local current_time = (self.timer.Get().GetTime() - self.start_time) / need_time
	if current_time > 1 then
		current_time = 1
	elseif self.params.sound_move then
		sound(self.params.sound_move)
	end
	--- новые координаты
	local new_x = self.clamp_start.X + (self.clamp_finish.X - self.clamp_start.X)*current_time
	local new_y = self.clamp_start.Y + (self.clamp_finish.Y - self.clamp_start.Y)*current_time
	
	self.clamp.SetOffset(new_x, new_y)
		
	if current_time == 1 then
		-- дошли до конца, надо выделить
		self.selecting = nil
		
		-- останавливаем шестеренки
		self.gears_moving.GetClip().Pause()
		
		if self.params.sound_take_item and not self.game_over then
			sound(self.params.sound_take_item)
		end
	end
end
-- если проиграли, надо дождаться, пока проиграет клип на поражение
function self.GameOverUpdate(_owner)
		local time_clip = 0
		for i = 1, #self.game_over do
			local i_time = qe.GetClipTime(self.game_over[i].GetClip())
			if time_clip < i_time then
				time_clip = i_time
			end
		end
		 self.MoveClampToObject(_owner)
		if self.timer.Get().GetTime() - self.start_clip > time_clip then
			for i = 1, #self.game_over do
				_owner.RemoveWidget(self.game_over[i])
			end
				self.BurningSun(_owner)
				for j = 1, #self.objects do
					self.objects[j].image.RemFlags(sf.gui.CWidget.FlagHidden)
				end
			--end
			self.game_over = nil
			for i = 1, self.pos_amount do
				self.objects[i].image = self.init_objects[i].image
				self.objects[i].image.SetOffset(self.init_objects[i].X, self.init_objects[i].Y)
				self.objects[i].obj_type = self.init_objects[i].obj_type
			end
			self.SelectObjects(_owner, 1)
			self.AddSelectionClips(_owner)
			
			
		elseif self.timer.Get().GetTime() - self.start_clip > time_clip/2 then
			

			self.gears_moving.GetClip().Pause()
			self.selecting = nil -- флаг о том, что штука сейчас ползет к выделяемым фишкам
		end
end

function self.MoveObjectsToNewPos(_owner) 
	-- рассчитываем сколько надо пройти
	
	local dist_x = (self.clamp_start.X - self.clamp_finish.X) * (self.clamp_start.X - self.clamp_finish.X)
	local dist_y = (self.clamp_start.Y - self.clamp_finish.Y) * (self.clamp_start.Y - self.clamp_finish.Y)
	local dist = math.sqrt(dist_x + dist_y) 
	local need_time = dist/self.params.speed * 1000 -- сколько нужно времени
	local current_time = (self.timer.Get().GetTime() - self.start_time) / need_time
	if current_time > 1 then
		current_time = 1
	elseif self.params.sound_move then
		sound(self.params.sound_move)
	end
	--- новые координаты
	local cur_x = self.clamp.GetOffset().X
	local new_x2 = self.clamp_start.X + (self.clamp_finish.X - self.clamp_start.X)*current_time
	local new_y2 = self.clamp_start.Y + (self.clamp_finish.Y - self.clamp_start.Y)*current_time
	self.clamp.SetOffset(new_x2, new_y2)
	-- новые координаты первой фишки
	local new_x = self.moving_widgets[1].GetOffset().X + (new_x2 - cur_x)
	local new_y = self.moving_widgets[1].GetOffset().Y
	self.moving_widgets[1].SetOffset(new_x, new_y)
	
	for i = 1, #self.selection_clips do	
		local new_x = self.selection_clips[i].GetOffset().X + (new_x2 - cur_x)
		local new_y = self.selection_clips[i].GetOffset().Y
		self.selection_clips[i].SetOffset(new_x, new_y)
	end
	
	-- новые координаты второй фишки
	local new_x1 = self.moving_widgets[2].GetOffset().X + (new_x2 - cur_x)
	local new_y1 = self.moving_widgets[2].GetOffset().Y
	self.moving_widgets[2].SetOffset(new_x1, new_y1)
	
	if current_time == 1 then
		-- дошли до конца, надо снять выделение
		self.moving = nil
		--self.BurningSun(_owner) -- зажигаем следующее положение солнышка
		self.CheckEnd(_owner)
		-- на всякий случай
		self.selecting = nil
		-- останавливаем шестеренки
		self.gears_moving.GetClip().Pause()

		-- возвращаем на изначальный слой
		self.moving_widgets[1].SetLayer(self.params.init_layer)
		self.moving_widgets[2].SetLayer(self.params.init_layer)
		
		if self.params.sound_place_item then
			sound(self.params.sound_place_item)
		end
		
		for i = 1, #self.selection_clips do	
			local cur_layer = self.selection_clips[i].GetLayer()
			self.selection_clips[i].SetLayer(cur_layer - 2)
		end
		
	end
end

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

	-- если у нас каретка движется без фишек
	if self.progress_start then
		local now = self.timer.Get().GetTime()
		if now - self.progress_start >= self.progress_time then
			self.progress_start = nil
		end
	elseif self.selecting then
		self.MoveClampToObject(_owner)
	end
	if self.moving then
		self.MoveObjectsToNewPos(_owner) -- двигаем все
	end
	-- если закончились ходы, надо расставить фишки заново
	if self.game_over then
		self.GameOverUpdate(_owner)
	end
	
end
function self.CheckEnd(_owner)
	local flag = true
	for i = 1, self.pos_amount do
		if self.objects[i].obj_type ~= self.params.positions[i].end_type then
			flag = false
			break
		end
	end
	
	
	if flag and self.turns <= self.params.turns then
		_owner.SetGameResult(1)
		_owner.OnEndGame()
	elseif self.turns == self.params.turns then
		self.BackToStart(_owner)
	else
		-- создаем партикли для движения к солнышку
		self.BurningSun(_owner)
	end
end

-- проверяет, в какой объект кликнули
function self.IsObject(_owner, _pos)
	for i = 1, #self.objects do
		local width, height = self.objects[i].image.GetSize().X, self.objects[i].image.GetSize().Y
		-- центр картинки
		local pos_x = self.objects[i].image.GetOffset().X + width/2
		local pos_y = self.objects[i].image.GetOffset().Y + height/2
		
		if math.abs(_pos.X - pos_x) < width/2 and math.abs(_pos.Y - pos_y) < height/2 then
			-- попали в виджет
			return i
		end
	end
	return nil
end

function self.Deselect(_owner) -- убрать подсветку с выделенных прежде
	local n = #self.selection_clips
	while n > 0 do
		_owner.RemoveWidget(self.selection_clips[n])
		table.remove(self.selection_clips, n)
		n = n - 1
	end
end

function self.SelectObjects(_owner, _index)
	local n = #self.objects
	if _index == n or self.objects[_index + 1].obj_type == 0 then
		-- нет объекта справа - надо выделить этот и левый
		if _index == 1 or self.objects[_index - 1].obj_type == 0 then
			return -- слева нет объектов, ничего не выделили
		else
			-- слева есть объекты
			self.Deselect(_owner) -- убрать подсветку с выделенных прежде
			self.selected = {}
			table.insert(self.selected, _index - 1)
			table.insert(self.selected, _index)
		end
	else
		-- справа есть объект, выделяем его и тот, в который кликнули
		self.Deselect(_owner) -- убрать подсветку с выделенных прежде
		self.selected = {}
		table.insert(self.selected, _index)
		table.insert(self.selected, _index + 1)
	end
end

function self.AddSelectionClips(_owner)
if #self.selected > 0 then
	-- подсветка клипами
	local off1 = self.objects[self.selected[1]].image.GetOffset()
	local off2 = self.objects[self.selected[2]].image.GetOffset()
	local size = self.objects[self.selected[1]].image.GetSize()
	-- подложка
	local clip1 = sf.gui.CClipWidget("", 1, 0)
	clip1.GetClip().Load(self.params.clip_under_tile, true)

	clip1.SetOffset(off1.X + size.X/2 - clip1.GetClip().GetViewSize().X/2, off1.Y + size.Y/2 - clip1.GetClip().GetViewSize().Y/2)
	_owner.AddWidget(clip1)
	local clip2 = sf.gui.CClipWidget("", 1, 0)
	clip2.GetClip().Load(self.params.clip_under_tile, true)
	clip2.SetOffset(off2.X + size.X/2 - clip2.GetClip().GetViewSize().X/2, off2.Y + size.Y/2 - clip2.GetClip().GetViewSize().Y/2)
	_owner.AddWidget(clip2)
	
	-- сверху
	local clip3 = sf.gui.CClipWidget("", 3, 0)
	local type1 = self.objects[self.selected[1]].obj_type
	local type2 = self.objects[self.selected[2]].obj_type
	
	clip3.GetClip().Load(self.params.clip_types[type1], true)
	clip3.SetOffset(off1.X + size.X/2 - clip3.GetClip().GetViewSize().X/2 + 1.5, off1.Y + size.Y/2 - clip3.GetClip().GetViewSize().Y/2 + 0.5)
	_owner.AddWidget(clip3)
	local clip4 = sf.gui.CClipWidget("", 3, 0)
	clip4.GetClip().Load(self.params.clip_types[type2], true)
	clip4.SetOffset(off2.X + size.X/2 - clip4.GetClip().GetViewSize().X/2 + 1.5, off2.Y + size.Y/2 - clip4.GetClip().GetViewSize().Y/2 + 0.5)
	_owner.AddWidget(clip4)
	table.insert(self.selection_clips, clip1)
	table.insert(self.selection_clips, clip2)
	table.insert(self.selection_clips, clip3)
	table.insert(self.selection_clips, clip4)
end
end

function self.OnMouseDown(_owner, _pos, _button, _state, _broadcast)
	-- ищем, куда попали
	if self.selecting or self.moving or self.progress_start then return true end
	if self.game_over then return true end
	
	local click = self.IsObject(_owner, _pos)
	if not click then
		return false-- никуда не попали
	else
		-- попали.
		if self.objects[click].obj_type > 0 then
			-- кликнули не на пустое место - надо выделить два объекта
			self.selecting = true
			self.SelectObjects(_owner, click)
			self.AddSelectionClips(_owner)
			self.clamp_finish = self.objects[self.selected[1]].image.GetOffset() + self.params.clamp_pos_diff -- финишная позиция выделения
			self.clamp_start = self.clamp.GetOffset() -- откуда поехали
			self.start_time = self.timer.Get().GetTime() -- когда начали ехать
			-- двигаем шестеренки
			
			self.gears_moving.GetClip().Play()
		else
			-- попали в пустое место. надо проверить, были ли выделены объекты, и если были - поменять их расположение и снять выделение
			if #self.selected == 0 then
				return false
			else
				local n = #self.objects
				if click == n or self.objects[click + 1].obj_type > 0 then
					click = click - 1 -- click - индекс левой свободной ячейки
				end
				self.SwitchFigures(_owner, click)

			end
		end
		return true
	end
end 

-- переносит выбранные фигуры на пустое место и снимает выделение
function self.SwitchFigures(_owner, _free_index)
	-- снимаем выделение
	
	-- меняем картинки местами
	local img_offset1_x, img_offset1_y = self.objects[_free_index].image.GetOffset().X, self.objects[_free_index].image.GetOffset().Y
	local img_offset2_x, img_offset2_y  = self.objects[self.selected[1]].image.GetOffset().X, self.objects[self.selected[1]].image.GetOffset().Y
	local img_offset3_x, img_offset3_y = self.objects[_free_index + 1].image.GetOffset().X, self.objects[_free_index + 1].image.GetOffset().Y
	local img_offset4_x, img_offset4_y = self.objects[self.selected[2] ].image.GetOffset().X, self.objects[self.selected[2] ].image.GetOffset().Y

	-- каретка
	self.clamp_finish = self.objects[_free_index].image.GetOffset() + self.params.clamp_pos_diff -- финишная позиция выделения
	self.clamp_start = self.clamp.GetOffset() -- откуда поехали
	self.start_time = self.timer.Get().GetTime() -- когда начали ехать
	-- двигаем шестеренки
	
	self.gears_moving.GetClip().Play()
	
	-- перемещаем пустые клетки на место фишек
	self.objects[_free_index].image.SetOffset(img_offset2_x, img_offset2_y)
	self.objects[_free_index + 1].image.SetOffset(img_offset4_x, img_offset4_y)

	-- запоминаем куда и откуда должны попасть фишки
	self.moving = true
	self.start_offsets = { img_offset2_x, img_offset4_x	}
	self.finish_offsets =  { img_offset1_x, img_offset3_x}

	self.start_time = self.timer.Get().GetTime() -- время начала движения
	self.moving_widgets = {self.objects[self.selected[1] ].image, self.objects[self.selected[2] ].image}
	
	-- выводим фишки на передний план
	self.moving_widgets[1].SetLayer(self.params.layer_on_move)
	self.moving_widgets[2].SetLayer(self.params.layer_on_move)
	
	
	
	--меняем местами позиции в массиве
	local tmp
	tmp = self.objects[_free_index].image
	self.objects[_free_index].image = self.objects[self.selected[1] ].image
	self.objects[self.selected[1] ].image = tmp
	tmp = self.objects[_free_index].obj_type
	self.objects[_free_index].obj_type = self.objects[self.selected[1] ].obj_type
	self.objects[self.selected[1] ].obj_type = tmp
	tmp = self.objects[_free_index].clip_id
	self.objects[_free_index].clip_id = self.objects[self.selected[1] ].clip_id
	self.objects[self.selected[1] ].clip_id = tmp
	
	tmp = self.objects[_free_index + 1].image
	self.objects[_free_index + 1].image = self.objects[self.selected[2] ].image
	self.objects[self.selected[2] ].image = tmp
	tmp = self.objects[_free_index + 1].obj_type
	self.objects[_free_index + 1 ].obj_type = self.objects[self.selected[2] ].obj_type
	self.objects[self.selected[2] ].obj_type = tmp
	tmp = self.objects[_free_index + 1].clip_id
	self.objects[_free_index + 1].clip_id = self.objects[self.selected[2] ].clip_id
	self.objects[self.selected[2] ].clip_id = tmp

	self.SelectObjects(_owner, _free_index)
	self.AddSelectionClips(_owner)
	for i = 1, #self.selection_clips do	
		local cur_layer = self.selection_clips[i].GetLayer()
		self.selection_clips[i].SetLayer(cur_layer+2)
	end
	-- добавляем ходы и обновляем текст label_widget
	self.turns = self.turns + 1
	
	local left = self.params.turns - self.turns
	self.left_turns.SetText("   "..tostring(left).."  ")
	

end 