--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| 	Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]


--	Weather mixed updates the variables live, unlike the Data.
--	This can't be set tho.
StormFox2.Mixer = {}

-- Local function
local function isColor(t)
	return t.r and t.g and t.b and true or false
end

---Tries to blend two variables together. Will return first variable if unable to.
---@param nFraction number
---@param vFrom any
---@param vTo any
---@return any
---@shared
local function Blender(nFraction, vFrom, vTo)
	-- Will it blend?
	-- Nils should be false, if one of them is a boolean
	if type(vFrom) == "nil" and type(vTo) == "boolean" then
		vFrom = false
	end
	if type(vTo) == "nil" and type(vFrom) == "boolean" then
		vTo = false
	end
	-- If the same value, then return it
	if vTo == vFrom then return vTo end
	-- In case of two diffrent variables.
	if type(vFrom) ~= type(vTo) then
		StormFox2.Warning("Mixer called with values of two different types[" .. type(vFrom) .. "," .. type(vTo) .. "]")
		debug.Trace()
		return vFrom
	elseif type(vTo) == "string" or type(vTo) == "IMaterial" or type(vTo) == "boolean" then -- String, material or bool. Return vTo.
		return vTo
	elseif type(vTo) == "number" then -- Number
		return Lerp(nFraction, vFrom, vTo)
	elseif type(vTo) == "table" then -- Objects
		local t = vTo.__MetaName and vTo.__MetaName == "CCT_Color" or false
		local f = vFrom.__MetaName and vFrom.__MetaName == "CCT_Color" or false
		if t and f then
			local v = StormFox2.util.CCTColor( Lerp( nFraction, vFrom:GetKelvin(), vTo:GetKelvin() ) )
			return v:ToRGB()
		else
			local s = f and vFrom:ToRGB() or vFrom
			local e = t and vTo:ToRGB() or vTo
			local r = Lerp( nFraction, s.r or 255, e.r )
			local g = Lerp( nFraction, s.g or 255, e.g )
			local b = Lerp( nFraction, s.b or 255, e.b )
			local a = Lerp( nFraction, s.a or 255, e.a )
			return Color( r, g, b, a )
		end
	end
	--StormFox2.Warning("ERROR: Unsupported mix value type[" .. type(vTo) .. "]. Returning original value")
	--debug.Trace()
	return vFrom
end

local cache = {}
local cStamp,nStamp,nStampFraction = 0,0,0
local function GetVar( wWeather, sKey )
	local v1 = wWeather:Get(sKey, cStamp)
	if cStamp == nStamp or nStampFraction <= 0 then
		return v1
	end
	local v2 = wWeather:Get(sKey, nStamp)
	local v = Blender(nStampFraction, v1, v2)
	return v
end

StormFox2.Mixer.Blender = Blender

local function vOd(a, b)
	if a == nil then return b end
	return a
end

---Blends the current weather key-variables together. Will return zDefault if fail. The result will be cached, unless you set the currentP variable.
---Mixer allows for live-precise variables.
---@param sKey string
---@param zDefault any
---@param currentP? number
---@return any
---@shared
function StormFox2.Mixer.Get( sKey, zDefault, currentP )
	if not currentP and cache[sKey] ~= nil then return cache[sKey] end
	if not StormFox2.Weather then return zDefault end -- Not loaded yet
	-- Get the current weather
	local cW = StormFox2.Weather.GetCurrent()
	-- In case thw weather-type is clear, no need to calculate.
	if not cW or cW.Name == "Clear" then return vOd( GetVar(cW, sKey), zDefault) end
	-- Get the percent, and check if we should cache.
	local shouldCache = not currentP
	currentP = currentP or StormFox2.Weather.GetPercent()
	if currentP >= 1 then -- No need to mix things, weather is at max.
		if shouldCache then
			cache[sKey] = GetVar(cW, sKey)
			return vOd(cache[sKey], zDefault)
		else
			return vOd(GetVar(cW, sKey), zDefault)
		end
	end
	-- Get the default weather to mix with.
	local clearW = StormFox2.Weather.Get( "Clear" )
	local var1 = GetVar(clearW, sKey)
	local var2 = GetVar(cW, sKey)
	if shouldCache then
		cache[sKey] = Blender(currentP, var1, var2)
		return vOd(cache[sKey], zDefault)
	else
		return vOd(Blender(currentP, var1, var2), zDefault)
	end
end
StormFox2.Mixer.Blender = Blender

--[[t.Function = {}
	t.Static = {}
	t.Dynamic = {}
	t.SunStamp = {}
]]

-- Resets the values after a few frames. This is calculated live and should be cached.
local max_frames = 4
local i = 0
local percent = 0
hook.Add("Think", "StormFox2.mixerreset", function()
	i = i + 1
	if i < max_frames then return end
	i = 0
	cache = {}
	-- Current Stamp
	local nTime = StormFox2.Time.Get()
	local stamp, percent, next_stamp, pitch_length = StormFox2.Sky.GetStamp(nTime, nil, true) -- cpercent goes from 0 - 1
	if not pitch_length then return end
	local pitch_left = pitch_length * (1 - percent)
	local forward = 6
	if pitch_left >= 6 then -- Only look 6 degrees in the furture.
		cStamp = stamp
		nStamp = stamp
		nStampFraction = 0
	else
		cStamp = stamp
		nStamp = next_stamp
		nStampFraction = 1 - ( pitch_left / (math.min(pitch_length, 6)) )
	end
end)