local weather_manager = nil
--18.02.2008 - added dynamic weather
--25.02.2010 - modified for AtmosFear by Cromm Cruac
-- No dynamic DOF

class "WeatherManager"
function WeatherManager:__init()
	self.wfx_time = 0
	self.weather_fx = nil
	self.update_time = 0
	self.update_level = ""
	self.forced_weather_change_on_time_change = false
	self.last_hour = 0
		self.state={}
	self.graphs={}
	self.graphs_ini = ini_file("environment\\dynamic_weather_graphs.ltx")
	if not self.graphs_ini then
		abort("error when open weather_dynamic_graphs.ltx")
	end
	self.period="good"
	self.last_period_change_hour=level.get_time_hours()
	--self.fallout=fallout_manager.get_fallout_manager()
	--self.debugMessages=debug_ui.get_debug_ui():create_elements(5)
	--self.debugMessages[1]:SetText("Weather system initialized")
	
end

-- Вызывается после load(). Состояние погоды уже загружено.
function WeatherManager:reset()
	printf("WeatherManager:WeatherManager():Reset()")
	-- Загрузить кондлист с погодой.
	local ini = ini_file("game.ltx")
	local weather = utils.cfg_get_string(ini, level.name(), "weathers", db.actor, false, "", "[default]")
	self.levelWeather = weather
	local postprocess = utils.cfg_get_string(ini, level.name(), "postprocess", db.actor, false, "")
	if postprocess ~= nil then
		printf("LEVEL POSTPROCESS: level: [%s], postprocess: [%s]", level.name(), postprocess)
		level.add_pp_effector(postprocess, 999, true)
	else
		printf("LEVEL POSTPROCESS: level: [%s], postprocess: [none]", level.name())
		level.remove_pp_effector(999)
	end
	if weather == "[default]" then
		-- сетим дефолтовую погоду
		self.weather_list = xr_logic.parse_condlist(db.actor, level.name(), "weather", "[default]")
	else
		self.weather_list = xr_logic.parse_condlist(db.actor, level.name(), "weather", weather)
	end
	
	-- CC read period hours
	if weather=="dynamic_default" or weather=="dynamic_zaton" or weather=="dynamic_jupiter" or weather=="dynamic_pripyat"then
		self.periods = xr_s.parse_ini_section_to_array(self.graphs_ini,weather.."_periods")
	else
		self.periods = xr_s.parse_ini_section_to_array(self.graphs_ini,"dynamic_default_periods")
	end
	self.next_period_change_hour=self:get_next_period_change_hour(self.period)
	-- end CC
    self:select_weather(true)
	self.last_hour=level.get_time_hours()
end

-- CC Functions

function WeatherManager:get_next_period_change_hour(period)
	local hour=0
	if period=="good" then 
		hour = math.random(self.periods["min_good"],self.periods["max_good"])+self.last_period_change_hour
	else
		hour = math.random(self.periods["min_bad"],self.periods["max_bad"])+self.last_period_change_hour
	end
	if hour>23 then
		hour=hour-24
	end
	return hour
end

function WeatherManager:change_period()
	local current_hour=level.get_time_hours()
	if current_hour==self.next_period_change_hour then
		if self.period == "good" then		
			self.period = "bad"
		else
			self.period = "good"
		end
		self.last_period_change_hour=current_hour
		self.next_period_change_hour=self:get_next_period_change_hour(self.period)
	end
end

-- end CC Functions

function WeatherManager:forced_weather_change()
	self.forced_weather_change_on_time_change = true
end

-- Обновляем погоду раз в час.
function WeatherManager:update()
		
	if(level.is_wfx_playing()) then
		self.weather_fx = level.get_weather()
	else
		self.weather_fx = nil
	end
	if not benchmark.weather then
		if self.last_hour~=level.get_time_hours() then
				self.last_hour=level.get_time_hours()
				for lvl,st in pairs(self.state) do
				st.current_state=st.next_state
				st.next_state=get_next_state(st.graph,st.current_state)
				end
				-- CC change period
				self:change_period()
				-- end CC
				-- Устанавливаем погоду на текущем уровне
				self:select_weather(false)
		end
	end
end

function WeatherManager:select_weather(now)
	local weather = xr_logic.pick_section_from_condlist(db.actor, db.actor, self.weather_list)
	-- CC add period to name
	if weather=="dynamic_default" or weather=="dynamic_zaton" or weather=="dynamic_jupiter" or weather=="dynamic_pripyat"then
		weather = weather.."_"..self.period
	end
	-- end CC
	local graph=self:get_graph_by_name(weather)
	local weather_section_name=""
	if graph==nil then
		self.state[weather]=nil
			weather_section_name=weather
	else
			if self.state[weather]==nil or self.state[weather].graph_name~=weather then
			self.state={}
			self.state[weather]=self:init_by_graph(graph,weather)
			end
			local st=self.state[weather]
			weather_section_name="default_"..st.current_state
	end
	if now then
		self.last_hour=level.get_time_hours()
	end
	if self.forced_weather_change_on_time_change then
		now = true
		self.forced_weather_change_on_time_change = false
	end
	if not(self.weather_fx) then
		level.set_weather(weather_section_name,now)
	else
		level.start_weather_fx_from_time(self.weather_fx, self.wfx_time)
	end
	printf("WEATHER: '%s' now '%s'", weather_section_name, tostring(now))
	--self.debugMessages[2]:SetText("WEATHER: "..weather_section_name)
end

-- Возвращает начальное состояние погоды.
function WeatherManager:init_by_graph(graph,graph_name)
	local cur_state=get_next_state(graph,"")
	local next_state=get_next_state(graph,cur_state)
	return {current_state=cur_state,next_state=next_state,graph_name=graph_name,graph=graph}
end

-- Возвращает одно из следующих состояний графа, согласно прописанным вероятностям.
function get_next_state(graph,state)
	local sum=0
	for st,prob in pairs(graph) do
		--if state==st then prob=prob*2 end
		sum=sum+prob
	end
	local rnd=math.random()*sum
	local next_state
	for st,prob in pairs(graph) do
		--if state==st then prob=prob*2 end
		next_state=st
		rnd=rnd-prob
		if (rnd<=0) then
			break
		end
	end
	return next_state
end

-- Устанавливаем состояние менеджера, распарсивая строку состояния
function WeatherManager:set_state_as_string(ss)
	self.state={}
		for lvlstring in string.gmatch(ss,"[^;]+") do
		local i,j,grname,curs,nexs=string.find(lvlstring,"([^=]+)=([^,]+),([^,]+)")
		if not grname then
			abort("WeatherManager:set_state_as_string: malformed state string. "..ss)
		end
		--local lvl_name=self:unpack_level(lvl)
		local current_state=self:unpack_state(curs)
		local next_state=self:unpack_state(nexs)
		local graph_name=self:unpack_graph_name(grname)
		local graph=self:get_graph_by_name(graph_name)
		-- guessing what period has been saved
		--self.debugMessages[1]:SetText("graph_name="..graph_name)	
		--self.debugMessages[2]:SetText("current_state="..current_state)
		if string.sub(graph_name, -3)== "bad" then
			self.period="bad"
		else
			self.period="good"
		end		
		--self.debugMessages[2]:SetText("period="..self.period)
		if graph==nil then
		-- Старая сохранёнка? Будем считать что на этом уровне - статическая погода
		else
			self.state[graph_name]={current_state=current_state,next_state=next_state,graph_name=graph_name,graph=graph}
		end
	end
end

-- Преобразуем текущее состояние менеджера в строку
function WeatherManager:get_state_as_string()
	local lvlstrings={}
	for lvl_name,st in pairs(self.state) do
		--local lvl=self:pack_level(lvl_name)
		local curs=self:pack_state(st.current_state)
		local nexs=self:pack_state(st.next_state)
		local grn=self:pack_graph_name(st.graph_name)
		table.insert(lvlstrings,grn.."="..curs..","..nexs)
	end
	return table.concat(lvlstrings,";")
end

-- Получить граф (таблицу переходов состояний погоды) по его названию и названию игрового уровня
function WeatherManager:get_graph_by_name(name)
	if not self.graphs[name] then
		self.graphs[name] = xr_s.parse_ini_section_to_array(self.graphs_ini,name)
	end
	return self.graphs[name]
end

-- Запаковать название вершины графа
function WeatherManager:pack_state(state)
	-- Пока паковать не будем.
	return state
end

-- Распаковать название вершины графа
function WeatherManager:unpack_state(st)
	-- Пока паковать не будем
	return st
end

-- Запаковать название графа переходов погоды
function WeatherManager:pack_graph_name(graph_name)
	-- Пока паковать не будем.
	return graph_name
end

-- Распаковать название графа переходов погоды
function WeatherManager:unpack_graph_name(grn)
	-- Пока паковать не будем
	return grn
end

function WeatherManager:load(F)
	set_save_marker(F, "load", false, "WeatherManager")
	printf("WEATHER LOAD")
	--self.update_level  = F:r_stringZ();
	local state_string = F:r_stringZ();
	printf("str = "..state_string)
	if state_string == "" then
		printf("str = empty string")
	end
	self:set_state_as_string(state_string)
	self.update_time = F:r_u32();
	local str = F:r_stringZ()
	if(str~="nil") then
		self.weather_fx = str
		self.wfx_time = F:r_float()
	end
	set_save_marker(F, "load", true, "WeatherManager")
end

function WeatherManager:save(F)
	set_save_marker(F, "save", false, "WeatherManager")
	printf("WEATHER SAVE")
	--F:w_stringZ(self.update_level);
	printf("str = "..tostring(self:get_state_as_string()))
	if self:get_state_as_string() == "" then
		printf("str = empty string")
	end
	F:w_stringZ(self:get_state_as_string())
	F:w_u32(self.update_time)
	F:w_stringZ(tostring(self.weather_fx))
	if(self.weather_fx) then
		F:w_float(level.get_wfx_time())
	end
	set_save_marker(F, "save", true, "WeatherManager")
end

function get_weather_manager ()
	if weather_manager == nil then
		weather_manager = WeatherManager()
	end
	return weather_manager
end
