set_clock_time = {}

set_clock_time.params = 
{
	center = sf.misc.FloatVector(162.0, 121.0),
	init_hours = 0.0,
	init_minutes = 0.0,
	target_hours = 22.0,
	target_minutes = 7.0,
	inaccuracy = 4,	-- погрешность (в минимальных делениях)
	lever_time_reset = 200 -- время, через которое рычажок переходит в начальное состояние при неверно указанном веремени
}

set_clock_time.CLever = function (_state1, _state2)
	return
	{
		states = {{image = _state1}, {image = _state2}},
		
		state = 1,
		
		SetState = function(_self, _state)
			_self.state = _state
			_self:_UpdateImage()
		end,
		
		IsContains = function(_self, _pos)
			return _self.states[_self.state].image.GetPoly().IsContains(_pos.X, _pos.Y)
		end,	
		
		_UpdateImage = function(_self)
			_self.states[_self.state].image.RemFlags(sf.gui.CWidget.FlagHidden)
			_self.states[3-_self.state].image.AddFlags(sf.gui.CWidget.FlagHidden)
		end
	}
end

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.lever = nil
	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
	elseif set_clock_time.lever and set_clock_time.lever:IsContains(_pos) then
		sf.core.g_Application.GetAudioManager().Play(_T("lever"), -2, -2, -2, -2, -2)
		if set_clock_time.resolved == true then
			set_clock_time.EndGame(_owner)
		else
			set_clock_time.lever:SetState(2)
			set_clock_time.lever_change_state_time = set_clock_time.timer.Get().GetTime()		
		end
		
		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
		
		set_clock_time.pointers[set_clock_time.drag_info.pointer].angle = set_clock_time.normal_angle(set_clock_time.drag_info.last_angle + angle)		
		set_clock_time.update_pointer_rotation(set_clock_time.drag_info.pointer)
		
		return true
	elseif set_clock_time.lever and set_clock_time.lever:IsContains(_pos) then		
		sf.gui.g_Cursor.Instance().SetCursor(sf.gui.CCursor.CursorHand)
		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)
		return true
	end
	
	return false
end


function set_clock_time.OnUpdate(_owner)
	if set_clock_time.resolved == false and set_clock_time.lever.state == 2 then
		if (set_clock_time.timer.Get().GetTime() - set_clock_time.lever_change_state_time) >= 
			set_clock_time.params.lever_time_reset then
				set_clock_time.lever:SetState(1)
		end
	end
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.lever1 = __cast(_owner.GetWidget("lever_state1", false).get(), sf.gui.CImageWidget)
	assert(set_clock_time.lever1)
	
	set_clock_time.lever2 = __cast(_owner.GetWidget("lever_state2", false).get(), sf.gui.CImageWidget)
	assert(set_clock_time.lever2)
	
	set_clock_time.lever = set_clock_time.CLever(set_clock_time.lever1, set_clock_time.lever2)
	set_clock_time.lever:SetState(1)
	
	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.lever_change_state_time = 0.0
	set_clock_time.timer = sf.core.CTimerWrapper(sf.core.g_Application.GetTimeManager().AttachTimer(_T(""), nil))
	
	set_clock_time.resolved = false
	
	set_clock_time.drag_info = {}
end
