-- этот модуль реализует создание и загрузку тотемов, организовывает их работу
-- здесь находится очередь цветов, разрушенных мачей, пополнение которой происходит
-- из GameField при разрушении мача игроком, посредством вызова totems_widget.AddColor
-- обработка очереди происходит поэлементно в этом модуле

-- информация о работе тотемов и их силе загружается при запуске уровя в self.totems_info_list
-- загружается информация только о поведении тотема с текущзем урвонем силы(так как по ходу урвоня она изменитсья не может)

-- функция totems_widget.IsTotemEffects проверяет есть ли эффект тотема или цвета в очереди обработки,
-- она вызывается из GameField, когда прочие условия позволяют сделать снап шот игры

totems_widget = totems_widget or {}

function totems_widget.__CreateInstance()
    return "totems_widget"
end

-- функция поолета по параболе
totems_widget.ParabolaFlyFunction = function(_start_pos, _end_pos, _t, _a, _b, _c)
	local current_pos = _start_pos + (_end_pos - _start_pos)*_t
	current_pos.Y = current_pos.X*current_pos.X*_a + current_pos.X*_b + _c
	return current_pos
end

__inherite(totems_widget, null_lua_widget_handler())

local self = totems_widget

-- время работы тотема - используется во время действия тотема
totems_widget._totem_work_time = 250

-- таблица для функциий создания эффектов тотемов
-- заполяняется в модулях реализующий тотемы
totems_widget._totem_effect_create_functions = totems_widget._totem_effect_create_functions or {}

-- определение таблицы с функциями, которые загружают параметры тотемов
totems_widget._totem_load_options_functions = totems_widget._totem_load_options_functions or {}

totems_widget._totems = {}

-- функция для обработки состояния щитов и изменения их отображения
-- вызывается при загрузке или начале уровня, а так же при работе тотема
function totems_widget.GetAbsOffset(_offset)
	return totems_widget._offset + _offset
end

-- карта соотнасящая индексы цветов с id тотемов
totems_widget._totems_map = 
{
	[s11.CFieldCap.CapTypeGreen] = "green_totem",
	[s11.CFieldCap.CapTypeYellow] = "yellow_totem",
	[s11.CFieldCap.CapTypeRed] = "red_totem",
	[s11.CFieldCap.CapTypeBlue] = "blue_totem",
	[s11.CFieldCap.CapTypeOrange] = "orange_totem",
	[s11.CFieldCap.CapTypeWhite] = "white_totem",
	[s11.CFieldCap.CapTypeViolet] = "violet_totem"
}

-- функция для загрузки списков бонусов из настроек игры
function totems_widget._LoadBonusList(_type)
    --получаем настройки гемплея для запускаемого урвоня
	local settings = self._parent_game_field.GetGameplaySettings()

	-- загружаем список бонусов
	list = {}
	for i = 0, settings.EnumBonusesList(_type) - 1 do
		table.insert(list, settings.GetBonusesListElement(_type, i))
	end
	return list
end

function totems_widget.LoadSettings()
	-- загружаем настройки тотемов
	local totems_group = g_App.GetSettings().GetChild("Items", false).GetChildRef("totems", false)
	if not totems_group then
		__message("Items info not found")
		return
	end


	totems_widget.totems_info_list = {}

    -- обходим все тотемы
	-- учитывая что может быть индекс 0 используем pairs
	for totem_index, totem_name in pairs(totems_widget._totems_map) do
		-- загружаем группу с настройкми тотема
		local totem_info = totems_group.GetChildByAttributeRef("totem", "name", totem_name, false)
		if not totem_info then
			-- если группы для этого тотема нет то ругаемся и выходим 
			__message("totem_widget : Settings for "..totem_name.."not found.")
			return
		end
		-- добавляем новую таблицу тотема
		local new_totem_table = {}
		totems_widget.totems_info_list[totem_index] = new_totem_table
		
		-- обходим в группе тотема его уровни силы 
		new_totem_table.activations = {}
		
		local force_index = 1
		local force_level = totem_info.GetChildRef("totem_level", false)
		while force_level do
			-- находим настрйоки для текущего уровеня силы тотема
			-- добавляем таблицу активаций тотема
			local new_activations_table = {}
			new_totem_table.activations[force_index] = new_activations_table
			-- загружаем в нее имеющиеся активации
			local activation_index = 1
			local activation = force_level.GetChildRef("activate", false)
			while activation do
				-- для каждой актвиации создаем подтаблицу с двумя параметарми
				-- которые определют действия тотемов
				local new_activation = {}
				new_activations_table[activation_index] = new_activation
				new_activation.perk1 = tonumber(activation.GetValue("perk1").c_str()) or 0
				new_activation.perk2 = tonumber(activation.GetValue("perk2").c_str()) or 0
				activation = activation.GetNextSiblingRef()
				activation_index = activation_index + 1
			end
			force_level = force_level.GetNextSiblingRef()
			force_index = force_index + 1
		end
	end
end

totems_widget.LoadSettings()

-- инициализация модуля в соотвтесии с сохраненной игрой
function totems_widget.Init(_game_field)
	
	self._gameplay_settings = _game_field.GetGameplaySettings()
	
	self._parent_game_field = _game_field
	self._game_info = _game_field.GetGameInfo()
	-- загружаем список слабых боунсов
	self._weak_bonuses_list = totems_widget._LoadBonusList(s11.GameplaySettings.BonusesListWeak)
	-- загружаем список сильных бонусов
	self._strong_bonuses_list = totems_widget._LoadBonusList(s11.GameplaySettings.BonusesListStrong)
	
	-- изначального активных тотемов нет
	totems_widget.active_totem = nil
	
	-- активный тотем
	local active_totem = _game_field.GetCurrentActiveTotem()
	-- состояние активного тотема
	local active_totem_stage = _game_field.GetCurrentTotemStage()
	
	-- функции для получения/установки дополнительных фич тотемов.
	-- пока использоются только для синих тотемов.
	local extra_feature_functions = 
	{
		[s11.CFieldCap.CapTypeBlue] =
		{
			get = _game_field.IsSteelShield,
			set = _game_field.SetSteelShield
		}
	}
	
	-- создание тотемов
	self._totems = {}
	for totem_index, totem_name in pairs(self._totems_map) do
		-- уровень тотема
		local totem_force =  self._gameplay_settings.GetItemLevel(totem_name)
		
		if totem_force < 0 then
			-- если сила меньше 0 то значить настройки для такого тотема в профайле отсутсвуют
			-- ругаемся и выходим
			__message("totem_widget : Force value for "..totem_name.."not found in profile options. Unknown totem id.")
		end
		
		local totem = totems.CTotem(totem_index, totem_name, totem_force, self.effects_timer, 
						extra_feature_functions[totem_index])
		table.insert(self._totems, totem)
		
		-- если созданный тотем должен быть активным, делаем таковым и устанавливаем ему состояние, загруженное из сэйвы
		if totem_index == active_totem then
			totems_widget.active_totem = totem
			totem:SetState(active_totem_stage+1)
		end
	end
	
	-- загружаем настройки тотемов
	local totems_group = g_App.GetSettings().GetChild("Items", false).GetChildRef("totems", false)
	if not totems_group then
		__message("Items info not found")
		return
	end

    -- обходим все тотемы
	-- учитывая что может быть индекс 0 используем pairs
	for totem_index, totem_name in pairs(self._totems_map) do
		-- загружаем группу с настройкми тотема
		local totem_info = totems_group.GetChildByAttributeRef("totem", "name", totem_name, false)
		if not totem_info then
			-- если группы для этого тотема нет то ругаемся и выходим 
			__message("totem_widget : Settings for "..totem_name.."not found.")
			return
		end

		-- загружаем силу данного тотема
		local totem_force = self._gameplay_settings.GetItemLevel(totem_name)
		if totem_force < 0 then
			-- если сила меньше 0 то значить настройки для такого тотема в профайле отсутсвуют
			-- ругаемся и выходим
			__message("totem_widget : Force value for "..totem_name.."not found in profile options. Unknown totem id.")
		end
		
		-- запоминаем силу тотема(возможно будет использована в дальнейшем для отображения тотемов)
		self.totems_info_list[totem_index].totem_force = totem_force
		
		-- загружаем параметры работы тотемов, которые для каждого тотема свои
		local load_function = totems_widget._totem_load_options_functions[totem_index]
		if load_function then
			local totems_info = g_App.GetSettings().GetChild("Constants", false).GetChild("totems_options", false).GetChild(totem_name, false)
			if totems_info.GetId().c_str() == "" then
				__message("Settings for "..totem_name.." not found")
				return
			end
		    -- вызываем функцию загрузки параметров для данного тотема
			load_function(totems_info)
		end
		
	end
	
end

function totems_widget.Load(_this, _info, _templates)
	totems_widget._offset = sf.misc.FloatVector(_this.GetOffset())
	-- список цветов
	totems_widget._colors_list = {}

	-- текущий эффект тотема
	totems_widget._totem_effect = nil
	
	-- таймер для эффектов тотемов
	self.effects_timer = sf.core.CTimerWrapper(sf.core.g_Application.GetTimeManager().GetTimer("game_timer").AttachTimer(""))
	
end

-- добавить цвет разрушенного ряда в обработку
-- вызывается при разрушении мача опредленного цвета
function totems_widget.AddColor(_color)
	table.insert(self._colors_list, _color)
end

-- сброс цветов
function totems_widget.DropColors()
	self._colors_list = {}
end

-- функция которая проверяет что нет эффекта тотема или его смены и не ожидается
function totems_widget.IsTotemEffects()
	-- работает ли эффект тотема
	if self._totem_effect ~= nil then
		return true
	end
	
	-- работает ли эффект актививарования/деактивирования тотема
	local fade_effect = false
	for _,t in pairs(self._totems) do
		fade_effect = fade_effect or t:IsFade()
	end
	if fade_effect then
		return true
	end
	
	-- есть ли в очереди необработанные мачи
	if #self._colors_list > 0 then
		return true
	end
	
	return false
end

-- активировать тотем.
-- вызывает из CTotem'а
function totems_widget.ActivateTotem(_totem)
	game_window.game_field.SetCurrentActiveTotem(_totem._color)
	game_window.game_field.SetCurrentTotemStage(0)
	totems_widget.active_totem = _totem
end

-- деактивировать тотем.
-- вызывает из CTotem'а
function totems_widget.DeactivateTotem(_totem)
	if totems_widget.active_totem == _totem then
		game_window.game_field.SetCurrentActiveTotem(-1)
		totems_widget.active_totem = nil
	end
end

-- использовать тотем.
-- _totem - СTotem.
-- _stage - схема использования (1 или 2)
-- вызывает из CTotem'а
function totems_widget.UseTotem(_totem, _stage)
	game_window.game_field.SetCurrentTotemStage(_stage)
	self._totem_effect = self._totem_effect_create_functions[_totem._color]()
	local totem_upgrade_level = self.totems_info_list[_totem._color].totem_force
	self._totem_effect:Init(self.totems_info_list[_totem._color].activations[totem_upgrade_level][_stage])
	if self._game_info then
		local used_totems = self._game_info.GetTotemsUsedCount() + 1
		self._game_info.SetTotemsUsedCount(used_totems)
		if used_totems == 50 then
			achievements.GetAchievement("totem_use_50")	
		end
	end
end

function totems_widget.DemonstrateTotem(_totem)
	for _,t in pairs(self._totems) do
		if t._color == _totem then
			t:Demonstrate()
			return
		end
	end
end

function totems_widget.DoUpdate(_this)
	-- активный тотем всегда должен быть наверху, чтобы эффект активирования/декактивирования рисовался воверх остальных тотемов.
	-- проверяем, является ли активный тотем самым верхним.
	-- если не так, то удаляем его со своей текущей позиции в списке и вставляем в конец этого списка, тем самым делая его верхним.
	if totems_widget.active_totem and self._totems[#self._totems] ~= totems_widget.active_totem then
		for i,t in pairs(self._totems) do
			if t == totems_widget.active_totem then
				table.remove(self._totems, i)
				break
			end
		end
		table.insert(self._totems, totems_widget.active_totem)
	end
	
	-- обновляем тотемы.
	local fade_effect = false
	for _,t in pairs(self._totems) do
		t:Update()
		fade_effect = fade_effect or t:IsFade()
	end
	
	-- обновляем эффект тотема, если он есть.
	if self._totem_effect then
		self._totem_effect:Update(self.effects_timer.Get().GetTime())
		if self._totem_effect:IsDead() then
			self._totem_effect = nil
		end
	end
	
	-- если в данный момент активен эффект активирования/деативирования или эффект дейстия тотема, то выходим из функции
	if fade_effect or self._totem_effect then
		return false
	end
	
	-- есть ли в очереди необработанные мачи
	if #self._colors_list <= 0 then
		return false
	end
		
	-- если цвета еще есть, то берем из очереди следующий
	local color = self._colors_list[1]
	
	for _,t in pairs(self._totems) do
		t:OnMatch(color)
	end
	
	-- удаляем обработаный цвет из очереди
	table.remove(self._colors_list, 1)
		
	return false
end

function totems_widget.DoDraw(_this, _renderer)
	-- рисуем тотемы
	for _,t in pairs(self._totems) do
		t:Draw(_renderer)
	end
	
    return false
end

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

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

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

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