----------------------------------------------------------------------------
--------------"The simplest design is the best design." --------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
-- Copyright (C)ViperGTS96--------------------------------------------
----------------------------------------------------------------------------

inactiveUpdater = {};

function inactiveUpdater:getHasMudStateChange(vehicle)
	local retValue = false;
	for i,wheel in pairs(vehicle.spec_wheels.wheels) do
		local updateSink_A = wheel.isInMud;
		local updateSink_B = wheel.isInFieldMud;
		wheel.isInMud, wheel.isInFieldMud = vehicle:getIsInMud(nil, wheel, true);
		if updateSink_A ~= wheel.isInMud or updateSink_B ~= wheel.isInFieldMud then
			vehicle:setMudSinkState(i,-1, wheel.isInMud, wheel.isInFieldMud);
			retValue = true;
		end;
		if wheel.mudSystem ~= nil and wheel.mudSystem.mudPS ~= nil and not wheel.mudSystem_sinkOnly then
			local ps = wheel.mudSystem.mudPS;
			local updateState = ps.isActive;
			local activePS = wheel.isInMud;
			ps.isActive = activePS;
			ParticleUtil.setEmittingState(ps, ps.isActive);
			if updateState ~= ps.isActive then
				vehicle:setMudEmittingState(i,-1, ps.isActive);
			end;
		end;
		if wheel.additionalWheels ~= nil then
			for a,additionalWheel in pairs(wheel.additionalWheels) do
				updateSink_A = additionalWheel.isInMud;
				updateSink_B = additionalWheel.isInFieldMud;
				additionalWheel.isInMud, additionalWheel.isInFieldMud  = vehicle:getIsInMud(wheel, additionalWheel, true);
				if updateSink_A ~= additionalWheel.isInMud or updateSink_B ~= additionalWheel.isInFieldMud then
					vehicle:setMudSinkState(i,a, additionalWheel.isInMud, additionalWheel.isInFieldMud);
				end;
				if additionalWheel.mudSystem ~= nil and additionalWheel.mudSystem.mudPS ~= nil and not wheel.mudSystem_sinkOnly then
					ps = additionalWheel.mudSystem.mudPS;
					updateState = ps.isActive;
					activePS = additionalWheel.isInMud;
					ps.isActive = activePS;
					ParticleUtil.setEmittingState(ps, ps.isActive);
					if updateState ~= ps.isActive then
						vehicle:setMudEmittingState(i,a, ps.isActive);
					end;
				end;
			end;
		end;
		if retValue then
			return true;
		end;
	end;
	return false;
end;

function inactiveUpdater:updateWheelPhysics(vehicle, dt)
	for _,wheel in pairs(vehicle.spec_wheels.wheels) do
		vehicle:updateWheelSink(wheel,dt,0,true);
		vehicle:updateWheelFriction(wheel, dt, 0);
		if wheel.densityType ~= nil and wheel.densityTypeForcedUpdate ~= nil then
			local wheelNode = wheel.mudSystemMainNode;
			local offsetY = 0;
			if wheelNode == nil then wheelNode = wheel.wheelTire; offsetY = -wheel.radius; end;
			if wheelNode == nil then wheelNode = wheel.driveNode; offsetY = -wheel.radius; end;
			if wheelNode == nil then wheelNode = wheel.repr; offsetY = -wheel.radius; end;
			local x,y,z = getWorldTranslation(wheelNode);
			if offsetY > 0 then x,y,z = localToWorld(wheelNode, 0,offsetY,0); end;
			local yT = getDensityHeightAtWorldPos(g_currentMission.terrainDetailHeightId, x,y,z);
			wheel.densityType = getDensityAtWorldPos(g_currentMission.terrainDetailId,x,yT,z);
			wheel.densityTypeForcedUpdate = nil;
		end;
	end;
end;

function inactiveUpdater:update(dt)
	for _, vehicle in pairs(g_currentMission.vehicles) do
		local inActive = not vehicle:getIsActive();
		if vehicle.spec_mudSystem ~= nil and vehicle.spec_wheels ~= nil and vehicle.spec_wheels.wheels ~= nil then
			if g_currentMission:getIsServer() and inActive then
				local xW,_,zW = getWorldTranslation(vehicle.rootNode);
				xW,zW= math.floor(xW),math.floor(zW);
				if vehicle.spec_mudSystem.lastPosition == nil then
					vehicle.spec_mudSystem.lastPosition = {x=xW,z=zW};
				end;
				if vehicle.spec_mudSystem.lastPosition.x ~= xW or vehicle.spec_mudSystem.lastPosition.z ~= zW then
					if inactiveUpdater:getHasMudStateChange(vehicle) then
						vehicle.spec_mudSystem.updateSinkTimer = (g_time/1000) + 60;
					end;
					vehicle.spec_mudSystem.lastPosition = {x=xW,z=zW};
				end;

				local timer = vehicle.spec_mudSystem.updateSinkTimer;
				if timer ~= nil and (g_time/1000) < timer then
					inactiveUpdater:updateWheelPhysics(vehicle, dt);
				else
					timer = nil;
				end;

			else
				if vehicle.spec_mudSystem.updateSinkTimer ~= nil then
					vehicle.spec_mudSystem.updateSinkTimer = nil;
				end;
				if vehicle.spec_mudSystem.lastPosition ~= nil then
					vehicle.spec_mudSystem.lastPosition = nil;
				end;
			end;
			if g_currentMission:getIsClient() and inActive then
				for i,wheel in pairs(vehicle.spec_wheels.wheels) do
					if wheel.mudSystem ~= nil and wheel.mudSystem.mudPS ~= nil then
						if wheel.netInfo.xDriveLast == nil then
							wheel.netInfo.xDriveLast = wheel.netInfo.xDrive;
						end;
						local xDriveDiff = wheel.netInfo.xDrive - wheel.netInfo.xDriveLast;
						if xDriveDiff > math.pi then
							wheel.netInfo.xDriveLast = wheel.netInfo.xDriveLast + 2*math.pi;
						elseif xDriveDiff < -math.pi then
							wheel.netInfo.xDriveLast = wheel.netInfo.xDriveLast - 2*math.pi;
						end;
						xDriveDiff = wheel.netInfo.xDrive - wheel.netInfo.xDriveLast;
						wheel.netInfo.xDriveLast = wheel.netInfo.xDrive;
						local wheelRotSpeed = math.deg(xDriveDiff) / (0.001 * dt);
						local maxWheelRotSpeed = 1080;
						local wheelRotFactor = math.abs(wheelRotSpeed) / maxWheelRotSpeed;
						wheelRotFactor = wheelRotFactor * wheel.radius;
						vehicle:updateWheelMudPS(wheel, wheelRotFactor, wheel.steeringAngle);
						if wheel.additionalWheels ~= nil then
							for a,additionalWheel in pairs(wheel.additionalWheels) do
								vehicle:updateWheelMudPS(additionalWheel, wheelRotFactor, wheel.steeringAngle, wheel);
							end;
						end;
					end;
				end;
			end;
		end;
	end;
end;

addModEventListener(inactiveUpdater);