set_clock_time = {}

set_clock_time.params = 
{
	center = sf.misc.FloatVector(160.0, 160.0),
	init_hours = 10.0,
	init_minutes = 30.0,
	target_hours = 17.0,
	target_minutes = 5.0,
	inaccuracy = 4,	-- погрешность (в минимальных делениях)
	
	sound_step_angle = math.pi / 10.0,
	sound_step_time = 100, -- не больше одного раза в заданное время
	sound_rotation = "mini_game_set_clock_time_rotate_01"
}

function set_clock_time.normal_angle(_a)
	local a = math.mod(math.abs(_a) + 2.0 * math.pi, 2.0 * math.pi)
	if _a < 0 then a = 2.0 * math.pi - a end
	return a
end

function set_clock_time.angles_is_equal(_a1, _a2, _e)
	return math.abs(_a1 - _a2) < _e
end

function set_clock_time.hours2rad(_h)
	return set_clock_time.normal_angle(4.0 * math.pi * _h / 24.0)
end

function set_clock_time.minutes2rad(_m)
	return 2.0 * math.pi * _m / 60.0
end

function set_clock_time.CheckEnd(_owner)
	local target_hours_rad = set_clock_time.hours2rad(set_clock_time.params.target_hours + set_clock_time.params.target_minutes / 60.0)
	local target_minutes_rad = set_clock_time.minutes2rad(set_clock_time.params.target_minutes)
	local inaccuracy = set_clock_time.minutes2rad(set_clock_time.params.inaccuracy)
	if	set_clock_time.angles_is_equal(target_hours_rad, set_clock_time.pointers[set_clock_time.pointer_hours].angle, inaccuracy) and
		set_clock_time.angles_is_equal(target_minutes_rad, set_clock_time.pointers[set_clock_time.pointer_minutes].angle, inaccuracy) then
		set_clock_time.resolved = true
	end
end
				
function set_clock_time.EndGame(_owner)
	set_clock_time.pointers = {}
	set_clock_time.timer = nil
	set_clock_time.drag_info = {}
	_owner.SetGameResult(1)
	_owner.OnEndGame()
end
				
function set_clock_time.OnMouseDown(_owner, _pos, _button, _state, _broadcast)
	
	set_clock_time.drag_info.pointer = nil
	set_clock_time.drag_info.last_mouse_pos = sf.misc.FloatVector(_pos)
	
	if set_clock_time.pointer_hours.GetPoly().IsContains(_pos.X, _pos.Y) then	
		set_clock_time.drag_info.pointer = set_clock_time.pointer_hours
		set_clock_time.drag_info.last_angle = set_clock_time.pointers[set_clock_time.pointer_hours].angle
		return true
	elseif set_clock_time.pointer_minutes.GetPoly().IsContains(_pos.X, _pos.Y) then
		set_clock_time.drag_info.pointer = set_clock_time.pointer_minutes
		set_clock_time.drag_info.last_angle = set_clock_time.pointers[set_clock_time.pointer_minutes].angle
		return true
	end
	
	return false
end

function set_clock_time.update_pointer_rotation(_pointer)
	local pointer_center = set_clock_time.pointers[_pointer].center
	local angle = set_clock_time.pointers[_pointer].angle
	local matrix = sf.misc.MatrixTranslation(-pointer_center.X, -pointer_center.Y)
	matrix = matrix * sf.misc.MatrixRotation(angle, 0.0, 0.0)
	matrix = matrix * sf.misc.MatrixTranslation(pointer_center.X, pointer_center.Y)
	_pointer.SetRotation(matrix)	
end

function set_clock_time.OnMouseMove(_owner, _pos, _state, _broadcast)

	if set_clock_time.drag_info.pointer then
		
		local vec1 = sf.misc.FloatVector(set_clock_time.drag_info.last_mouse_pos - set_clock_time.center)
		local vec2 = sf.misc.FloatVector(_pos - set_clock_time.center)		

		if sf.misc.CalculateFloatVectorModule(vec1) < 0.001 or sf.misc.CalculateFloatVectorModule(vec2) < 0.001 then
			return false
		end

		vec2 = vec2 * (sf.misc.CalculateFloatVectorModule(vec1) / sf.misc.CalculateFloatVectorModule(vec2))

		local a = sf.misc.CalculateFloatVectorModule(vec1)
		local b = sf.misc.CalculateFloatVectorModule(vec2)
		local c = sf.misc.CalculateFloatVectorModule(vec2-vec1)

		local angle = math.acos(misc.Clamp((a*a+b*b-c*c)/(2*a*b), -1.0, 1.0))

		local p1 = vec2 * sf.misc.MatrixRotation(angle, 0.0, 0.0)
		local p2 = vec2 * sf.misc.MatrixRotation(-angle, 0.0, 0.0)

		if 	sf.misc.CalculateFloatVectorModule(vec1-p1) < 
			sf.misc.CalculateFloatVectorModule(vec1-p2) then
			angle = angle * -1.0
		end
		
		angle = set_clock_time.normal_angle(set_clock_time.drag_info.last_angle + angle)
		
		set_clock_time.pointers[set_clock_time.drag_info.pointer].angle = angle
		set_clock_time.update_pointer_rotation(set_clock_time.drag_info.pointer)
		
		local curr_time = set_clock_time.timer.Get().GetTime()
		if (not set_clock_time.sound_id or not sf.core.g_Application.GetAudioManager().IsSound(set_clock_time.sound_id) or 
			math.abs(set_clock_time.sound_angle - angle) >= set_clock_time.params.sound_step_angle) and
			(not set_clock_time.sound_time or (curr_time - set_clock_time.sound_time) >= set_clock_time.params.sound_step_time) then
				set_clock_time.sound_id = 
					sf.core.g_Application.GetAudioManager().Play(set_clock_time.params.sound_rotation, -2, -2, -2, -2, -2)
				set_clock_time.sound_angle = angle
				set_clock_time.sound_time = curr_time
		end
		
		return true
	end

	return false
end

function set_clock_time.OnMouseUp(_owner, _pos, _button, _state, _broadcast)	
	if set_clock_time.drag_info.pointer then
		set_clock_time.drag_info.pointer = nil		
		set_clock_time.CheckEnd(_owner)
		if set_clock_time.resolved then
			set_clock_time.EndGame(_owner)
		end
		return true
	end
	
	return false
end


function set_clock_time.OnUpdate(_owner)
end

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

function set_clock_time.Init(_owner)
	sminigames.SetStandartScriptName(_owner, set_clock_time)
	
	set_clock_time.clock_face = __cast(_owner.GetWidget("clock_face", false).get(), sf.gui.CImageWidget)
	assert(set_clock_time.clock_face)
	
	set_clock_time.pointer_hours = __cast(_owner.GetWidget("pointer_hours", false).get(), sf.gui.CImageWidget)
	assert(set_clock_time.pointer_hours)
	
	set_clock_time.pointer_minutes = __cast(_owner.GetWidget("pointer_minutes", false).get(), sf.gui.CImageWidget)
	assert(set_clock_time.pointer_minutes)
	
	set_clock_time.timer = sf.core.CTimerWrapper(sf.core.g_Application.GetTimeManager().AttachTimer(_T(""), nil))

	set_clock_time.center = set_clock_time.params.center
	
	set_clock_time.pointers = {}
	
	set_clock_time.pointers[set_clock_time.pointer_hours] = {}
	set_clock_time.pointers[set_clock_time.pointer_hours].center = set_clock_time.center - set_clock_time.pointer_hours.GetOffset()
	set_clock_time.pointers[set_clock_time.pointer_hours].angle = set_clock_time.hours2rad(set_clock_time.params.init_hours)
	set_clock_time.update_pointer_rotation(set_clock_time.pointer_hours)
	
	set_clock_time.pointers[set_clock_time.pointer_minutes] = {}
	set_clock_time.pointers[set_clock_time.pointer_minutes].center = set_clock_time.center - set_clock_time.pointer_minutes.GetOffset()
	set_clock_time.pointers[set_clock_time.pointer_minutes].angle = set_clock_time.minutes2rad(set_clock_time.params.init_minutes)
	set_clock_time.update_pointer_rotation(set_clock_time.pointer_minutes)
		
	set_clock_time.resolved = false
	
	set_clock_time.drag_info = {}
end
