--модуль для луавиджета отрисовывающего разнообразные эффекте в верхних слоях отрисовки игры( полеты гемов, очков, бонусов, файерболов)
effects_widget = {}

__inherite(effects_widget, null_lua_widget_handler())

function effects_widget.__CreateInstance()
    return "effects_widget"
end

effects_widget._mix_fly_speed = 800
effects_widget._mix_start_pos = sf.misc.FloatVector(50, 415)
effects_widget._mix_end_pos = sf.misc.FloatVector(650, 390)

effects_widget._gem_size = sf.misc.FloatVector(48, 48) -- размер изображения с гемом
effects_widget._def_time_bonus_fly_speed = 300 -- скорость поумолчанию для полета временного бонуса с поля
effects_widget._def_hint_bonus_fly_speed = 300 -- скорость поумолчанию для полета бонуса-подсказки с поля


effects_widget._time_target_pos = sf.misc.FloatVector(130, 365) -- позиция куда летит временной бонус
effects_widget._def_new_bonus_fly_pos = sf.misc.FloatVector(100, 600) -- позиция откуда добавляется бонус на поле
effects_widget._def_new_bonus_fly_time = 600 -- время добавления нового бонуса

effects_widget._after_bonus_add_delay = 100 -- время после добавления бонуса, которое фишка еще залочена

function effects_widget.Load(_this, _info, _templates)

	local time_bonus_info = g_App.GetSettings().GetChild("Constants", false).GetChildRef("fly_time_effect", false)
	if time_bonus_info then
		effects_widget._def_time_bonus_fly_speed = tonumber(time_bonus_info.GetValue("fly_speed").c_str()) or effects_widget._def_time_bonus_fly_speed
	end

	local hint_bonus_info = g_App.GetSettings().GetChild("Constants", false).GetChildRef("fly_hint_effect", false)
	if hint_bonus_info then
		effects_widget._def_hint_bonus_fly_speed = tonumber(hint_bonus_info.GetValue("fly_speed").c_str()) or effects_widget._def_hint_bonus_fly_speed
	end

	effects_widget.visual_effects = visual_effects.CreateEffectsList()

	effects_widget.effects_timer = sf.core.CTimerWrapper(sf.core.g_Application.GetTimeManager().GetTimer("game_timer").AttachTimer(""))

	effects_widget.effects_list = {}

	-- таблица с изображениями камней, для эффекат добавления камня
	effects_widget._gems_map = 
	{
		[s11.CFieldCap.CapTypeGreen] = sf.graphics.CImage("screens_game_gems_gem_1"),
		[s11.CFieldCap.CapTypeYellow] = sf.graphics.CImage("screens_game_gems_gem_2"),
		[s11.CFieldCap.CapTypeRed] = sf.graphics.CImage("screens_game_gems_gem_3"),
		[s11.CFieldCap.CapTypeBlue] = sf.graphics.CImage("screens_game_gems_gem_4"),
		[s11.CFieldCap.CapTypeOrange] = sf.graphics.CImage("screens_game_gems_gem_5"),
		[s11.CFieldCap.CapTypeWhite] = sf.graphics.CImage("screens_game_gems_gem_6"),
		[s11.CFieldCap.CapTypeViolet] = sf.graphics.CImage("screens_game_gems_gem_7")
	}
	
end

function effects_widget.DoUpdate(_this)
	
	effects_widget.visual_effects:Update()
	
	local size = #(effects_widget.effects_list)
	if size ~= 0 then
		local current_time = effects_widget.effects_timer.Get().GetTime()
		local i = 1
		while i <= size do
			effects_widget.effects_list[i]:Update(current_time)
			if effects_widget.effects_list[i]:IsDead() then
				if not effects_widget.effects_list[i].is_visual then
					game_window.game_field.DecLuaEffectsCount()
				end
				table.remove(effects_widget.effects_list, i)
				
				size = size - 1
				i = i - 1
			end
			i = i + 1
		end
	end
	return false
end

function effects_widget.DoDraw(_this, _renderer)
	effects_widget.visual_effects:PreDraw(_renderer)

	local size = #(effects_widget.effects_list)
	if size ~= 0 then
		for i = 1, size do
			effects_widget.effects_list[i]:Draw(_renderer)
		end
	end
	effects_widget.visual_effects:PostDraw(_renderer)
    s11.effects.FlushShaderSurface(_renderer)

    return false
end

function effects_widget.OnMouseMove(_this, _pos, _state, _broadcast)
    return false
end

function effects_widget.OnMouseUp(_this, _pos, _button, _state, _broadcast)
    return false
end

function effects_widget.add_visual_effect(_effect)
	_effect.is_visual = true
	table.insert(effects_widget.effects_list, _effect)
end

function effects_widget.add_effect(_effect)
	game_window.game_field.AddLuaEffectsCount()
	table.insert(effects_widget.effects_list, _effect)
end

function effects_widget.OnMouseDown(_this, _pos, _button, _state, _broadcast)
    return false
end

function effects_widget.OnDoubleClick(_this, _pos, _state, _broadcast)
    return true
end

-- функция для расчета позиции летящего по прямой объекта
function effects_widget.SimpleFlyFunction( _start_pos, _end_pos, _t)
    return _start_pos + (_end_pos - _start_pos)*_t
end

--вызывается с плюсов для инициализации полета эффекта бонусаподсказчик к месту его отображения
-- _time_count - количество добавляемого времени
-- _pos - позиция откуда летит время(может с поля может от тотема лететь)
function effects_widget.AddMovesHint(_time_count, _pos)
    local new_child_effect = 
    {
        Init = function(_self, _speed, _start_pos, _end_pos, _time )
			_self._time = _time
			_self._start_pos = _start_pos
			_self._end_pos = _end_pos
            _self._start_time = effects_widget.effects_timer.Get().GetTime()
            _self._total_time = CalcTimeForVector(_self._start_pos, _self._end_pos, _speed)
			_self._particle_effect = effects_widget.visual_effects:CreateEffect("HintFromField", _start_pos)            
        end,

        Draw = function(_self, _renderer)
        end,

        Update = function(_self, _time)
            local koef = (_time - _self._start_time)/_self._total_time
			if koef > 1 then
				koef = 1
			end
			_self._particle_effect:SetPos(effects_widget.SimpleFlyFunction(_self._start_pos, _self._end_pos, koef))
            if koef >= 1 then
                _self:InstantApply()
            end
        end,

        InstantApply = function(_self)
            if not _self._is_dead then
				_self._particle_effect:Kill(false)
				effects_widget.visual_effects:CreateInstantEffect("HintHit", _self._end_pos)
				game_window.game_field.SetHintResumeTime(0)
				hint_button.StartBonusHintTimer()
				game_window.game_field.SetHintBonusTime(game_window.game_field.GetHintBonusTime() + _self._time)
			end

            _self._is_dead = true
        end,
		
		IsDead = function(_self)
			return _self._is_dead
		end,
		
    }
	new_child_effect:Init(effects_widget._def_hint_bonus_fly_speed, 
	                      _pos, 
						  game_window.GetHintFlyTarget(),  
						  _time_count)
	effects_widget.add_visual_effect(new_child_effect)
end

--вызывается для инициализации полета эффекта доавляения времени к часам
function effects_widget.AddCapsMix()
    local new_child_effect = 
    {
        Init = function(_self, _fly_speed, _start_pos, _end_pos)
			_self._time = _time
			_self._start_pos = _start_pos
			_self._end_pos = _end_pos
            _self._start_time = effects_widget.effects_timer.Get().GetTime()
            _self._total_time = CalcTimeForVector(_self._start_pos, _self._end_pos, _fly_speed)
			_self._particle_effect = effects_widget.visual_effects:CreateEffect("MixFly", _start_pos)       
			effects_widget.visual_effects:CreateInstantEffect("MixStart", _self._start_pos)			
        end,

        Draw = function(_self, _renderer)
        end,

        Update = function(_self, _time)
            local koef = (_time - _self._start_time)/_self._total_time
			if koef > 1 then
				koef = 1
			end
			_self._particle_effect:SetPos(effects_widget.SimpleFlyFunction( _self._start_pos, _self._end_pos, koef))
            if koef >= 1 then
                _self:InstantApply()
            end
        end,

        InstantApply = function(_self)
            if not _self._is_dead then
				_self._particle_effect:Kill(false)
				game_window.game_field.AddCompositeEffect(_self._end_pos, "MixHit")
				game_window.game_field.PlayClipOnField("shuffle01")
				game_window.game_field.MixCaps()
			end

            _self._is_dead = true
        end,

		IsDead = function(_self)
			return _self._is_dead
		end,
		
    }
	new_child_effect:Init(effects_widget._mix_fly_speed, 
                          effects_widget._mix_start_pos, 
                          effects_widget._mix_end_pos)
	effects_widget.add_effect(new_child_effect)
end

--вызывается для инициализации полета эффекта доавляения времени к часам
-- _time_count - количество отнимаемых милисекунд
-- _pos - позиция откуда будут лететь очки
-- _fly_speed - время полета эффекта
function effects_widget.AddTimeBonus(_time_count, _pos, _fly_speed)
    local new_child_effect = 
    {
        Init = function(_self, _fly_speed, _start_pos, _end_pos, _time )
			_self._time = _time
			_self._start_pos = _start_pos
			_self._end_pos = _end_pos
            _self._start_time = effects_widget.effects_timer.Get().GetTime()
            _self._total_time = CalcTimeForVector(_self._start_pos, _self._end_pos, _fly_speed)
			_self._particle_effect = effects_widget.visual_effects:CreateEffect("TimeFromField", _start_pos)            
        end,

        Draw = function(_self, _renderer)
        end,

        Update = function(_self, _time)
            local koef = (_time - _self._start_time)/_self._total_time
			if koef > 1 then
				koef = 1
			end
			_self._particle_effect:SetPos(effects_widget.SimpleFlyFunction( _self._start_pos, _self._end_pos, koef))
            if koef >= 1 then
                _self:InstantApply()
            end
        end,

        InstantApply = function(_self)
            if not _self._is_dead then
				local new_game_time = game_window.game_field.GetGameTime() - _self._time
				if new_game_time < 0 then
					new_game_time = 0
				end
				_self._particle_effect:Kill(false)
				effects_widget.visual_effects:CreateInstantEffect("TimeHit", _self._end_pos)
				game_window.game_field.SetGameTime(new_game_time)
				-- при добавлении времени аватар радуется
				avatar_widget.ChangeMood("on_add_time")
			end

            _self._is_dead = true
        end,

		IsDead = function(_self)
			return _self._is_dead
		end,
		
    }
	new_child_effect:Init(_fly_speed or effects_widget._def_time_bonus_fly_speed, 
                          _pos, 
                          effects_widget._time_target_pos, 
                          _time_count)
	effects_widget.add_visual_effect(new_child_effect)
end

-- добавление эффекта летящего с поля гема
-- вызывается с плюсов для инициализации полета гема
-- _color - цвет добавляемого гема
-- _pos - позиция в которую прилетает гем
function effects_widget.AddFlyGem(_color, _pos)
    local new_child_effect = 
    {
        Init = function(_self, _total_time, _start_pos, _end_pos, _color )
			_self._gem_image = effects_widget._gems_map[_color]
			_self._color = _color
			_self._start_pos = _start_pos -- effects_widget._gem_size/2
			_self._end_pos = _end_pos -- effects_widget._gem_size/2
            _self._start_time = effects_widget.effects_timer.Get().GetTime()
            _self._total_time = _total_time
			_self._particle_effect = effects_widget.visual_effects:CreateEffect("GemFly", _start_pos)            
			_self._gem_size_half = effects_widget._gem_size/2
        end,

        Draw = function(_self, _renderer)
			if _self._fly_obj_pos ~= nil then
				_renderer.PushState()
				_renderer.ApplyMatrix( sf.misc.MatrixTranslation(_self._fly_obj_pos.X, _self._fly_obj_pos.Y))
				_self._gem_image.Draw(_renderer)
				_renderer.PopState()
			end
        end,

        Update = function(_self, _time)
            local koef = (_time - _self._start_time)/_self._total_time
			if koef > 1 then
				koef = 1
			end
            _self._fly_obj_pos = effects_widget.SimpleFlyFunction( _self._start_pos, _self._end_pos, koef)
			_self._particle_effect:SetPos(_self._fly_obj_pos + _self._gem_size_half)
            if koef >= 1 then
                _self:InstantApply()
            end
        end,

        InstantApply = function(_self)
            if not _self._is_dead then
				gems_bar_widget.add_gem(_self._color, true)
				_self._particle_effect:Kill(false)
				effects_widget.visual_effects:CreateInstantEffect("GemHit", _self._end_pos+ _self._gem_size_half)
			end

            _self._is_dead = true
        end,
		
		IsDead = function(_self)
			return _self._is_dead
		end,
    }
	new_child_effect:Init(600, 
	                      _pos, 
						  gems_bar_widget.offset + gems_bar_widget.get_next_gem_pos(), 
						  _color)
	-- добавление логического гема в гембар
	gems_bar_widget.add_gem(_color, false)
						  
	effects_widget.add_visual_effect(new_child_effect)
end

-- эффект добавления бонуса на поле 
-- _cell - ячейка на которую добавляем бонус
-- _bonus - бонус для добавления
-- _fly_time - время полета бонуса на поле
-- _start_pos - позиция откуда летит бонус
function effects_widget.AddBonusToCell(_cell, _bonus, _fly_time, _start_pos)
    local new_child_effect = 
    {
        Init = function(_self, _start_pos, _total_time, _cell, _bonus)
			
			_self._bonus = _bonus
			_self._cell = _cell
			_self._cell.AddLock()
			_self._cell_pos = _cell.GetCellPos()
			_self._start_pos = _start_pos
			_self._end_pos = game_helpers.GetFieldPos() + _cell.GetCapPos(true)
            _self._start_time = effects_widget.effects_timer.Get().GetTime()
            _self._total_time = _total_time
			_self._particle_effect = effects_widget.visual_effects:CreateEffect("VioletBonusFly", _start_pos)            
			
			_self._stage = 1
        end,

        Draw = function(_self, _renderer)
        end,

        Update = function(_self, _time)
            local koef = (_time - _self._start_time)/_self._total_time
			if koef > 1 then
				koef = 1
			end
			if _self._stage == 1 then
				_self._fly_obj_pos = effects_widget.SimpleFlyFunction( _self._start_pos, _self._end_pos, koef)
				_self._particle_effect:SetPos(_self._fly_obj_pos)
				if koef >= 1 then
					game_window.game_field.AddBonusToCell(_self._cell, _self._bonus, false, -1)
					_self._particle_effect:Kill(false)
					_self._start_time = _time
					_self._total_time = effects_widget._after_bonus_add_delay
					_self._stage = 2
				end
			else
				if koef >= 1 then
					_self:InstantApply()
				end
			end
        end,

        InstantApply = function(_self)
            if not _self._is_dead then
				_self._cell.DecLock()
			end
            _self._is_dead = true
        end,

		IsDead = function(_self)
			return _self._is_dead
		end,
    }
	new_child_effect:Init(_start_pos or effects_widget._def_new_bonus_fly_pos, 
	                      _fly_time or effects_widget._def_new_bonus_fly_time, 
						  _cell, 
						  _bonus)
	effects_widget.add_effect(new_child_effect)
end

-- эффект добавления бонуса на поле 
-- _cell - ячейка на которую добавляем бонус
-- _bonus - бонус для добавления
function effects_widget.AddBonusToCellByMatch(_cell, _bonus)
    local new_child_effect = 
    {
        Init = function(_self, _start_pos, _total_time, _cell, _bonus)
			
			_self._bonus = _bonus
			_self._cell = _cell
			_self._cell.AddLock()
			_self._cell_pos = _cell.GetCellPos()
			_self._start_pos = _start_pos
			_self._end_pos = game_helpers.GetFieldPos() + _cell.GetCapPos(true)
            _self._end_time = effects_widget.effects_timer.Get().GetTime() + _total_time
			--_self._particle_effect = effects_widget.visual_effects:CreateEffect("VioletBonusFly", _start_pos)  
			game_window.game_field.AddBonusToCell(_self._cell, _self._bonus, true, -1)	
			effects_widget.visual_effects:CreateInstantEffect("BonusAddByMatch", _self._end_pos)			
        end,

        Draw = function(_self, _renderer)
        end,

        Update = function(_self, _time)
            if _time > _self._end_time then
                _self:InstantApply()
            end
        end,

        InstantApply = function(_self)
            if not _self._is_dead then
				_self._cell.DecLock()
			end
            _self._is_dead = true
        end,

		IsDead = function(_self)
			return _self._is_dead
		end,
    }
	new_child_effect:Init(effects_widget._def_new_bonus_fly_pos, 
	                      effects_widget._def_new_bonus_fly_time, 
						  _cell, 
						  _bonus)
	effects_widget.add_effect(new_child_effect)
end
