-- by modelleicher
-- www.schwabenmodding.bplaced.net
-- December 2015
-- Version 1.0, works with OEB_realTerrain, not ideal (wheels jump a bit if both are active, like your in the field and hitting the pressure change button) 
-- but not errors and all works fine

-- Version 1.1, missing tire tracks when low air fixed
-- Version 1.2, added sound
-- XML: lowAirRadius="" optional for each wheel in xml


adjustableTirePressure = {};

function adjustableTirePressure.prerequisitesPresent(specializations)
    return true;
end;

function adjustableTirePressure:load(xmlFile)
	self.changeTPState = adjustableTirePressure.changeTPState;
	self.wheelsCnt = 0;
	for id, wheel in ipairs(self.wheels) do
		wheel.radiusOld = wheel.radius;
		wheel.lowAirRadius = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.wheels.wheel("..self.wheelsCnt..")#lowAirRadius"), wheel.radius*0.84);
		wheel.currentRadius = wheel.radius;
		self.wheelsCnt = self.wheelsCnt +1;
	end;
	self.isAirLow = false;
	self.isAirLowChanged = true;
	
	-- V1.2 Sound
	self.aTPFillSound = {};
	self.aTPLowerSound = {};
	local fillSound = getXMLString(xmlFile, "vehicle.adjustableTirePressure.fillSound#file");
	local lowerSound = getXMLString(xmlFile, "vehicle.adjustableTirePressure.lowerSound#file");
	if fillSound ~= nil then
		fillSound = Utils.getFilename(fillSound, self.baseDirectory);
		self.aTPFillSound.sample = createSample("aTPFillSound");
		loadSample(self.aTPFillSound.sample, fillSound, false);
		self.aTPFillSound.volume = getXMLFloat(xmlFile, "vehicle.adjustableTirePressure.fillSound#volume");
		self.aTPFillSound.exists = true;
		setSamplePitch(self.aTPFillSound.sample, 1);
	end;
	if lowerSound ~= nil then
		lowerSound = Utils.getFilename(lowerSound, self.baseDirectory);
		self.aTPLowerSound.sample = createSample("aTPLowerSound");
		loadSample(self.aTPLowerSound.sample, lowerSound, false);
		self.aTPLowerSound.volume = getXMLFloat(xmlFile, "vehicle.adjustableTirePressure.lowerSound#volume");
		self.aTPLowerSound.exists = true;
		setSamplePitch(self.aTPLowerSound.sample, 1);
	end;
end;
function adjustableTirePressure:readStream(streamId, connection)
	if connection:getIsServer() then
		self:changeTPState(streamReadBool(streamId));
	end;
end;
function adjustableTirePressure:writeStream(streamId, connection)
	if not connection:getIsServer() then
		streamWriteBool(streamId, self.isAirLow);
	end;
end;
function adjustableTirePressure:changeTPState(state, noEventSend)
	if state ~= self.isAirLow then
		self.isAirLow = state;
		self.isAirLowChanged = false;
		adjustableTirePressureEvent.sendEvent(self, state, noEventSend);
		
		if not state and self.aTPFillSound.exists then -- V1.2 addition, sound
			playSample(self.aTPFillSound.sample, 1, self.aTPFillSound.volume, 0);
		end;
		if state and self.aTPLowerSound.exists then
			playSample(self.aTPLowerSound.sample, 1, self.aTPLowerSound.volume, 0);
		end;
	end;
end;
function adjustableTirePressure:update(dt)
	if self:getIsActive() then
		if self:getIsActiveForInput() then
			if InputBinding.hasEvent(InputBinding.adjustAirPressure) then
				self:changeTPState(not self.isAirLow);
			end;
		end;
		if self.isServer then -- in MP only the server needs to do this.. since all the physics (so the wheelshapes) are only server-side
			if self.isAirLow and not self.isAirLowChanged then -- lower air pressure
				local isAirLowChanged = 0;
				for id, wheel in ipairs(self.wheels) do
					local radius = math.max(wheel.currentRadius - (0.0001*dt), wheel.lowAirRadius);
					local positionY = wheel.netInfo.yMin + wheel.netInfo.yRange;
					local doUpdate = true;
					if wheel.RT ~= nil then -- if OEB_realTerrain is active 
						wheel.RT.origWheelRadius = radius;		
						if wheel.RT.currentRadiusDelta ~= wheel.RT.radiusDelta then
							doUpdate = false; -- since OEB_realTerrain changes the wheelshape already, we dont
						end;
					end;
					if doUpdate then
						createWheelShape(wheel.node, wheel.positionX, positionY, wheel.positionZ, radius, wheel.suspTravel, wheel.spring, wheel.damper, wheel.mass, collisionMask, wheel.wheelShape);
					end;
					wheel.currentRadius = radius;
					wheel.radius = radius;
					if radius == wheel.lowAirRadius then
						isAirLowChanged = isAirLowChanged +1;
					end;
				end;
				if isAirLowChanged == self.wheelsCnt then
					self.isAirLowChanged = true;
				end;
			elseif not self.isAirLow and not self.isAirLowChanged then -- add air pressure
				local isAirLowChanged = 0;
				for id, wheel in ipairs(self.wheels) do
					local radius = math.min(wheel.currentRadius + (0.0001*dt), wheel.radiusOld);
					local positionY = wheel.netInfo.yMin + wheel.netInfo.yRange;
					local doUpdate = true;
					if wheel.RT ~= nil then -- if OEB_realTerrain is active 
						wheel.RT.origWheelRadius = radius;		
						if wheel.RT.currentRadiusDelta ~= wheel.RT.radiusDelta then
							doUpdate = false; -- since OEB_realTerrain changes the wheelshape already, we dont
						end;
					end;
					if doUpdate then
						createWheelShape(wheel.node, wheel.positionX, positionY, wheel.positionZ, radius, wheel.suspTravel, wheel.spring, wheel.damper, wheel.mass, collisionMask, wheel.wheelShape);
					end;
					wheel.currentRadius = radius;
					wheel.radius = radius;
					if radius == wheel.radiusOld then
						isAirLowChanged = isAirLowChanged +1;
					end;
				end;
				if isAirLowChanged == self.wheelsCnt then
					self.isAirLowChanged = true;
				end;
			end;
		end;
	end;		
end;
function adjustableTirePressure:delete()
end;
function adjustableTirePressure:mouseEvent(posX, posY, isDown, isUp, button)
end;
function adjustableTirePressure:keyEvent(unicode, sym, modifier, isDown)
end;
function adjustableTirePressure:draw()
	if self:getIsActiveForInput() then
		if self.isAirLow then
			g_currentMission:addHelpButtonText(g_i18n:getText("adjustableTirePressure_airLow"),  InputBinding.adjustAirPressure);		
		else
			g_currentMission:addHelpButtonText(g_i18n:getText("adjustableTirePressure_airHigh"),  InputBinding.adjustAirPressure);		
		end;
	end;
end;

-- event
adjustableTirePressureEvent = {};
adjustableTirePressureEvent_mt = Class(adjustableTirePressureEvent, Event);

InitEventClass(adjustableTirePressureEvent, "adjustableTirePressureEvent");

function adjustableTirePressureEvent:emptyNew()
	local self = Event:new(adjustableTirePressureEvent_mt);
    return self;
end;

function adjustableTirePressureEvent:new(object, state)
	local self = adjustableTirePressureEvent:emptyNew();
	self.object = object;
	self.state = state;
	return self;
end;

function adjustableTirePressureEvent:readStream(streamId, connection)
	local id = streamReadInt32(streamId);
	self.object = networkGetObject(id);
	self.state = streamReadBool(streamId);
    self:run(connection);
end;

function adjustableTirePressureEvent:writeStream(streamId, connection)
	streamWriteInt32(streamId, networkGetObjectId(self.object));
	streamWriteBool(streamId, self.state);
end;

function adjustableTirePressureEvent:run(connection)
	self.object:setAnimation(self.state, true);
	if not connection:getIsServer() then
		g_server:broadcastEvent(adjustableTirePressureEvent:new(self.object, self.state), nil, connection, self.object);
	end;
end;

function adjustableTirePressureEvent.sendEvent(object, state, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(adjustableTirePressureEvent:new(object, state), nil, nil, object);
		else
			g_client:getServerConnection():sendEvent(adjustableTirePressureEvent:new(object, state));
		end;
	end;
end;




