assemble_image = {}

assemble_image.params = 
{
	size = sf.misc.IntVector(3, 3),

	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
	},
	
	-- цвет элемента, вставшего на место
	color_hide = sf.graphics.Color(255, 255, 255, 255),
	-- цвет выделенного элемента
	color_active = sf.graphics.Color(255, 120, 160, 255),
	-- цвет элемента, находящегося не на своем месте
	color_standart = sf.graphics.Color(255, 255, 255, 180),
	
	sound_select = "select_part",
	sound_put = "put_part"
}
 
function assemble_image.OnChangeItemPlace(_owner)
	if assemble_image.images and assemble_image.images.array then
		local item_index = 1
		local end_game = true
		while item_index <= #assemble_image.images.array do
			if	assemble_image.images.array[item_index] and assemble_image.images.array[item_index].widget then
				if 	assemble_image.images.array[item_index].place.x == assemble_image.images.array[item_index].current_place.x and
				assemble_image.images.array[item_index].place.y == assemble_image.images.array[item_index].current_place.y then
					if	assemble_image.active == nil or item_index ~= assemble_image.active then
						assemble_image.UpdateColor(item_index)
					end
					if	assemble_image.game_type == _T("swap every") then
						_owner.RemoveWidget(assemble_image.images.array[item_index].widget)
						table.remove(assemble_image.images.array, item_index)
						item_index = item_index - 1
					end
				else
					end_game = false
				end
			end
			item_index = item_index + 1
		end
		if	end_game then
			_owner.SetGameResult(1)
			_owner.OnEndGame()
		end
	end
end

function assemble_image.CoordsToIndex(_x, _y)
	local x = math.floor(_x / assemble_image.rectangle_size.x) + 1
	local y = math.floor(_y / assemble_image.rectangle_size.y) + 1
	for index in pairs(assemble_image.images.array) do
		if	assemble_image.images.array[index] then
			if	assemble_image.images.array[index].current_place.x == x and
				assemble_image.images.array[index].current_place.y == y then
				return index
			end
		end
	end
	return 0
end

function assemble_image.CanMove(_index)
	if	assemble_image.images.array[_index] then
		if	assemble_image.game_type == _T("swap every") then
			if	assemble_image.images.array[_index].place.x == assemble_image.images.array[_index].current_place.x and
				assemble_image.images.array[_index].place.y == assemble_image.images.array[_index].current_place.y then
				return false
			end
		end
	end
	return true
end

function assemble_image.MoveTo(_index, _x, _y, _speed)
	if	assemble_image.images.array[_index] and assemble_image.images.array[_index].widget then 
		if	_speed == 0 then
			assemble_image.images.array[_index].widget.SetOffset(assemble_image.rectangle_size.x * (_x - 1), assemble_image.rectangle_size.y * (_y - 1))
		else
			assemble_image.add_moving_effect(assemble_image.images.array[_index], {x=_x, y=_y})			
		end
		assemble_image.images.array[_index].current_place = {}
		assemble_image.images.array[_index].current_place.x = _x
		assemble_image.images.array[_index].current_place.y = _y
	end
end

function assemble_image.SwapObjects(_index1, _index2, _speed)
	if	assemble_image.images.array[_index1] and assemble_image.images.array[_index2] then
		local x1 = assemble_image.images.array[_index1].current_place.x
		local y1 = assemble_image.images.array[_index1].current_place.y
		local x2 = assemble_image.images.array[_index2].current_place.x
		local y2 = assemble_image.images.array[_index2].current_place.y
		assemble_image.MoveTo(_index1, x2, y2, _speed)
		assemble_image.MoveTo(_index2, x1, y1, _speed)
	end
end

function assemble_image.SetColor(_index, _color)
	if	assemble_image.images.array[_index].widget then
		assemble_image.images.array[_index].widget.SetColor(_color)
	end		
end

function assemble_image.UpdateColor(_index)
	if	assemble_image.images.array[_index].widget then
		local color = nil
		if 	assemble_image.images.array[_index].place.x == assemble_image.images.array[_index].current_place.x and
			assemble_image.images.array[_index].place.y == assemble_image.images.array[_index].current_place.y then
				color = assemble_image.hide_color
		else
				color = assemble_image.standart_color
		end
		assemble_image.images.array[_index].widget.SetColor(color)
	end		
end

function assemble_image.Activate(_owner, _index)
	if	assemble_image.images.array[_index] == nil or assemble_image.CanMove(_index) == false then
		return 
	end
	sound(assemble_image.params.sound_select)
	if	assemble_image.active == 0 then
		assemble_image.active = _index
		assemble_image.SetColor(_index, assemble_image.active_color)
	else
		if	assemble_image.active ~= _index then
		
			local swap = true
			if	assemble_image.game_type == _T("swap only neighbourhood") then
				if	math.abs(assemble_image.images.array[_index].current_place.x - assemble_image.images.array[assemble_image.active].current_place.x) + 
					math.abs(assemble_image.images.array[_index].current_place.y - assemble_image.images.array[assemble_image.active].current_place.y) > 1 then
					swap = false
				end
			end
			
			if	swap then
				assemble_image.SwapObjects(_index, assemble_image.active, assemble_image.speed)
				assemble_image.UpdateColor(_index)
				assemble_image.UpdateColor(assemble_image.active)
				assemble_image.active = 0
			end
		else
			assemble_image.UpdateColor(assemble_image.active)
			assemble_image.active = 0
		end
	end	
end

function assemble_image.OnMouseDown(_owner, _pos, _button, _state, _broadcast)
	local index = assemble_image.CoordsToIndex(_pos.X, _pos.Y)
	if	index ~= 0 then
		assemble_image.Activate(_owner, index)
		return true
	end
	return false
end

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

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

function assemble_image.Load(_owner, _data)
	sminigames.SetStandartScriptName(_owner, assemble_image)
	math.randomseed(os.time())
    _data.image = __cast(_owner.GetWidget(_T("image"), true), sf.gui.CImageWidget).GetImage()
	assemble_image.hide_color = _data.colors.hide
	
	assemble_image.active_color = _data.colors.active
	assemble_image.standart_color = _data.colors.standart
	
	assemble_image.game_type = _data.game_type
	assemble_image.active = 0
	
	-- Размер виджета с игрой равен размеру рисунка!!!
	_owner.AddFlags(sf.gui.CBaseWidget.FlagClipDraw)
    local size = _owner.GetPreferredSize()
	
	assemble_image.rectangle_count = _data.size
	assemble_image.speed = _data.speed
	
	assemble_image.size = {} 
	assemble_image.size.x = size.X
	assemble_image.size.y = size.Y

	assemble_image.rectangle_size = {} 
	assemble_image.rectangle_size.x = math.floor(assemble_image.size.x / assemble_image.rectangle_count.x)
	assemble_image.rectangle_size.y = math.floor(assemble_image.size.y / assemble_image.rectangle_count.y)
	
	assemble_image.images = {} 
	assemble_image.images.array = {} 
	for i = 1, assemble_image.rectangle_count.x do
		for j = 1, assemble_image.rectangle_count.y do
			local image_index = #assemble_image.images.array + 1
			assemble_image.images.array[image_index] = {}
			local image_owner = sf.gui.CImageWidget(_data.image, _T(tostring(i)..tostring(j)), 0, 0)
			image_owner.GetImage().SetSourceRect(sf.misc.IntRect(assemble_image.rectangle_size.x * (i - 1), assemble_image.rectangle_size.y * (j - 1), assemble_image.rectangle_size.x, assemble_image.rectangle_size.y))
			image_owner.SetSize(assemble_image.rectangle_size.x, assemble_image.rectangle_size.y)
			local image_owner_ptr = sf.gui.CImageWidgetPtrT(image_owner)
			_owner.AddWidget(image_owner_ptr)
			
			assemble_image.images.array[image_index].widget = image_owner_ptr
			assemble_image.images.array[image_index].place = {}
			assemble_image.images.array[image_index].place.x = i
			assemble_image.images.array[image_index].place.y = j
			assemble_image.MoveTo(image_index, i, j, 0)
            assemble_image.SetColor(image_index, _data.colors.standart)
		end
	end
	for index in pairs(assemble_image.images.array) do
		if	assemble_image.images.array[index] and #assemble_image.images.array > 1 then
			while true do
				t = math.random(#assemble_image.images.array) 
				if	assemble_image.images.array[t] then
					if	(assemble_image.images.array[t].place.x ~= assemble_image.images.array[index].current_place.x or assemble_image.images.array[t].place.y ~= assemble_image.images.array[index].current_place.y) and
						(assemble_image.images.array[index].place.x ~= assemble_image.images.array[t].current_place.x or assemble_image.images.array[index].place.y ~= assemble_image.images.array[t].current_place.y) then
						assemble_image.SwapObjects(index, t, 0)
						break
					end
				end
			end
		end
	end
	_owner.SetSize(size.X, size.Y)
end

function assemble_image.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.params.highlight_effect.time
			local cl_min = assemble_image.params.highlight_effect.color.min
			local cl_max = assemble_image.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.FlagHidden)
				_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.params.highlight_effect.color.min)
	
	return effect
end

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

function assemble_image.CMovingEffect(_object, _from, _to, _time_create)
	
	local from, to = sf.misc.FloatVector(assemble_image.rectangle_size.x * (_from.x - 1), assemble_image.rectangle_size.y * (_from.y - 1)),
		sf.misc.FloatVector(assemble_image.rectangle_size.x * (_to.x - 1), assemble_image.rectangle_size.y * (_to.y - 1))
	
	return
	{
		object = _object,
		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.params.moving_effect.speed
			local k = (_time - _self.time_create) * speed / _self.dist
			
			if _self.object.widget then
				if k >= 1.0 then	
					_self.object.widget.SetOffset(_self.to.X, _self.to.Y)
					_self.is_dead = true	
					if _self.object.place.x == _self.to_cell.x and _self.object.place.y == _self.to_cell.y then
						sound(assemble_image.params.sound_put)
						assemble_image.add_highlight_effect(_self.object.widget)
					end
				else
					local pos = _self.from + (_self.to - _self.from) * k
					_self.object.widget.SetOffset(pos.X, pos.Y)
				end
			end
		end
	}	
end

function assemble_image.add_moving_effect(_object, _to)
	local effect = assemble_image.CMovingEffect(_object, _object.current_place, _to, assemble_image.timer.Get().GetTime())
	table.insert(assemble_image.effects, effect)
end

function assemble_image.Init(_owner)
	local data = {}
	data.colors = {}
	data.colors.hide = assemble_image.params.color_hide
	data.colors.active = assemble_image.params.color_active
	data.colors.standart = assemble_image.params.color_standart
	
	data.size = {}
	data.size.x = assemble_image.params.size.X
	data.size.y = assemble_image.params.size.Y
	
	data.speed = assemble_image.params.speed_moving
	
	data.game_type = _T("swap only neighbourhood")
	
	assemble_image.Load(_owner, data)
	
	assemble_image.timer = sf.core.CTimerWrapper(sf.core.g_Application.GetTimeManager().AttachTimer(_T(""), nil))
	assemble_image.highlight_image = __cast(_owner.GetWidget(_T("highlight"), true), sf.gui.CImageWidget)	
	assemble_image.highlight_image.AddFlags(sf.gui.CWidget.FlagHidden)
	
	assemble_image.effects = {}
	
	assemble_image.resolved = false
end
