assemble_image_with_one_free = {}

assemble_image_with_one_free.params = 
{
	init_positions = 
	{
		-- 1-8 - заполненные ячейки
		-- 9 - пустая ячейка
		{1, 2, 3},
		{4, 5, 6},
		{7, 8, 9}
	},

	highlight_effect = 
	{
		color =
		{
			min = sf.graphics.Color(0, 255, 255, 255),
			max = sf.graphics.Color(150, 255, 255, 255)
		},
		
		time = 700
	},
	
	moving_effect = 
	{
		speed = 0.8
	},
	
	sound_click = "shift_item"
}
 
function assemble_image_with_one_free.get_offset(_pos)
	return sf.misc.FloatVector(
		(_pos.X - 1) * assemble_image_with_one_free.cell_size.X,
		(_pos.Y - 1) * assemble_image_with_one_free.cell_size.Y
		)
end

function assemble_image_with_one_free.CheckEnd(_owner)
	local resolved = true
	
	for _, c in ipairs(assemble_image_with_one_free.cells) do	
		if c.target_pos.X ~= c.pos.X or c.target_pos.Y ~= c.pos.Y then
			resolved = false
			break
		end
	end
	
	if resolved == true then
		_owner.SetGameResult(1)
		_owner.OnEndGame()
	end
end

function assemble_image_with_one_free.OnMouseDown(_owner, _pos, _button, _state, _broadcast)
	for _, c in ipairs(assemble_image_with_one_free.cells) do
		if c ~= assemble_image_with_one_free.free_cell and c.widget.GetPoly().IsContains(_pos.X, _pos.Y) == true then		
			sf.core.g_Application.GetAudioManager().Play(assemble_image_with_one_free.params.sound_click, -2, -2, -2, -2, -2)
			local dist = sf.misc.CalculateFloatVectorModule(c.pos - assemble_image_with_one_free.free_cell.pos)
			if math.abs(dist) <= 1.001 then
				assemble_image_with_one_free.add_moving_effect(c, sf.misc.IntVector(assemble_image_with_one_free.free_cell.pos))	
				
				local temp = sf.misc.IntVector(c.pos)
				c.pos.X = assemble_image_with_one_free.free_cell.pos.X
				c.pos.Y = assemble_image_with_one_free.free_cell.pos.Y
				assemble_image_with_one_free.free_cell.pos.X = temp.X
				assemble_image_with_one_free.free_cell.pos.Y = temp.Y				
			end
		end
	end
	return false
end

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

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

function assemble_image_with_one_free.CHighlightEffect(_owner, _image, _time_create)
	
	local effect = 
	{
		owner = _owner,
		widget = sf.gui.CImageWidget(_image, _T(""), -1, 0),
		time_create = _time_create,
		is_dead = false,
		
		Update = function(_self, _time)			
			local tm = assemble_image_with_one_free.params.highlight_effect.time
			local cl_min = assemble_image_with_one_free.params.highlight_effect.color.min
			local cl_max = assemble_image_with_one_free.params.highlight_effect.color.max
			
			local t = _time - _self.time_create
			local k = 0.0
			
			if t < tm then
				local a = tm / 2.0
				k = (a - math.abs(t - a)) / a
			end
						
			local color = sf.graphics.Color()
			color.Alpha = cl_min.Alpha + (cl_max.Alpha - cl_min.Alpha) * k
			color.Red = cl_min.Red + (cl_max.Red - cl_min.Red) * k
			color.Green = cl_min.Green + (cl_max.Green - cl_min.Green) * k
			color.Blue = cl_min.Blue + (cl_max.Blue - cl_min.Blue) * k
			color.Clamp()
			
			_self.widget.SetColor(color)
			
			if t >= tm then
				_self.widget.AddFlags(sf.gui.CWidget.FlagDead)
				_self.is_dead = true
			end
		end
	}
		
	_owner.AddWidget(sf.gui.CImageWidgetPtrT(effect.widget))

	local size = _owner.GetSize()
	effect.widget.SetSize(size.X, size.Y)		
	effect.widget.SetColor(assemble_image_with_one_free.params.highlight_effect.color.min)
	
	return effect
end

function assemble_image_with_one_free.add_highlight_effect(_widget)
	local effect = assemble_image_with_one_free.CHighlightEffect(_widget, assemble_image_with_one_free.highlight_image.GetImage(), assemble_image_with_one_free.timer.Get().GetTime())
	table.insert(assemble_image_with_one_free.effects, effect)
end

function assemble_image_with_one_free.CMovingEffect(_cell, _from, _to, _time_create)
	
	local from, to = assemble_image_with_one_free.get_offset(_from), assemble_image_with_one_free.get_offset(_to)
	
	return
	{
		cell = _cell,
		from_cell = _from,
		to_cell = _to,
		from = from,
		to = to,
		dist = sf.misc.CalculateFloatVectorModule(to - from),
		time_create = _time_create,	
		is_dead = false,
		
		Update = function(_self, _time)			
			local speed = assemble_image_with_one_free.params.moving_effect.speed
			local k = (_time - _self.time_create) * speed / _self.dist
			
			if _self.cell.widget then
				if k >= 1.0 then	
					_self.cell.widget.SetOffset(_self.to.X, _self.to.Y)
					_self.is_dead = true	
					if _self.cell.target_pos.X == _self.to_cell.X and _self.cell.target_pos.Y == _self.to_cell.Y then
						assemble_image_with_one_free.add_highlight_effect(_self.cell.widget)
					end
				else
					local pos = _self.from + (_self.to - _self.from) * k
					_self.cell.widget.SetOffset(pos.X, pos.Y)
				end
			end
		end
	}	
end

function assemble_image_with_one_free.add_moving_effect(_cell, _to)
	local effect = assemble_image_with_one_free.CMovingEffect(_cell, _cell.pos, _to, assemble_image_with_one_free.timer.Get().GetTime())
	table.insert(assemble_image_with_one_free.effects, effect)
end

function assemble_image_with_one_free.set_positions()

	local init_positions = assemble_image_with_one_free.params.init_positions
	local r, c = #init_positions, #init_positions[1]
	for i = 1, r do 
		for j = 1, c do
			local cell = assemble_image_with_one_free.cells[init_positions[i][j]]
			assert(cell)
			cell.pos = sf.misc.IntVector(j, i)
			local offset = assemble_image_with_one_free.get_offset(cell.pos)
			if cell.widget then cell.widget.SetOffset(offset.X, offset.Y) end
		end
	end
end

function assemble_image_with_one_free.Init(_owner)
	
	sminigames.SetStandartScriptName(_owner, assemble_image)
	
	math.randomseed(os.time())
	
	assemble_image_with_one_free.back_image = __cast(_owner.GetWidget(_T("back"), true), sf.gui.CImageWidget)	
	assert(assemble_image_with_one_free.back_image)
	
	assemble_image_with_one_free.image = __cast(_owner.GetWidget(_T("image"), true), sf.gui.CImageWidget)	
	assert(assemble_image_with_one_free.image)
	assemble_image_with_one_free.image.AddFlags(sf.gui.CWidget.FlagHidden)
	
	local image_size = assemble_image_with_one_free.image.GetSize()
	
	local init_positions = assemble_image_with_one_free.params.init_positions
	local r, c = #init_positions, #init_positions[1]
	
	assemble_image_with_one_free.cells = {}		
	assemble_image_with_one_free.cell_size = sf.misc.FloatVector(image_size.X / c, image_size.Y / r)
	
	for i = 1, r do
		for j = 1, c do
			
			local widget = nil
			
			if not (j==c and i==r) then			
				local source_rect = sf.misc.IntRect(
					(j - 1) * assemble_image_with_one_free.cell_size.X,
					(i - 1) * assemble_image_with_one_free.cell_size.Y,
					assemble_image_with_one_free.cell_size.X,
					assemble_image_with_one_free.cell_size.Y
					)
				
				widget = sf.gui.CImageWidget(assemble_image_with_one_free.image.GetImage(), _T(""), 0, 0)
				widget.GetImage().SetSourceRect(source_rect)
				widget.SetSize(assemble_image_with_one_free.cell_size.X, assemble_image_with_one_free.cell_size.Y)
				widget.SetLayer(2)
				local offset = assemble_image_with_one_free.get_offset(sf.misc.IntVector(j, i))
				widget.SetOffset(offset.X, offset.Y)
				
				local widget_ptr = sf.gui.CImageWidgetPtrT(widget)
				_owner.AddWidget(widget_ptr)
			end
			
			local cell =
			{
				widget = widget,
				pos = sf.misc.IntVector(j, i),
				target_pos = sf.misc.IntVector(j, i)
			}
			
			table.insert(assemble_image_with_one_free.cells, cell)
		end
	end
	
	assemble_image_with_one_free.set_positions()
	
	assemble_image_with_one_free.free_cell = assemble_image_with_one_free.cells[r * c]

	assemble_image_with_one_free.highlight_image = __cast(_owner.GetWidget(_T("highlight"), true), sf.gui.CImageWidget)	
	assert(assemble_image_with_one_free.highlight_image)
	assemble_image_with_one_free.highlight_image.AddFlags(sf.gui.CWidget.FlagHidden)
	
	assemble_image_with_one_free.timer = sf.core.CTimerWrapper(sf.core.g_Application.GetTimeManager().AttachTimer(_T(""), nil))	
	
	assemble_image_with_one_free.effects = {}
	
	assemble_image_with_one_free.resolved = false
	
	local size = assemble_image_with_one_free.back_image.GetSize()
	_owner.SetSize(size.X, size.Y)
end
