--[[
Переливание жидкостей
 ]]

liquids_pouring = {}

local self = liquids_pouring

self.params = {
	weight_num_id = "scenes_scene06_02_minigame_minigame01_number", -- id циферок для весов
	weight_num_layer = 1, -- слой, на котором отображаются цифры на весах
	sound_on_pour = "mini_game_mini_game_liquids_pouring_water_01",  -- звук переливания
	sound_on_move = "mini_game_mini_game_liquids_pouring_go_01", -- звук движения полочки. в dsfrontend должно быть max_concurent_sound = 1
	sound_select = "mini_game_mini_game_birds_and_fishes_select_01", -- выделение колбочки
	sound_on_win = "", -- звук при победе
	before_win_clip_id = "wrong_center", -- клип, который мигает до победы, при победе мы его прячем
	win_clip_id = "correct_center", -- id из dsfrontend, проигрывается после победы. должен быть ненулевой таймлайн. 
	moving_shelf = 
	{ -- параметры движения полки
		lower_pos = sf.misc.FloatVector(355, 569), -- самая нижняя позиция полочки
		higher_pos = sf.misc.FloatVector(355, 121), -- самая верхняя позиция полочки
		start_pos = sf.misc.FloatVector(355, 569), -- где находится сначала
		bottle = 1, -- номер бутылки на полке
		speed = 10 -- скорость движения - пикселей в секунду
	},
	liquids_exchange_time = 100, -- за сколько милисекунд происходит обмен жидкостью (плавно с альфой)
	bottles = 
	{
		{ --1
			start_amount = 14, -- изначально полный
			size = 14, -- сколько входит
			need = 7, -- сколько должно быть в конце. 0 означает, что неважно
			id = "bottle01_", --  начало id жидкости для бутыльков (куча картинок в dsfrontend)
			layer = 2, -- слой бутылки
			select_clip ="glow01", -- клип на выделение. его центр совмещается с центром картинки-бутылька
			weight_number_pos =
			{ -- позиции для циферок на весах
				sf.misc.FloatVector(343, 131), -- единицы 
				sf.misc.FloatVector(319, 131) -- десятки
			}
		},
		{ --2
			start_amount = 0, -- изначально пустой
			size = 9, -- сколько входит
			need = 0, -- сколько должно быть в конце. 0 означает, что неважно
			id = "bottle02_", --  начало id жидкости для бутыльков (куча картинок в dsfrontend)
			layer = 2, -- слой бутылки
			select_clip ="glow02", -- клип на выделение. его центр совмещается с центром картинки-бутылька
			weight_number_pos =
			{ -- позиции для циферок на весах
				sf.misc.FloatVector(526, 503), -- единицы 
				sf.misc.FloatVector(502, 503) -- десятки
			},
			moving = false -- не движется на полочке
		},
		{ --3 
			start_amount = 0, -- изначально пустой
			size = 5, -- сколько входит
			need = 0, -- сколько должно быть в конце. 0 означает, что неважно
			id = "bottle03_", --  начало id жидкости для бутыльков (куча картинок в dsfrontend)
			layer = 2, -- слой бутылки
			select_clip ="glow03", -- клип на выделение. его центр совмещается с центром картинки-бутылька
			weight_number_pos =
			{ -- позиции для циферок на весах
				sf.misc.FloatVector(653, 386), -- единицы 
				sf.misc.FloatVector(627, 386) -- десятки
			},
			moving = false -- не движется на полочке
		}
	}
}

function self.Init(_owner)
	sminigames.SetStandartScriptName(_owner, liquids_pouring) 
	
	self.LoadInfo(_owner)
	self.timer = __create_timer()
end

-- подготовка к работе
function self.LoadInfo(_owner)
	self.objects = {}
	-- считываем бутыльки
	for i = 1, #self.params.bottles do
		local now = self.params.bottles[i].start_amount
	
		-- получаем виджет самой бутылки
		local id = "bottle"
		if i < 10 then
			id = id .. 0
		end
		id = id .. i
		local bottle = __cast(_owner.GetWidget(id, true), sf.gui.CImageWidget)
		__assert(bottle, "Нет image_widget бутылки в dsfrontend: id = "..id)
		local layer = self.params.bottles[i].layer or 1
		bottle.SetLayer(layer)
		
		local object = {
			bottle_image = bottle,
			weight = now, -- сколько сейчас
			size = self.params.bottles[i].size, -- сколько входит
			need = self.params.bottles[i].need, -- сколько должно быть в конце
			fill_images = {}, -- картинки с жидкостью
			weight_widgets = {} -- картинки с весом
		}
		
		table.insert(self.objects, object)
		
		local fill = nil
		-- считываем виджеты с заполнением
		fill =  self.GetFillImages(_owner, i)
		object.fill_images = fill
		
		self.ShowFillAmount(i, now)
		-- заполняем инфо о количестве
		self.SetBottleWeight(_owner, i, now)
	end
	
	self.selected = -1 -- выделенный объект
	
	local shelf = __cast(_owner.GetWidget("shelf", true), sf.gui.CImageWidget)
	shelf.SetOffset(self.params.moving_shelf.start_pos.X, self.params.moving_shelf.start_pos.Y)
	self.moving_widgets = 
	{ 
		shelf = shelf,
		bottle = self.objects[self.params.moving_shelf.bottle]
	}
	local right = __cast(_owner.GetWidget(self.params.win_clip_id, true), sf.gui.CClipWidget)
	if right then
		right.AddFlags(sf.gui.CWidget.FlagHidden)
	end
end 

-- устанавливает значение на весах бутылька
function self.SetBottleWeight(_owner, _i, _weight)
	-- удаляем старые картинки с весом этого бутылька
	
	for _, widget in pairs(self.objects[_i].weight_widgets) do
		_owner.RemoveWidget(widget)
	end
	self.objects[_i].weight_widgets = {}
	if _weight > 0 then
		-- получаем значения циферок на весах
		local ones = self.GetOnes(_weight)
		local tens = self.GetTens(_weight)
		local base_id = self.params.weight_num_id -- начало id картинки для любого числа
		
		local ones_id = base_id .. ones -- id для единиц
		local tens_id = base_id .. tens -- id для десятков
		-- где хранится информация о позициях виджетов
		local weight_pos = self.params.bottles[_i].weight_number_pos
		
		-- создаем картинки с виджетами
		local ones_widget = sf.gui.CImageWidget(ones_id, "ones_".._i, 0, 0)
		ones_widget.SetOffset(weight_pos[1].X, weight_pos[1].Y)
		local layer = self.params.weight_num_layer or 1
		ones_widget.SetLayer(layer)
		_owner.AddWidget(ones_widget)
		
		local tens_widget = sf.gui.CImageWidget(tens_id, "tens_".._i, 0, 0)
		tens_widget.SetOffset(weight_pos[2].X, weight_pos[2].Y)
		_owner.AddWidget(tens_widget)
		tens_widget.SetLayer(layer)
		
		table.insert(self.objects[_i].weight_widgets, ones_widget)
		table.insert(self.objects[_i].weight_widgets, tens_widget)
	end
end

-- возвращает единицы числа _num 
function self.GetOnes(_num)
	return _num % 10
end
-- возвращает десятки  числа
function self.GetTens(_num)
	return math.floor(_num / 10) % 10
end

function self.CheckEnd(_owner)
	for i = 1, #self.objects do
		-- проверяем соответствие содержимого объекта нужному количеству
		if self.objects[i].weight ~= self.params.bottles[i].need 
			and self.params.bottles[i].need ~= 0 then
				return false
		end
	end
	if self.params.sound_on_win then
		sound(self.params.sound_on_win)
	end
	
	local wrong = __cast(_owner.GetWidget(self.params.before_win_clip_id, true), sf.gui.CClipWidget)
	if wrong then
		wrong.AddFlags(sf.gui.CWidget.FlagHidden)
	end
	self.right = __cast(_owner.GetWidget(self.params.win_clip_id, true), sf.gui.CClipWidget)
	if self.right then
		self.right.RemFlags(sf.gui.CWidget.FlagHidden)
		self.right.GetClip().Play()
		self.win_start = self.timer.Get().GetTime()
	else
		_owner.OnEndGame()
	end
end 

-- проверяет, попали ли мы в бутылку
function self.IsBottle(_pos)
	for i = 1, #self.objects do
		if misc.GetRect(self.objects[i].bottle_image).IsContains(_pos.X, _pos.Y) then
			return i
		end
	end
	return nil
end 

-- выделяет объект
function self.Select(_owner, _i)
	self.Deselect(_owner)
	
	if self.params.sound_select then
		sound(self.params.sound_select)
	end
	
	self.selected = _i
	
	self.selection_clip =  sf.gui.CClipWidget("", 0, 0)
	self.selection_clip.GetClip().Load(self.params.bottles[self.selected].select_clip, true)
	_owner.AddWidget(self.selection_clip)
	-- вычисляем положение клипа (совмещаем его центр с центром изображения бутылки)
	local center_offset = self.objects[self.selected].bottle_image.GetOffset() + 
						self.objects[self.selected].bottle_image.GetSize()/2
	local clip_size = self.selection_clip.GetClip().GetViewSize()
	self.selection_clip.SetOffset(center_offset.X - clip_size.X/2, center_offset.Y- clip_size.Y/2)	
end

-- снимает выделение с объекта
function self.Deselect(_owner)
	if self.selected > 0 then
		self.selection_clip.GetClip().Stop()
		_owner.RemoveWidget(self.selection_clip)
	end
	
	self.selected = -1
end

function self.OnMouseDown(_owner, _pos, _button, _keyboard_state, _broadcast)
	if self.exchange_start or self.move_start  or self.win_start then 
		return false 
	end
	
	local ind = self.IsBottle(_pos) -- проверяем, попали ли мы в бутылку
	
	if not ind then return false end
	
	-- обработка попадания	
	if self.selected == ind then
		-- повторный клик снимает выделение
		self.Deselect(_owner)
	else
		if self.selected < 0  then
			if self.objects[ind].weight ~= 0 then 
				self.Select(_owner, ind) -- выделяем бутылек, если в нем что-то есть
			end
		else
			-- уже был выделен бутылек, выполняем переливание
			self.Pour(_owner, self.selected, ind)
			self.Deselect(_owner)
		end
	end
	
	return true
end 

-- функция, которая собственно изменяет количество жидкости в бутыльках
function self.Pour(_owner, _from, _where)
	-- вычисляем, сколько свободного места в бутыльке
	if self.params.sound_on_pour then
		sound(self.params.sound_on_pour)
	end
	local free_space = self.objects[_where].size - self.objects[_where].weight 
	local has = self.objects[_from].weight -- сколько есть в бутыльке-исходнике
	
	local amount = math.min(has, free_space) -- сколько переливаем
	-- меняем количества в бутыльках
	self.objects[_where].weight = self.objects[_where].weight + amount
	self.objects[_from].weight = self.objects[_from].weight - amount
	
	-- снимаем флаги с картинок, которые постепенно будут проявляться
	self.ShowFillAmount(_where, self.objects[_where].weight)
	-- создаем виджет с количеством жидкости для одного бутылька
	if self.objects[_where].weight < 0 then -- не может быть отрицательным, на всякий случай
		self.objects[_where].weight = 0
	end
	
	-- создаем списки виджетов, которые постепенно будут появляться/исчезать
	self.appear_widgets = {}
	for i = self.objects[_where].weight - amount + 1, self.objects[_where].weight do
		table.insert(self.appear_widgets, self.objects[_where].fill_images[i])
		local color = sf.graphics.Color(0, 255, 255, 255)
		self.objects[_where].fill_images[i].SetColor(color)
	end
	
	self.hiding_widgets = {}
	for i = self.objects[_from].weight + 1, self.objects[_from].weight + amount do
		table.insert(self.hiding_widgets, self.objects[_from].fill_images[i])
	end
	self.exchange_start = self.timer.Get().GetTime() -- начало обмена жидкостями
	self.from = _from
	self.where = _where
	
	if self.params.moving_shelf.bottle == _where or self.params.moving_shelf.bottle == _from then
		self.need_move_shelf = true
	else
		self.need_move_shelf = nil
	end
end 
-- считывает из dsfrontend все картинки с жидкостью для бутылька _num
function self.GetFillImages(_owner, _num)
	local fill = {}
	local base_id = self.params.bottles[_num].id
	local i = 1 
	local flag = true
	while flag do
		local id = nil 
		if i < 10 then
			id = base_id .. 0
		end
		if id then 
			id = id .. i
		else
			id = base_id .. i
		end
		
		local img = __cast(_owner.GetWidget(id, true), sf.gui.CImageWidget)
		if not img then
			img = __cast(_owner.GetWidget(id, true), sf.gui.CClipWidget)
		end
		if not img then
			flag = false
		else
			table.insert(fill, img)
			i = i + 1
		end
	end
	
	return fill
end 

-- показывает нужное количество картинок для бутылька _i
function self.ShowFillAmount(_i, _amount)
	local fill = self.objects[_i].fill_images
	--__message("количество жидкости: "..#fill)
	for i = 1, #fill do
		if i <= _amount then
			-- показываем
			fill[i].RemFlags(sf.gui.CWidget.FlagHidden)
		else
			fill[i].AddFlags(sf.gui.CWidget.FlagHidden)
			local color = sf.graphics.Color(255, 255, 255, 255)
			fill[i].SetColor(color) -- убираем эффект от постепенного увода в альфу
		end
	end
end 

function self.OnUpdate(_owner)
	if not self.exchange_start and not self.move_start and not self.win_start then 
		return 
	end
	
	if self.exchange_start then
		self.UpdateExchange(_owner)
	elseif self.move_start then
		self.UpdateMoving(_owner)
	elseif self.win_start then
		local now = self.timer.Get().GetTime()
		local clip_time = qe.GetClipTime(self.right.GetClip())
		if now - self.win_start >= clip_time then
			_owner.OnEndGame()
		end
	end
end 

-- обновление движения
function self.UpdateMoving(_owner)
	-- звук движения полочки
	if self.params.sound_on_move and self.need_move_shelf then
		sound(self.params.sound_on_move)
	end
	local dist = math.abs(self.start_pos.Y - self.end_pos.Y) -- расстояние 
	local need_time = 1000 * dist / self.params.moving_shelf.speed -- за сколько пройдем
	local now = self.timer.Get().GetTime()
	local cur_time = (now - self.move_start) / need_time
	if cur_time > 1 then -- сколько уже прошли
		cur_time = 1
	end
	local cur_pos = self.moving_widgets.shelf.GetOffset()
	local new_shelf_pos = self.start_pos + (self.end_pos - self.start_pos) * cur_time -- новое положение полки
	
	local diff = new_shelf_pos - cur_pos -- на сколько сдвинулись
	self.moving_widgets.shelf.SetOffset(new_shelf_pos.X, new_shelf_pos.Y)
	-- новое положение бутылки
	local bottle_off = self.moving_widgets.bottle.bottle_image.GetOffset() + diff
	self.moving_widgets.bottle.bottle_image.SetOffset(bottle_off.X, bottle_off.Y)
	
	-- новые положения заполнения
	for i, fill in ipairs(self.moving_widgets.bottle.fill_images) do
		local fill_off = fill.GetOffset() + diff
		fill.SetOffset(fill_off.X, fill_off.Y)
	end
	
	if cur_time == 1 then
		self.move_start = nil
		
		self.CheckEnd(_owner)
	end
end

-- обновление при обмене жидкостями
function self.UpdateExchange(_owner)
	local now = self.timer.Get().GetTime()
	local cur_time = (now - self.exchange_start) / self.params.liquids_exchange_time
	if cur_time > 1 then
		cur_time = 1
	end
	local color_appear = sf.graphics.Color(255*cur_time, 255, 255, 255)
	local color_hide = sf.graphics.Color(255*(1 - cur_time), 255, 255, 255)
	for i = 1, #self.appear_widgets do
		self.appear_widgets[i].SetColor(color_appear)
		self.hiding_widgets[i].SetColor(color_hide)
	end
	
	if cur_time == 1 then
		-- закончили переливать
		self.ShowFillAmount(self.from, self.objects[self.from].weight)
		self.SetBottleWeight(_owner, self.from, self.objects[self.from].weight)
		self.SetBottleWeight(_owner, self.where, self.objects[self.where].weight)
		
		self.from = nil
		self.where = nil
		self.exchange_start = nil
		
		if self.need_move_shelf then
			-- инициализация движения полочки
			self.move_start = now
			self.start_pos = self.moving_widgets.shelf.GetOffset() -- откуда идем
			local num = self.params.moving_shelf.bottle -- номер двигающейся бутылки
			local weight = self.objects[num].weight
			local y_diff = self.params.moving_shelf.lower_pos.Y - self.params.moving_shelf.higher_pos.Y
			local y_step = y_diff / self.params.bottles[num].size -- вычисляем, сколько надо пройти при изменении веса на единицу
			self.end_pos = self.params.moving_shelf.higher_pos + sf.misc.FloatVector(0, y_step * weight) -- куда идем
		else
			self.CheckEnd(_owner)
		end
	end
end 