assemble_image_pieces = {}

assemble_image_pieces.params = 
{
	init_pos = 
	{
		-- 1		
		sf.misc.FloatVector(0.0, 0.0),
		-- 2
		sf.misc.FloatVector(0.0, 0.0),
		-- è ò.ä.
	},
	
	target_pos = 
	{
		-- 1		
		sf.misc.FloatVector(0.0, 0.0),
		-- 2
		sf.misc.FloatVector(0.0, 0.0),
		-- è ò.ä.
	},
	
	colors = 
	{
		normal = sf.graphics.Color(255, 255, 255, 255),
		selected = sf.graphics.Color(255, 255, 255, 255)
	},
	
	highlight_effect = 
	{
		color =
		{
			min = sf.graphics.Color(255, 255, 255, 255),
			max = sf.graphics.Color(255, 100, 200, 100)
		},
		
		time = 700
	},
	
	moving_effect = 
	{
		speed = 0.2
	},
	
	inaccuracy = 15.0,
	
	sound_take = "take_put_item",
	sound_right_put = "put_part",
	sound_error_put = "put_part"
}
 
function assemble_image_pieces.normalize_pos(_owner, _widget)
	local pos = sf.misc.FloatVector(_widget.GetOffset())
	pos.X = misc.Clamp(pos.X, 0.0, _owner.GetSize().X - _widget.GetSize().X)
	pos.Y = misc.Clamp(pos.Y, 0.0, _owner.GetSize().Y - _widget.GetSize().Y)
	_widget.SetOffset(pos.X, pos.Y)
end

function assemble_image_pieces.CheckEnd(_owner)
	local resolved = true
	for _, p in ipairs(assemble_image_pieces.pieces) do
		if p.resolved == false then 
			resolved = false
			break
		end
	end
	
	if resolved == true then
		--assemble_image_pieces.whole_image.RemFlags(sf.gui.CWidget.FlagHidden)
		--assemble_image_pieces.whole_image.SetLayer(assemble_image_pieces.layer + 1)
		if assemble_image_pieces.widgets then
			for _, w in pairs(assemble_image_pieces.widgets) do
				sminigames.ImageDropBuffer(w.GetImage())
			end
			assemble_image_pieces.widgets = nil
		end
		_owner.SetGameResult(1)
		_owner.OnEndGame()
	end
end
 
function assemble_image_pieces.OnMouseDown(_owner, _pos, _button, _state, _broadcast)
	if assemble_image_pieces.drag_info then		
		local piece = assemble_image_pieces.drag_info.piece
		local dist = sf.misc.CalculateFloatVectorModule(piece.target - piece.widget.GetOffset())
		if dist <= assemble_image_pieces.params.inaccuracy then
			assemble_image_pieces.add_moving_effect(piece, piece.target)
		else
			sound(assemble_image_pieces.params.sound_error_put)
		end
		assemble_image_pieces.drag_info.piece.widget.SetColor(assemble_image_pieces.params.colors.normal)
		assemble_image_pieces.drag_info = nil
		return true
	end
	
	for _, p in ipairs(assemble_image_pieces.pieces) do
		if p.resolved == false and p.widget.GetPoly().IsContains(_pos.X, _pos.Y) == true then		
			local piece_pos = p.widget.GetOffset()
			local coords = _pos - piece_pos			
			if sminigames.IsVisiblePoint(p.widget.GetImage(), coords.X, coords.Y) == true then
				assemble_image_pieces.drag_info = 
				{
					piece = p,
					last_piece_pos = sf.misc.FloatVector(piece_pos.X, piece_pos.Y),
					last_mouse_pos = sf.misc.FloatVector(_pos.X, _pos.Y)
				}				
				assemble_image_pieces.select_piece(assemble_image_pieces.drag_info.piece)
				sound(assemble_image_pieces.params.sound_take)
				return true
			end
		end
	end
	return false
end

function assemble_image_pieces.OnMouseMove(_owner, _pos, _state, _broadcast)
	if assemble_image_pieces.drag_info then
		local delta = _pos - assemble_image_pieces.drag_info.last_mouse_pos
		local pos = assemble_image_pieces.drag_info.last_piece_pos + delta
		assemble_image_pieces.drag_info.piece.widget.SetOffset(pos.X, pos.Y)
		assemble_image_pieces.normalize_pos(_owner, assemble_image_pieces.drag_info.piece.widget)
		return true
	end
	return false
end

function assemble_image_pieces.OnMouseUp(_owner, _pos, _button, _state, _broadcast)
	if assemble_image_pieces.drag_info then
		local delta = _pos - assemble_image_pieces.drag_info.last_mouse_pos
		if sf.misc.CalculateFloatVectorModule(delta) >= 0.001 then
			local piece = assemble_image_pieces.drag_info.piece
			local dist = sf.misc.CalculateFloatVectorModule(piece.target - piece.widget.GetOffset())
			if dist <= assemble_image_pieces.params.inaccuracy then
				assemble_image_pieces.add_moving_effect(piece, piece.target)
			else
				sound(assemble_image_pieces.params.sound_error_put)
			end
			assemble_image_pieces.drag_info.piece.widget.SetColor(assemble_image_pieces.params.colors.normal)
			assemble_image_pieces.drag_info = nil
		end
		return true
	end
	return false
end 

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

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

function assemble_image_pieces.CHighlightEffect(_owner, _image, _time_create)
	
	local effect = 
	{
		owner = _owner,
		time_create = _time_create,
		is_dead = false,
		
		Update = function(_self, _time)			
			local tm = assemble_image_pieces.params.highlight_effect.time
			local cl_min = assemble_image_pieces.params.highlight_effect.color.min
			local cl_max = assemble_image_pieces.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.owner.SetColor(color)
			
			_self.is_dead = (t >= tm)
		end
	}
	
	effect.owner.SetColor(assemble_image_pieces.params.highlight_effect.color.min)
	
	return effect
end

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

function assemble_image_pieces.CMovingEffect(_piece, _from, _to, _time_create)
	
	return
	{
		piece = _piece,
		from = sf.misc.FloatVector(_from.X, _from.Y),
		to = sf.misc.FloatVector(_to.X, _to.Y),
		dist = sf.misc.CalculateFloatVectorModule(_to - _from),
		time_create = _time_create,	
		is_dead = false,
		
		Update = function(_self, _time)			
			local speed = assemble_image_pieces.params.moving_effect.speed
			local k = (_time - _self.time_create) * speed / _self.dist
			
			if _self.piece.widget then
				if k >= 1.0 then	
					_self.piece.widget.SetOffset(_self.to.X, _self.to.Y)
					_self.is_dead = true	
					_self.piece.resolved = true
					_self.piece.widget.SetLayer(assemble_image_pieces.default_layer-1)
					assemble_image_pieces.add_highlight_effect(_self.piece.widget)
					sound(assemble_image_pieces.params.sound_right_put)
				else
					local pos = _self.from + (_self.to - _self.from) * k
					_self.piece.widget.SetOffset(pos.X, pos.Y)
				end
			end
		end
	}	
end

function assemble_image_pieces.add_moving_effect(_piece, _to)
	local effect = assemble_image_pieces.CMovingEffect(_piece, _piece.widget.GetOffset(), _to, assemble_image_pieces.timer.Get().GetTime())
	table.insert(assemble_image_pieces.effects, effect)
end

function assemble_image_pieces.select_piece(_p)	
	for i = 1, #assemble_image_pieces.pieces do
		if _p == assemble_image_pieces.pieces[i] and i ~= 1 then
			table.remove(assemble_image_pieces.pieces, i)
			table.insert(assemble_image_pieces.pieces, 1, _p)
			assemble_image_pieces.layer = assemble_image_pieces.layer + 1
			_p.widget.SetLayer(assemble_image_pieces.layer)		
			_p.widget.SetColor(assemble_image_pieces.params.colors.selected)			
			break
		end
	end
end

function assemble_image_pieces.Init(_owner)

	sminigames.SetStandartScriptName(_owner, assemble_image_pieces)
	
	math.randomseed(os.time())	
		
	assemble_image_pieces.default_layer = 3
		
	assemble_image_pieces.pieces = {}
	assemble_image_pieces.widgets = {}
	
	local iterator = _owner.GetWidgets()
    while iterator.IsEnd() == false do
		local image = __cast(iterator.Get(), sf.gui.CImageWidget)
		if image then
			if string.find(iterator.Get().GetId().c_str(), "piece") == 1 then
				local piece = 
				{
					widget = image,
					target = sf.misc.FloatVector(image.GetOffset().X, image.GetOffset().Y),
					resolved = false
				}
				image.SetLayer(assemble_image_pieces.default_layer)
				table.insert(assemble_image_pieces.pieces, piece)
				table.insert(assemble_image_pieces.widgets, image)
			end
		end
        iterator.Next()
    end
	
	local count = #assemble_image_pieces.pieces
	assert(count == #assemble_image_pieces.params.init_pos and count == #assemble_image_pieces.params.target_pos)
	for i=1, count do
		local piece = assemble_image_pieces.pieces[i]
		local init_pos = assemble_image_pieces.params.init_pos[count-i+1]
		local target_pos = assemble_image_pieces.params.target_pos[count-i+1]
		piece.widget.SetOffset(init_pos.X, init_pos.Y)
		piece.target.X = target_pos.X
		piece.target.Y = target_pos.Y
	end

	assemble_image_pieces.back_image = __cast(_owner.GetWidget(_T("back"), true), sf.gui.CImageWidget)
	assert(assemble_image_pieces.back_image)
	
--	assemble_image_pieces.whole_image = __cast(_owner.GetWidget(_T("whole"), true), sf.gui.CImageWidget)
--	assert(assemble_image_pieces.whole_image)
--	assemble_image_pieces.whole_image.AddFlags(sf.gui.CWidget.FlagHidden)
	
	assemble_image_pieces.highlight_image = __cast(_owner.GetWidget(_T("highlight"), true), sf.gui.CImageWidget)
	assert(assemble_image_pieces.highlight_image)
	assemble_image_pieces.highlight_image.AddFlags(sf.gui.CWidget.FlagHidden)
	
	assemble_image_pieces.timer = __create_timer("", "qe_level")
	
	assemble_image_pieces.effects = {}
	
	local size = assemble_image_pieces.back_image.GetSize()
	_owner.SetSize(size.X, size.Y)
	
	assemble_image_pieces.layer = assemble_image_pieces.default_layer
end
