--***************************************************************
--
-- based on dural's mrGearbox2.lua
-- 
-- version 1.2 by mogli (biedens)
-- 2014/08/04
--
--***************************************************************

mrGearboxMogli = {} 

function mrGearboxMogli.prerequisitesPresent(specializations) 
	return SpecializationUtil.hasSpecialization(RealisticMotorized, specializations) 
end 

function mrGearboxMogli:load(xmlFile) 

	self.mrGbMSetState          = mrGearboxMogli.mrGbMSetState 
	self.mrGbMSetGear           = mrGearboxMogli.mrGbMSetGear 
	self.mrGbMSetRange          = mrGearboxMogli.mrGbMSetRange 
	self.mrGbMSetAutomatic      = mrGearboxMogli.mrGbMSetAutomatic 
	self.mrGbMGetClutchPercent  = mrGearboxMogli.mrGbMGetClutchPercent 
	self.mrGbMDoGearShift       = mrGearboxMogli.mrGbMDoGearShift 
	
	--adding the new transmission mode
	self.realTransmissionMode.maxMode = self.realTransmissionMode.maxMode + 1
	self.mrGbMTransmissionModeNum     = self.realTransmissionMode.maxMode
	self.realTransmissionMode.modes[self.mrGbMTransmissionModeNum] = {} 
	self.realTransmissionMode.modes[self.mrGbMTransmissionModeNum].enabled = true  -- gearboxMogli mode
	self.realTransmissionMode.modes[self.mrGbMTransmissionModeNum].text = "manual" 	
				
	local xmlString = "vehicle.gearboxMogli" 
	
	self.mrGbMDisableT123             = Utils.getNoNil(getXMLBool( xmlFile, xmlString .. "#disableT123" ),true)
	
	self.mrGbMIdleRpmRatio            = self.realEngine.idleRpm / self.realEngine.ratedRpm  
	self.mrGbMOffRpmRatio             = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. "#motorOffRpm"),    0 ) / self.realEngine.ratedRpm  
	self.mrGbMOpenRpmRatio            = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. "#clutchOpenRpm"),  1.043* self.realEngine.idleRpm) / self.realEngine.ratedRpm  --0.86* self.realEngine.idleRpm) / self.realEngine.ratedRpm  
	self.mrGbMCloseRpmRatio           = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. "#clutchCloseRpm"), 1.43* self.realEngine.idleRpm) / self.realEngine.ratedRpm  
	self.mrGbMOverspeedProtection     = Utils.getNoNil(getXMLBool( xmlFile, xmlString .. "#overspeedProtection"), false)
	
	self.mrGbMClutchEngagingTime      = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. "#clutchEngagingTimeMs"), 1000)  -- 1000 = 1s
	self.mrGbMClutchShiftTime         = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. "#clutchShiftingTimeMs"), 200) 
	self.mrGbMTransmissionEfficiency  = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. "#transmissionEfficiency"), 0.93) 
	self.mrGbMTransmissionEfficiencyBackup = self.realTransmissionEfficiency 
		
	self.mrGbMGearTimeToShiftGear     = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. ".gears#shiftTimeMs"), 800) 
	self.mrGbMGearTimeToShiftHl       = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. ".ranges#shiftTimeMs"), 1000) 
	self.mrGbMGearTimeToShiftReverse  = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. ".reverse#shiftTimeMs"), 1200) 

	self.mrGbMClutchAfterShiftGear    = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. ".gears#clutchRatio"), 0.7) 
	self.mrGbMClutchAfterShiftHl      = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. ".ranges#clutchRatio"), 0.1) 
	self.mrGbMClutchAfterShiftReverse = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. ".reverse#clutchRatio"), 0.1) 

	local f1, f2
	f1 = getXMLFloat(xmlFile, xmlString .. "#maxRpm")
	f2 = getXMLFloat(xmlFile, xmlString .. "#overspeedRpm")
	
	if f1 == nil and f2 == nil then
		self.mrGbMMaxEngineRevFx    = 1 + 100 / self.realEngine.ratedRpm  
		self.mrGbMOverspeedRpmRatio = 1 + 200 / self.realEngine.ratedRpm   
	elseif f1 == nil then
		self.mrGbMOverspeedRpmRatio = f2 / self.realEngine.ratedRpm
		self.mrGbMMaxEngineRevFx    = 0.5 * ( self.mrGbMOverspeedRpmRatio + 1 )
	elseif f2 == nil then
		self.mrGbMMaxEngineRevFx    = f1 / self.realEngine.ratedRpm  
		self.mrGbMOverspeedRpmRatio = 2 * self.mrGbMMaxEngineRevFx - 1
	else
		self.mrGbMMaxEngineRevFx    = f1 / self.realEngine.ratedRpm  
		self.mrGbMOverspeedRpmRatio = f2 / self.realEngine.ratedRpm
	end
	
	if self.mrGbMMaxEngineRevFx < 1 then
		print("Error: <vehicle><gearboxMogli maxRpm must be greater than <vehicle><realEngine ratedRpm")
		if self.mrGbMOverspeedRpmRatio > 1 then
			self.mrGbMMaxEngineRevFx = 0.5 * ( self.mrGbMOverspeedRpmRatio + 1 )
		else
			self.mrGbMMaxEngineRevFx = 1 + 100 / self.realEngine.ratedRpm  
		end
		print("Error: new value: maxRpm=%4.0f",self.mrGbMMaxEngineRevFx * self.realEngine.ratedRpm )
	end
	
	if self.mrGbMOverspeedRpmRatio <= self.mrGbMMaxEngineRevFx then
		print("Error: <vehicle><gearboxMogli overspeedRpm must be greater than maxRpm")
		self.mrGbMOverspeedRpmRatio = 2 * self.mrGbMMaxEngineRevFx - 1
		print("Error: new value: maxRpm=%4.0f",self.mrGbMOverspeedRpmRatio * self.realEngine.ratedRpm )
	end
	
	self.mrGbMGears = {} 
	local i = 0 
	while true do
		local baseName = xmlString .. string.format(".gears.gear(%d)", i) 		
		local speed    = getXMLFloat(xmlFile, baseName .. "#speed") 
		if speed==nil then
			break 
		end 
		i = i + 1 
		local name  = Utils.getNoNil(getXMLString(xmlFile, baseName .. "#name"), tostring(i)) 
		local newGear = {speed=speed/3.6,name=name} 
		table.insert(self.mrGbMGears, newGear)  -- m/s
	end 	
	
	self.mrGbMRanges = {} 
	local i = 0 
	local generateNames = true 
	while true do
		local baseName = xmlString .. string.format(".ranges.range(%d)", i) 		
		local ratio = getXMLFloat(xmlFile, baseName .. "#ratio") 
		if ratio==nil then
			break 
		end 
		i = i + 1 
		
		local name = getXMLString(xmlFile, baseName .. "#name") 
		if name == nil then
			name = "G"..tostring(i) 
		else
			generateNames = false 
		end
		
		local newRange = {ratio=ratio,name=name} 
		table.insert(self.mrGbMRanges, newRange)  -- m/s
	end 	
	
	if generateNames then
		if     table.getn(self.mrGbMRanges) == 1 then
			self.mrGbMRanges[1].name = "" 
		elseif table.getn(self.mrGbMRanges) == 2 then
			self.mrGbMRanges[1].name = "L" 
			self.mrGbMRanges[2].name = "H" 
		elseif table.getn(self.mrGbMRanges) == 3 then
			self.mrGbMRanges[1].name = "L" 
			self.mrGbMRanges[2].name = "M" 
			self.mrGbMRanges[3].name = "H" 
		elseif table.getn(self.mrGbMRanges) == 4 then
			self.mrGbMRanges[1].name = "S" 
			self.mrGbMRanges[2].name = "L" 
			self.mrGbMRanges[3].name = "M" 
			self.mrGbMRanges[4].name = "H" 
		end
	end
	
	self.mrGbMReverseRatio            = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. ".reverse#ratio"), 1) 
	self.mrGbMReverseResetGear        = Utils.getNoNil(getXMLBool(xmlFile, xmlString .. ".reverse#resetGear"), true) 
	self.mrGbMReverseResetRange       = Utils.getNoNil(getXMLBool(xmlFile, xmlString .. ".reverse#resetRange"), true) 
	self.mrGbMReverseMinGear          = math.max( Utils.getNoNil(getXMLInt(xmlFile, xmlString .. ".reverse#minGear"), 1), 1) 
	self.mrGbMReverseMaxGear          = math.min( Utils.getNoNil(getXMLInt(xmlFile, xmlString .. ".reverse#maxGear"), table.getn(self.mrGbMGears)), table.getn(self.mrGbMGears)) 
	self.mrGbMReverseMinRange         = math.max( Utils.getNoNil(getXMLInt(xmlFile, xmlString .. ".reverse#minRange"), 1), 1) 
	self.mrGbMReverseMaxRange         = math.min( Utils.getNoNil(getXMLInt(xmlFile, xmlString .. ".reverse#maxRange"), table.getn(self.mrGbMRanges)), table.getn(self.mrGbMRanges)) 
	
	--RealisticUtils.testClass("mrGearboxMogli - mrGbMGears", self.mrGbMGears) 
	
	self.mrGbMDefaultGear     = Utils.getNoNil(getXMLInt(xmlFile, xmlString .. ".gears#defaultGear"), 1) 
	self.mrGbMDefaultGear0    = self.mrGbMDefaultGear 
	self.mrGbMDefaultRange    = Utils.getNoNil(getXMLInt(xmlFile, xmlString .. ".ranges#defaultRange"), table.getn(self.mrGbMRanges)) 
	self.mrGbMDefaultRange0   = self.mrGbMDefaultRange 
	self.mrGbMRangeGearOffset = Utils.getNoNil(getXMLInt(xmlFile, xmlString .. ".ranges#gearOffset"), 0) 
	self.mrGbMGearRangeOffset = Utils.getNoNil(getXMLInt(xmlFile, xmlString .. ".gears#rangeOffset"), 0) 

	self.mrGbMAutoShiftTimeout   = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. ".gears#autoShiftTimeout"), 2000 ) 
	self.mrGbMAutoShiftTimeout2  = Utils.getNoNil(getXMLFloat(xmlFile, xmlString .. ".gears#autoShiftTimeout2"), 500 ) 
	self.mrGbMAutoShiftUpTimer   = 0
	self.mrGbMAutoShiftDownTimer = 0
	
	local f
	f = getXMLFloat(xmlFile, xmlString .. ".gears#autoUpRpm") 
	if f ~= nil then
		self.mrGbMAutoShiftUpRpmRatio = f / self.realEngine.ratedRpm
	end
	f = getXMLFloat(xmlFile, xmlString .. ".gears#autoDownRpm") 
	if f ~= nil then
		self.mrGbMAutoShiftDownRpmRatio = f / self.realEngine.ratedRpm
	end
	
	self.mrGbMAutoShiftMinMaxFactor = 1
	if self.mrGbMAutoShiftUpRpmRatio  ~= nil and self.mrGbMAutoShiftDownRpmRatio ~= nil then
		self.mrGbMAutoShiftMinMaxFactor = self.mrGbMAutoShiftUpRpmRatio / self.mrGbMAutoShiftDownRpmRatio 
	end
	
	self.mrGbMIsOn = false 
	self.mrGbMGearShiftingNeeded = false 
	self.mrGbMGearShiftingTime   = 0 
	self.mrGbMClutchShiftingTime = 0 
	self.mrGbMReverseActive      = false 	
	self.mrGbMNeutralActive      = true 	
	self.mrGbMClutchPressed      = false 
	self.mrGbMLastMinThrottle    = self.mrGbMIdleRpmRatio 
	self.mrGbMLastMaxThrottle    = 1
	self.mrGbMLastMaxThrottleS   = 0.9
	self.mrGbMLastMaxThrottleSG  = {}
	self.mrGbMLastEngineRpm      = self.realEngine.idleRpm 
	self.mrGbMLastMotorLoad      = 0 
	self.mrGbMLastForceFx        = 1
	self.mrGbMEngineRpmMinus     = - self.realEngine.ratedRpm / self.realEngine.revDownTimeMs 
	self.mrGbMEngineRpmPlus      =   self.realEngine.ratedRpm / self.realEngine.revUpTimeMs 
	self.mrGbMMinClutchPercent   = 0.01 
	
	self.mrGbMDrawClutch = 0 
  self.mrGbMDrawLoad   = 0   
  self.mrGbMDrawSpeed  = 0 
	self.mrGbMDrawFuel   = 0 
    
	self.mrGbMLastSumDt      = 0 
	self.mrGbMLastDrawClutch = 0 
  self.mrGbMLastDrawLoad   = 0   
  self.mrGbMLastDrawSpeed  = 0 
	
	self.mrGbMDirtyFlag      = self:getNextDirtyFlag() 
    
	
	self.mrGbMCurrentGear  = self.mrGbMDefaultGear 
	self.mrGbMCurrentRange = self.mrGbMDefaultRange  -- 1=forward low range, 2 = forward high range, -1 = reverse
	self.mrGbMMinGear      = 1  -- 1 = first gear
	self.mrGbMMaxGear      = table.getn(self.mrGbMGears)  -- to be set each time we switch from reverse/forward
	self.mrGbMMinRange     = 1  -- 1 = first gear
	self.mrGbMMaxRange     = table.getn(self.mrGbMRanges)  -- to be set each time we switch from reverse/forward
	
	self.mrGbMCurrentRpmRatio    = self.mrGbMIdleRpmRatio 
	self.mrGbMAutomatic          = self.mrGbMAutoShiftUpRpmRatio ~= nil or self.mrGbMAutoShiftDownRpmRatio ~= nil 
	self.mrGbMClutchPercent      = self.mrGbMMinClutchPercent 
	
	self.mrGbMOnSetState = {} 
	self.mrGbMOnSetState.mrGbMNeutralActive = mrGearboxMogli.mrGbMOnSetNeutral 
	self.mrGbMOnSetState.mrGbMReverseActive = mrGearboxMogli.mrGbMOnSetReverse 
	self.mrGbMOnSetState.mrGbMCurrentGear   = mrGearboxMogli.mrGbMOnSetGear 
	self.mrGbMOnSetState.mrGbMCurrentRange  = mrGearboxMogli.mrGbMOnSetRange 
	self.mrGbMOnSetState.mrGbMIsOn          = mrGearboxMogli.mrGbMOnSetIsOn 
	
end 

function mrGearboxMogli:delete()    
end 

function mrGearboxMogli:mouseEvent(posX, posY, isDown, isUp, button)
end 

function mrGearboxMogli:keyEvent(unicode, sym, modifier, isDown)
end 

function mrGearboxMogli:readStream(streamId, connection)
	self.mrGbMIsOn              = streamReadBool(streamId) 
	self.mrGbMCurrentGear       = streamReadInt8(streamId) 
	self.mrGbMCurrentRange      = streamReadInt8(streamId) 
	self.mrGbMReverseActive     = streamReadBool(streamId) 
	self.mrGbMNeutralActive     = streamReadBool(streamId) 
	self.mrGbMAutomatic         = streamReadBool(streamId) 
	self.mrGbMClutchPressed     = streamReadBool(streamId) 
end 
 
function mrGearboxMogli:writeStream(streamId, connection)
	streamWriteBool(streamId, self.mrGbMIsOn) 	
	streamWriteInt8(streamId, self.mrGbMCurrentGear) 
	streamWriteInt8(streamId, self.mrGbMCurrentRange) 
	streamWriteBool(streamId, self.mrGbMReverseActive) 	
	streamWriteBool(streamId, self.mrGbMNeutralActive) 	
	streamWriteBool(streamId, self.mrGbMAutomatic) 	
	streamWriteBool(streamId, self.mrGbMClutchPressed) 	
end 

function mrGearboxMogli:update(dt)

	if self.mrGbMDisableT123 then
		self.realTransmissionMode.currentMode    = self.mrGbMTransmissionModeNum
		self.realTransmissionMode.switchPossible = false
	end
		
	if self:getIsActiveForInput(false) then
		if     self.mrGbMNeutralActive then
			if self.mrGbMReverseActive then
				self.realTransmissionMode.modes[self.mrGbMTransmissionModeNum].text = "neutral (R)" 	
			else
				self.realTransmissionMode.modes[self.mrGbMTransmissionModeNum].text = "neutral" 	
			end
		elseif self.mrGbMAutomatic then
			self.realTransmissionMode.modes[self.mrGbMTransmissionModeNum].text = "auto" 	
		else
			self.realTransmissionMode.modes[self.mrGbMTransmissionModeNum].text = "manual" 	
		end
	
		if self.mrGbMIsOn and self.realIsMotorStarted and g_gui.currentGui == nil and (self.isMouseActive == nil or not self.isMouseActive) then
			if     InputBinding.hasEvent(InputBinding.mrGearboxMogliNEUTRAL) then
				if self.mrGbMAutoShiftUpRpmRatio ~= nil or self.mrGbMAutoShiftDownRpmRatio ~= nil then
					if self.mrGbMNeutralActive == self.mrGbMAutomatic then
						self:mrGbMSetState( "mrGbMNeutralActive", not self.mrGbMNeutralActive ) 
						self:mrGbMSetAutomatic( true ) 
					else
						self:mrGbMSetAutomatic( not self.mrGbMAutomatic ) 
					end					
				else	
					self:mrGbMSetState( "mrGbMNeutralActive", not self.mrGbMNeutralActive ) 
				end
			elseif InputBinding.hasEvent(InputBinding.mrGearboxMogliREVERSE) then			
				self:mrGbMSetState( "mrGbMReverseActive", not self.mrGbMReverseActive ) 
			elseif InputBinding.hasEvent(InputBinding.mrGearboxMogliSHIFTRANGEUP) then -- high/low range shift
				self:mrGbMSetRange(self.mrGbMCurrentRange+1)                                        
			elseif InputBinding.hasEvent(InputBinding.mrGearboxMogliSHIFTRANGEDOWN) then -- high/low range shift
				self:mrGbMSetRange(self.mrGbMCurrentRange-1) 
			elseif InputBinding.hasEvent(InputBinding.mrGearboxMogliSHIFTGEARUP) then
				self:mrGbMSetGear(self.mrGbMCurrentGear+1) 
			elseif InputBinding.hasEvent(InputBinding.mrGearboxMogliSHIFTGEARDOWN) then
				self:mrGbMSetGear(self.mrGbMCurrentGear-1) 	
			end 
			
			self:mrGbMSetState( "mrGbMClutchPressed", InputBinding.isPressed(InputBinding.mrGearboxMogliCLUTCH) ) 		
		end 
	end 
		
--**********************************************************************************************************		
--**********************************************************************************************************		
	if self.isServer and self.isActive and self.mrGbMIsOn then	
		
		self.realParkbrakeIsManual    = true 
		self.realParkbrakeIsActive    = false 
		self.realClutchEngaged        = true 				
		self.realThrottleIsManual     = false 
		self.realThrottleOnlyManual   = false 
		self.realThrottleCurrentValue = 0  
		if     self.mrGbMNeutralActive then
			self.realShuttleDirection = 0 
		elseif self.mrGbMReverseActive then	
			self.realShuttleDirection = -1 
		else
			self.realShuttleDirection = 1 
		end

		local wspd = math.max(0,self.realAvgMotorizedWheelSpd) 
		local currentEngineRpm = wspd * self.realEngine.ratedEngineRpmWheelSpeedRatio 
				
		-- get corrected current wheel rpm
		if self.mrGbMNeutralActive or self.realWantedAcceleration <= -0.01 then
			self.mrGbMLastEngineRpm = currentEngineRpm 
		else
		-- smooth
			self.mrGbMLastEngineRpm = self.mrGbMLastEngineRpm + Utils.clamp( currentEngineRpm - self.mrGbMLastEngineRpm, dt * self.mrGbMEngineRpmMinus, dt * self.mrGbMEngineRpmPlus ) 
		end 
		
		local currentRpmRatio  = currentEngineRpm / self.realEngine.ratedRpm		
		local currentRpmRatioS = self.mrGbMLastEngineRpm / self.realEngine.ratedRpm		
		local minRpm           = self.realEngine.idleRpm 
		
		-- minimum power => min rpm
		if self.realCurrentTotalPowerConsumption > 0 then
			local currentPowerConsumption = self.realCurrentTotalPowerConsumption / self.realPtoDriveEfficiency  -- do not make any difference between hydraulic and pto consumption

			local boostRatio = 1 
			if self.realPower > 0 then
				boostRatio = 1 + ( self.realCurrentPowerBoost + self.realCurrentPowerBoost2 ) / self.realPower 
			end
			
			local torque = self.realEngine.torqueCurve:get(minRpm) 
			--and now the power : |=> power (KW) = torque (Nm) * rpm / 9548.8
			local enginePower = boostRatio * torque * minRpm / 9548.8 
			
			while minRpm < self.realEngine.ratedRpm and enginePower < currentPowerConsumption do
				minRpm = minRpm + 50
				torque = self.realEngine.torqueCurve:get(minRpm) 
			--and now the power : |=> power (KW) = torque (Nm) * rpm / 9548.8
				enginePower = boostRatio * torque * minRpm / 9548.8 
			end
		end
		
		local minRpmRatio  = minRpm / self.realEngine.ratedRpm 		
					
--**********************************************************************************************************		
		if self.mrGbMGearShiftingNeeded then
		-- during gear shifting
			self.realEngine.idleRpmRatio  = minRpmRatio
			self.mrGbMCurrentRpmRatio     = Utils.clamp( self.mrGbMCurrentRpmRatio - dt/self.realEngine.revDownTimeMs, minRpmRatio, self.mrGbMMaxEngineRevFx ) 
			self.realThrottleIsManual     = true 
			self.realThrottleOnlyManual   = true 
			self.realThrottleCurrentValue = Utils.clamp( ( self.mrGbMCurrentRpmRatio - self.realEngine.idleRpmRatio ) / ( 1 - self.realEngine.idleRpmRatio ), 0, 1 )
		
			if self.time>=self.mrGbMGearShiftingTime then
				self.mrGbMGearShiftingNeeded = false 
				self.realClutchPercent       = self.mrGbMClutchPercent 
				if self.mrGbMGearShiftingNeeded2 then	
					self.mrGbMGearShiftingNeeded2 = false 
					self:mrGbMDoGearShift() 
				end 
			elseif self.mrGbMGearShiftingNeeded2 then	
				if self.realClutchPercent > 0 and self.time < self.mrGbMClutchShiftingTime then
					self.realClutchPercent =  Utils.clamp( ( self.mrGbMClutchShiftingTime - self.time )/self.mrGbMClutchShiftTime, 0, self.realClutchPercent ) 					
				else
					self.mrGbMGearShiftingNeeded2 = false 
					self.realClutchPercent = 0 
					self:mrGbMDoGearShift() 
				end 
			else
					self.realClutchPercent = 0  				
			end 
			
			local motorLoad         = self.realMotorThrottleForTools;
			self.mrGbMLastMotorLoad = Utils.clamp( self.mrGbMLastMotorLoad + 0.1 * ( motorLoad - self.mrGbMLastMotorLoad ), 0, 1 ) 
			
		elseif self.mrGbMNeutralActive
		    or ( currentRpmRatioS            <= minRpmRatio 
		     and self.realWantedAcceleration <= -0.01 ) then
		-- neutral or braking
			self.realShuttleDirection     = 0 			
			self.realEngine.idleRpmRatio  = minRpmRatio
			self.mrGbMCurrentRpmRatio     = minRpmRatio + self.lastAcceleration * ( self.mrGbMMaxEngineRevFx - minRpmRatio ) 
			self.realParkbrakeIsActive    = true 
			self.realClutchEngaged        = false 	
			self.realClutchPercent        = math.max(self.mrGbMMinClutchPercent, self.realClutchPercent -dt/self.mrGbMClutchEngagingTime ) 
			
			if     self.realSoundEngineRevFx > self.mrGbMOverspeedRpmRatio then
				self.realThrottleIsManual     = true 
				self.realThrottleOnlyManual   = true 
				self.realThrottleCurrentValue = 0
			elseif self.realSoundEngineRevFx > self.mrGbMMaxEngineRevFx then
				self.realThrottleIsManual     = true 
				self.realThrottleOnlyManual   = true 
				self.realThrottleCurrentValue = Utils.clamp( ( self.mrGbMMaxEngineRevFx - self.realEngine.idleRpmRatio ) / ( 1 - self.realEngine.idleRpmRatio ), 0, 1 )
			end
			
			local motorLoad         = self.realMotorThrottleForTools;
			self.mrGbMLastMotorLoad = Utils.clamp( self.mrGbMLastMotorLoad + 0.1 * ( motorLoad - self.mrGbMLastMotorLoad ), 0, 1 ) 
			
		else
--**********************************************************************************************************		
			local acc               = math.min(math.abs(self.realWantedAcceleration),self.mrGbMLastMaxThrottle);
			local motorLoad         = self.realMotorThrottleForTools + (1 - self.realMotorThrottleForTools) * acc * self.realRegulatorFxS;
			self.mrGbMLastMotorLoad = Utils.clamp( self.mrGbMLastMotorLoad + 0.1 * ( motorLoad - self.mrGbMLastMotorLoad ), 0, 1 ) 

			-- acceleration for idle/minimum rpm
			if self.realWantedAcceleration <= 0.1 or self.realSoundEngineRevFx < minRpmRatio then
				local delta     = self.realSoundEngineRevFx - minRpmRatio 
				local throttle  = Utils.clamp( 42 * delta, -1, 1 )^3  
				self.mrGbMLastMinThrottle = Utils.clamp( self.mrGbMLastMinThrottle - 0.01 * throttle, 0.05, math.min( minRpmRatio, 0.9 ) ) 
			end
			
			self.realEngine.idleRpmRatio  = math.min(self.mrGbMLastMinThrottle,self.mrGbMIdleRpmRatio) 
			self.realThrottleCurrentValue = Utils.clamp( ( self.mrGbMLastMinThrottle - self.realEngine.idleRpmRatio ) / ( 1 - self.realEngine.idleRpmRatio ), 0, 1 )
			self.realThrottleIsManual     = ( self.realThrottleCurrentValue > 0.01 ) and ( self.realWantedAcceleration < self.realThrottleCurrentValue )

			if self.mrGbMLastMaxThrottleS < self.mrGbMLastMinThrottle then
				self.mrGbMLastMaxThrottleS = math.min( 0.95, self.mrGbMLastMinThrottle )
			end
			
			-- speed limiter
			local maxThrottleFx = 0.05 * ( 0.3 + 0.0504 * self.realEngine.currentGearRatedSpeed )--0.00072 * self.realEngine.currentGearRatedSpeed^2 
			if self.realSoundEngineRevFx > 1 then
				local diff = 0
				--if     self.realSoundEngineRevFx > self.mrGbMOverspeedRpmRatio then
				--	diff = -1
				if     self.realSoundEngineRevFx > self.mrGbMMaxEngineRevFx then
				-- negative
					if self.mrGbMOverspeedRpmRatio <= self.mrGbMMaxEngineRevFx then
						diff = -1
					else
						diff = ( self.mrGbMMaxEngineRevFx - self.realSoundEngineRevFx ) / ( self.mrGbMOverspeedRpmRatio - self.mrGbMMaxEngineRevFx )
					end
				elseif self.mrGbMMaxEngineRevFx > 1 then
				-- positive
					diff = ( self.mrGbMMaxEngineRevFx - self.realSoundEngineRevFx ) / ( self.mrGbMMaxEngineRevFx - 1 )
				end
				
				diff = Utils.clamp( diff, -1.5, 1 )
				-- smooth
				diff = diff^3 
				self.mrGbMLastMaxThrottle = Utils.clamp( self.mrGbMLastMaxThrottle + maxThrottleFx * diff, self.mrGbMLastMaxThrottleS - 0.05, self.mrGbMLastMaxThrottleS + 0.05 )
			elseif self.realWantedAcceleration > self.mrGbMLastMaxThrottle then
				self.mrGbMLastMaxThrottle     = math.min( self.mrGbMLastMaxThrottle + maxThrottleFx, self.mrGbMLastMaxThrottleS + 0.05 )
			end

			if self.realWantedAcceleration > self.mrGbMLastMaxThrottle then
				self.realThrottleIsManual     = true 
				self.realThrottleOnlyManual   = true 
				self.realThrottleCurrentValue = self.mrGbMLastMaxThrottle
				
				if     self.mrGbMLastMaxThrottle > self.mrGbMLastMaxThrottleS and self.realSoundEngineRevFx < self.mrGbMMaxEngineRevFx then
					self.mrGbMLastMaxThrottleS  = Utils.clamp( self.mrGbMLastMaxThrottleS +  0.2 * ( self.mrGbMLastMaxThrottle - self.mrGbMLastMaxThrottleS ), 0.4, 0.95 )
				elseif self.realSoundEngineRevFx > 1 then
					self.mrGbMLastMaxThrottleS  = Utils.clamp( self.mrGbMLastMaxThrottleS + 0.05 * ( self.mrGbMLastMaxThrottle - self.mrGbMLastMaxThrottleS ), 0.4, 0.95 )
				else
					self.mrGbMLastMaxThrottleS  = Utils.clamp( self.mrGbMLastMaxThrottleS + 0.01 * ( self.mrGbMLastMaxThrottle - self.mrGbMLastMaxThrottleS ), 0.4, 0.95 )
				end
			end
			
			self.mrGbMCurrentRpmRatio  = currentRpmRatioS 
			--no auto parkbrake when a gear is engaged
			local factorFx     = self.mrGbMLastMotorLoad 
			local idleRpmRatio = minRpmRatio 
			
--**********************************************************************************************************		
			-- semi automatic transmission
			if      self.mrGbMAutomatic
					and not self.mrGbMClutchPressed then
													
				local diff = 0 
				local autoDownRpmRatio, autoUpRpmRatio = minRpmRatio, 1 
				
				if self.mrGbMAutoShiftDownRpmRatio ~= nil then
					if      factorFx                        <  1
							and self.mrGbMAutoShiftDownRpmRatio >  minRpmRatio then
						diff = (1 - factorFx) * ( self.mrGbMAutoShiftDownRpmRatio - minRpmRatio ) 
					end
				  autoDownRpmRatio  = math.max( minRpmRatio, self.mrGbMAutoShiftDownRpmRatio - diff ) 
				end 
				if self.mrGbMAutoShiftUpRpmRatio ~= nil then
					if      factorFx                        <  1
							and self.mrGbMAutoShiftDownRpmRatio ~= 0 
							and self.mrGbMAutoShiftUpRpmRatio   >  minRpmRatio * self.mrGbMAutoShiftMinMaxFactor then
						diff = (1 - factorFx) * ( self.mrGbMAutoShiftUpRpmRatio - minRpmRatio * self.mrGbMAutoShiftMinMaxFactor ) 
					end
					autoUpRpmRatio  = math.min( 1, self.mrGbMAutoShiftUpRpmRatio - diff ) 
				end 
				
				-- shift down					
				if 			self.mrGbMAutoShiftDownRpmRatio ~= nil 
						and self.mrGbMCurrentGear           > self.mrGbMMinGear 
						and ( currentRpmRatioS              < minRpmRatio
						   or ( self.time                   > self.mrGbMAutoShiftDownTimer 
								and self.realWantedAcceleration > 0.1 
								and currentRpmRatioS            < autoDownRpmRatio )) then
					self:mrGbMSetGear(self.mrGbMCurrentGear-1) 
				
				-- shift up				
				elseif  self.mrGbMAutoShiftUpRpmRatio   ~= nil 
						and self.mrGbMCurrentGear           < self.mrGbMMaxGear
						and ( currentRpmRatioS              > 1
							 or ( self.time                   > self.mrGbMAutoShiftUpTimer 	
								and self.realWantedAcceleration > 0.1 
								and currentRpmRatioS            > autoUpRpmRatio )) then
					self:mrGbMSetGear(self.mrGbMCurrentGear+1) 
				end
			end

--**********************************************************************************************************		
			--local targetClutchPercent = self:mrGbMGetClutchPercent( math.max( self.mrGbMOpenRpmRatio , minRpmRatio ), math.max( self.mrGbMCloseRpmRatio, minRpmRatio )) 
			local targetClutchPercent = 1 
			if self.mrGbMOverspeedProtection and currentRpmRatio > self.mrGbMMaxEngineRevFx then
				targetClutchPercent = Utils.clamp( (self.mrGbMOverspeedRpmRatio - currentRpmRatio) / (self.mrGbMOverspeedRpmRatio - self.mrGbMMaxEngineRevFx), 0.1, 1 )
			else
				targetClutchPercent = self:mrGbMGetClutchPercent( math.max( self.mrGbMOpenRpmRatio , minRpmRatio ), math.max( self.mrGbMCloseRpmRatio, minRpmRatio )) 
				diff = targetClutchPercent - self.realClutchPercent 
				if -0.25 < diff and diff < 0.25 then
					targetClutchPercent = self.realClutchPercent + 16 * diff^3 
				end
			end

			if targetClutchPercent < self.realClutchPercent then
				self.realClutchPercent = math.max(self.mrGbMMinClutchPercent, self.realClutchPercent - math.min( dt/self.mrGbMClutchEngagingTime, self.realClutchPercent - targetClutchPercent ) ) 
			else
				self.realClutchPercent = math.min(  1, self.realClutchPercent + math.min( dt/self.mrGbMClutchEngagingTime, targetClutchPercent - self.realClutchPercent ) ) 
			end 
			
			-- over speed protection: release clutch and calculate acc to keep max rpm
			if self.mrGbMOverspeedProtection and currentRpmRatio > self.mrGbMMaxEngineRevFx and self.realClutchPercent <= 0.99 then
				local throttle = ( self.mrGbMMaxEngineRevFx - self.realClutchPercent * currentRpmRatio ) / ( 1 - self.realClutchPercent )
				throttle       = Utils.clamp( ( throttle - self.realEngine.idleRpmRatio ) / ( 1 - self.realEngine.idleRpmRatio ), 0, 1 )
				self.realThrottleIsManual     = true 
				self.realThrottleOnlyManual   = true 
				self.realThrottleCurrentValue = Utils.clamp( throttle, 0, 1 ) 
			end 
		end 			
	end 	
--**********************************************************************************************************		
--**********************************************************************************************************		
end 

function mrGearboxMogli:mrGbMGetClutchPercent( openRpmRatio, closeRpmRatio, smooth )

	local minPercent, clutchPercent = self.mrGbMMinClutchPercent, 1 
	
	if self.mrGbMClutchPressed then
		return minPercent 
	end

	local wheels   = math.max(0, self.realAvgMotorizedWheelSpd ) / self.realEngine.currentGearRatedSpeed 
	local target   = math.max(self.mrGbMIdleRpmRatio, closeRpmRatio) 
	local throttle = math.max(self.realEngine.idleRpmRatio, self.lastAcceleration) 
	
	if self.realWantedAcceleration <= 0.01 and wheels <= openRpmRatio then
	-- open clutch because of very low speed
		clutchPercent = minPercent 
	elseif throttle >= wheels + 0.01 then
	-- calculate clutch to match target and engineRevFx
		clutchPercent = ( throttle - target ) / ( throttle - wheels ) 
	else
		clutchPercent = 1 
	end
	
	if self.realSoundEngineRevFx > openRpmRatio then
	-- keep clutch closed above open rpm ratio
		minPercent = self.realClutchPercent 
	end 
	
	if     clutchPercent < minPercent then
		clutchPercent = minPercent
	elseif clutchPercent > 1 then
		clutchPercent = 1
	end
	
	if smooth ~= nil and smooth > 0 and smooth <= 1 then
		clutchPercent = self.realClutchPercent + smooth * ( clutchPercent - self.realClutchPercent ) 
	end
	
	return clutchPercent 
end 

function mrGearboxMogli:mrGbMDoGearShift()
	if self.isServer then
		local oldI, newI
		if self.realEngine.currentGearRatedSpeed ~= nil then
			oldI = math.floor( self.realEngine.currentGearRatedSpeed *3.6 + 0.5 )
		end
		local gearMaxSpeed = self.mrGbMGears[self.mrGbMCurrentGear].speed * self.mrGbMRanges[self.mrGbMCurrentRange].ratio
		if self.mrGbMNeutralActive then
			self.realShuttleDirection  = 0 
			self.realClutchEngaged     = false 
			self.realParkbrakeIsManual = false 
		else
			if self.mrGbMReverseActive then	
				self.realShuttleDirection = -1 
				gearMaxSpeed = gearMaxSpeed * self.mrGbMReverseRatio 
			else
				self.realShuttleDirection = 1 
			end
		end
		RealisticMotorized.setManualGear3(self, true, gearMaxSpeed) 	
		
		newI = math.floor( gearMaxSpeed *3.6 + 0.5 )
		if oldI ~= nil and oldI > 0 then
			self.mrGbMLastMaxThrottleSG[oldI] = self.mrGbMLastMaxThrottleS
		end
		if self.mrGbMLastMaxThrottleSG[newI] ~= nil then
			self.mrGbMLastMaxThrottleS = self.mrGbMLastMaxThrottleSG[newI]
		end
	end 
end 

function mrGearboxMogli:updateTick(dt)

	if self.isActive then
		if self.isServer then
			if self.isAITractorActivated then
				self:mrGbMSetState( "mrGbMIsOn", false ) 
			elseif  self.realIsMotorStarted 
					and self.motor.speedLevel == 0 
					and self.realTransmissionMode.currentMode==self.mrGbMTransmissionModeNum then
				self:mrGbMSetState( "mrGbMIsOn", true ) 
			else		
				self:mrGbMSetState( "mrGbMIsOn", false ) 
			end 	
		
			if self.mrGbMIsOn then	
				self.mrGbMLastSumDt = self.mrGbMLastSumDt + dt
			end
			
			if self.mrGbMLastSumDt > 200 then
				self.mrGbMLastSumDt = 0
				self.mrGbMDrawClutch = tonumber( math.floor(self.realClutchPercent*10+0.5)*10 ) 
				self.mrGbMDrawLoad   = tonumber( math.floor(Utils.getNoNil(self.mrGbMLastMotorLoad,0)*10+0.5)*10 ) 			
				if self.mrGbMAutoShiftUpRpmRatio ~= nil or self.mrGbMAutoShiftDownRpmRatio ~= nil then
					self.mrGbMDrawSpeed  = tonumber( math.floor(self.realEngine.currentGearRatedSpeed * 3.6 + 0.5 ) ) 
				else
					self.mrGbMDrawSpeed  = 0
				end

				if     self.mrGbMLastDrawClutch ~= self.mrGbMDrawClutch
						or self.mrGbMLastDrawLoad   ~= self.mrGbMDrawLoad   
						or self.mrGbMLastDrawSpeed  ~= self.mrGbMDrawSpeed 
						then
					self:raiseDirtyFlags(self.mrGbMDirtyFlag) 
				
					self.mrGbMLastDrawClutch = self.mrGbMDrawClutch
					self.mrGbMLastDrawLoad   = self.mrGbMDrawLoad   
					self.mrGbMLastDrawSpeed  = self.mrGbMDrawSpeed 
				end 
			end 
		end
		if self.mrGbMLastFuelFillLevel == nil then
			self.mrGbMLastFuelFillLevel = self.fuelFillLevel
			self.mrGbMDrawFuel          = 0
			self.mrGbMLastFuelFillDt    = dt
		else
		--fuelUsed = fuelFactor * self.realMaxFuelUsage * dt/(1000 * 3600);
			local fuelUsed = self.mrGbMLastFuelFillLevel - self.fuelFillLevel
			self.mrGbMLastFuelFillLevel = self.fuelFillLevel
			self.mrGbMDrawFuel          = fuelUsed * (1000 * 3600) / self.mrGbMLastFuelFillDt
			self.mrGbMLastFuelFillDt    = dt
		end
	end
end 

function mrGearboxMogli:readUpdateStream(streamId, timestamp, connection)
  if connection:getIsServer() then
		if streamReadBool( streamId ) then
			self.mrGbMDrawClutch = streamReadUIntN( streamId ) 
			self.mrGbMDrawLoad   = streamReadUIntN( streamId )  
			self.mrGbMDrawSpeed  = streamReadUIntN( streamId ) 
		end 
  end 
end 

function mrGearboxMogli:writeUpdateStream(streamId, connection, dirtyMask)
  if not connection:getIsServer() then
		if streamWriteBool(streamId, bitAND(dirtyMask, self.mrGbMDirtyFlag) ~= 0) then	
			streamWriteUIntN(streamId, self.mrGbMDrawClutch ) 
			streamWriteUIntN(streamId, self.mrGbMDrawLoad   ) 
			streamWriteUIntN(streamId, self.mrGbMDrawSpeed  ) 
		end 
	end 
end 

function mrGearboxMogli:draw() 	
	
	if self.mrGbMIsOn then
		
		if self.mrGbMDisableT123  then
			setTextBold(true);
			setTextAlignment(RenderText.ALIGN_RIGHT);
			local transText = self.realTransmissionMode.modes[self.realTransmissionMode.currentMode].text;
			setTextColor(0.0, 0.0, 0.0, 0.75);
			renderText(0.974, 0.730-0.0015, 0.024, transText);			
			setTextColor(1, 0.89, 0.267, 1.0);
			renderText(0.974, 0.730, 0.024, transText);		
		end;
		
		setTextBold(false) 
		setTextAlignment(RenderText.ALIGN_LEFT) 
		setTextColor(1, 1, 1, 1) 
		
		local gearText = self.mrGbMRanges[self.mrGbMCurrentRange].name .." ".. self.mrGbMGears[self.mrGbMCurrentGear].name
		local drawY0   = 0.706
		local deltaY   = 0.02
		local drawY    = drawY0
		
		renderText(0.85, drawY, deltaY, gearText) 			     
		drawY = drawY - deltaY; renderText(0.85, drawY, deltaY, "Rpm...................")
		drawY = drawY - deltaY; renderText(0.85, drawY, deltaY, "Clutch................")
		drawY = drawY - deltaY; renderText(0.85, drawY, deltaY, "Load..................")
		drawY = drawY - deltaY; renderText(0.85, drawY, deltaY, "Fuel used.............")
		
		setTextAlignment(RenderText.ALIGN_RIGHT) 
		
		drawY    = drawY0 
		
		if self.mrGbMDrawSpeed > 0 then
			renderText(0.99,drawY,deltaY, string.format("%3.1f km/h", self.mrGbMDrawSpeed ))
		end
		drawY = drawY - deltaY; renderText(0.99, drawY, deltaY, string.format("%4.0f", math.floor(self.realSoundEngineRevFx*self.realEngine.ratedRpm*0.1+0.5)*10)) 
		drawY = drawY - deltaY; renderText(0.99, drawY, deltaY, string.format("%3d %%", self.mrGbMDrawClutch )) 
		drawY = drawY - deltaY; renderText(0.99, drawY, deltaY, string.format("%3d %%", self.mrGbMDrawLoad )) 	
		drawY = drawY - deltaY; renderText(0.99, drawY, deltaY, string.format("%3d l/h", self.mrGbMDrawFuel ))  
		                                                                                                                                  
		
	--if self.isServer then
	--	drawY = drawY - deltaY; renderText(0.85, drawY, deltaY, string.format("minThrottle : %3.0f %%", self.mrGbMLastMinThrottle*100)) 
	--	drawY = drawY - deltaY; renderText(0.85, drawY, deltaY, string.format("maxThrottle : %3.0f %%", self.mrGbMLastMaxThrottle*100))
	--	drawY = drawY - deltaY; renderText(0.85, drawY, deltaY, string.format("maxThrottleS : %3.0f %%", self.mrGbMLastMaxThrottleS*100))
	--end 
	
	elseif self.mrGbMDisableT123  then
		setTextBold(true);
		setTextAlignment(RenderText.ALIGN_RIGHT);
		local transText
		if self.isAITractorActivated then
			transText = "AI"
		elseif not ( self.realIsMotorStarted ) then
			transText = "off"
		elseif self.motor.speedLevel ~= 0 then
			transText = "cruise control"
		else		
			transText = "?"
		end 	
		setTextColor(0.0, 0.0, 0.0, 0.75);
		renderText(0.974, 0.730-0.0015, 0.024, transText);			
		setTextColor(1, 0.89, 0.267, 1.0);
		renderText(0.974, 0.730, 0.024, transText);		
	end;

	setTextAlignment(RenderText.ALIGN_LEFT) 
	setTextBold(false);
	
end 

function mrGearboxMogli:getSaveAttributesAndNodes(nodeIdent)

	local attributes = ""

	attributes = attributes.." mrGbMCurrentGear=\""  .. tostring(self.mrGbMCurrentGear  ) .. "\""
	attributes = attributes.." mrGbMCurrentRange=\"" .. tostring(self.mrGbMCurrentRange ) .. "\""

	return attributes
end 

function mrGearboxMogli:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)

	local i
	
	i = getXMLInt(xmlFile, key .. "#mrGbMCurrentGear" )
	if i ~= nil then
		self.mrGbMCurrentGear = i
		self.mrGbMDefaultGear = i
	end

	i = getXMLInt(xmlFile, key .. "#mrGbMCurrentRange" )
	if i ~= nil then
		self.mrGbMCurrentRange = i
		self.mrGbMDefaultRange = i
	end
end 


function mrGearboxMogli:mrGbMSetGear(newGear, noEventSend)
	local new = Utils.clamp( newGear, self.mrGbMMinGear, self.mrGbMMaxGear ) 
	local old = self.mrGbMCurrentGear 
	self:mrGbMSetState( "mrGbMCurrentGear", new, noEventSend ) 		

	local newRange = self.mrGbMCurrentRange 
	if     new > old then
		newRange = Utils.clamp( self.mrGbMCurrentRange - self.mrGbMGearRangeOffset, self.mrGbMMinRange, self.mrGbMMaxRange ) 
	elseif new < old then
		newRange = Utils.clamp( self.mrGbMCurrentRange + self.mrGbMGearRangeOffset, self.mrGbMMinRange, self.mrGbMMaxRange ) 
	end 
	
	if newRange ~= self.mrGbMCurrentRange then
		self:mrGbMSetState( "mrGbMCurrentRange", newRange, noEventSend ) 
	end 
end 

function mrGearboxMogli:mrGbMSetRange(newRange, noEventSend)
	local new = Utils.clamp( newRange, self.mrGbMMinRange, self.mrGbMMaxRange ) 
	local old = self.mrGbMCurrentRange 
	self:mrGbMSetState( "mrGbMCurrentRange", new, noEventSend ) 		

	local newGear = self.mrGbMCurrentGear 
	if     new > old then
		newGear = Utils.clamp( self.mrGbMCurrentGear - self.mrGbMRangeGearOffset, self.mrGbMMinGear, self.mrGbMMaxGear ) 
	elseif new < old then
		newGear = Utils.clamp( self.mrGbMCurrentGear + self.mrGbMRangeGearOffset, self.mrGbMMinGear, self.mrGbMMaxGear ) 
	end 		

	if newGear ~= self.mrGbMCurrentGear then
		self:mrGbMSetState( "mrGbMCurrentGear", newGear, noEventSend ) 
	end 
end 

function mrGearboxMogli:mrGbMSetAutomatic( value, noEventSend )
	local new = false 
	if value and ( self.mrGbMAutoShiftUpRpmRatio ~= nil or self.mrGbMAutoShiftDownRpmRatio ~= nil ) then
		new = true 
	end 
	self:mrGbMSetState( "mrGbMAutomatic", new, noEventSend ) 		
end 

function mrGearboxMogli:mrGbMPrepareGearShift( timeToShift, clutchPercent )
	if self.isServer then
		self.mrGbMGearShiftingNeeded  = true 
		self.mrGbMGearShiftingNeeded2 = true 
		self.mrGbMClutchShiftingTime  = math.max( self.mrGbMClutchShiftingTime, self.time + self.mrGbMClutchShiftTime ) 
		self.mrGbMGearShiftingTime    = math.max( self.mrGbMGearShiftingTime, self.time + timeToShift ) 
		self.mrGbMClutchPercent       = math.min( self.realClutchPercent, clutchPercent ) 
	end 
end

function mrGearboxMogli:debugEvent( old, new, noEventSend )
	local i = 2 
	local info 
	print("------------------------------------------------------------------------") 
	while i <= 10 do
		info = debug.getinfo(i) 
		if info == nil then break end
		print(string.format("%i: %s (%i): %s", i, info.short_src, Utils.getNoNil(info.currentline,0), Utils.getNoNil(info.name,"<???>"))) 
		i = i + 1 
	end
	if info ~= nil and info.name ~= nil and info.currentline ~= nil then
		print("...") 
	end
	print("------------------------------------------------------------------------") 
	print(tostring(old).." "..tostring(new).." "..tostring(noEventSend)) 
end 

function mrGearboxMogli:mrGbMOnSetReverse( old, new, noEventSend )

	self.mrGbMReverseActive = new 
	--timer to shift the "reverse/forward"
	mrGearboxMogli.mrGbMPrepareGearShift( self, self.mrGbMGearTimeToShiftReverse, self.mrGbMClutchAfterShiftReverse ) 

	if self.mrGbMReverseActive then
		self.mrGbMMinGear  = self.mrGbMReverseMinGear
		self.mrGbMMaxGear  = self.mrGbMReverseMaxGear
		self.mrGbMMinRange = self.mrGbMReverseMinRange
		self.mrGbMMaxRange = self.mrGbMReverseMaxRange
	else
		self.mrGbMMinGear  = 1
		self.mrGbMMaxGear  = table.getn(self.mrGbMGears) 
		self.mrGbMMinRange = 1
		self.mrGbMMaxRange = table.getn(self.mrGbMRanges) 
	end 
	
	local default = self.mrGbMCurrentGear
	if self.mrGbMReverseResetGear then
		default = self.mrGbMDefaultGear
	end
	
	self:mrGbMSetState( "mrGbMDefaultGear", self.mrGbMCurrentGear, noEventSend ) 
	self:mrGbMSetState( "mrGbMCurrentGear", Utils.clamp( default, self.mrGbMMinGear, self.mrGbMMaxGear ), noEventSend ) 
	
	local default = self.mrGbMCurrentRange
	if self.mrGbMReverseResetRange then
		default = self.mrGbMDefaultRange
	end

	self:mrGbMSetState( "mrGbMDefaultRange", self.mrGbMCurrentRange, noEventSend ) 
	self:mrGbMSetState( "mrGbMCurrentRange", Utils.clamp( default, self.mrGbMMinRange, self.mrGbMMaxRange ), noEventSend ) 

	if self.isServer then
		self.mrGbMAutoShiftDownTimer = self.time + self.mrGbMAutoShiftTimeout 
		self.mrGbMAutoShiftUpTimer   = self.time + self.mrGbMAutoShiftTimeout 
	end 
end 
		
function mrGearboxMogli:mrGbMOnSetNeutral( old, new, noEventSend )		
	self.mrGbMNeutralActive = new 
	mrGearboxMogli.mrGbMPrepareGearShift( self, self.mrGbMGearTimeToShiftHl, self.mrGbMClutchAfterShiftHl ) 
end 

function mrGearboxMogli:mrGbMOnSetRange( old, new, noEventSend )
		
	self.mrGbMCurrentRange = new

	--timer to shift the "range"
	mrGearboxMogli.mrGbMPrepareGearShift( self, self.mrGbMGearTimeToShiftHl, self.mrGbMClutchAfterShiftHl ) 
	
	if self.isServer then
		self.mrGbMAutoShiftDownTimer = 0
		self.mrGbMAutoShiftUpTimer   = 0
	end 
end 

function mrGearboxMogli:mrGbMOnSetGear( old, new, noEventSend )

	if     new > self.mrGbMCurrentGear then
		if self.isServer then
			self.mrGbMAutoShiftDownTimer = self.time + self.mrGbMAutoShiftTimeout 
			self.mrGbMAutoShiftUpTimer   = self.time + self.mrGbMAutoShiftTimeout2
		end 
	elseif new < self.mrGbMCurrentGear then                                              
		if self.isServer then
			self.mrGbMAutoShiftDownTimer = self.time + self.mrGbMAutoShiftTimeout2
			self.mrGbMAutoShiftUpTimer   = self.time + self.mrGbMAutoShiftTimeout 
		end 
	end			
	self.mrGbMCurrentGear = new
	
	--timer to set the gear
	mrGearboxMogli.mrGbMPrepareGearShift( self, self.mrGbMGearTimeToShiftGear, self.mrGbMClutchAfterShiftGear ) 
end 		

function mrGearboxMogli:mrGbMOnSetIsOn( old, new, noEventSend )


	self.mrGbMIsOn = new 
	
	if self.isServer then
		if self.mrGbMIsOn then
			self.realDirectInverser         = false 
			self.realShuttleIsManual        = true 
			self.realUseDefaultShuttle      = false 
			self.realClutchEngaged          = true 
			self.realClutchPercent          = 1 		
			self.realTransmissionEfficiency = self.mrGbMTransmissionEfficiency 
				
			if self.realShuttleDirection<0 then		
				self:mrGbMSetState( "mrGbMReverseActive", true, noEventSend )  -- first gear, H range, reverse
			else
				self:mrGbMSetState( "mrGbMReverseActive", false, noEventSend )  -- first gear, H range, forward
			end 
			self:mrGbMDoGearShift() 
		else
			self:mrGbMSetState( "mrGbMDefaultGear", self.mrGbMCurrentGear, noEventSend ) 
			self:mrGbMSetState( "mrGbMDefaultRange", self.mrGbMCurrentRange, noEventSend ) 
			self.mrGbMGearShiftingNeeded    = false 
			self.realClutchEngaged          = true 	
			self.realClutchPercent          = 1 		
			RealisticMotorized.setManualGear3(self, false) 
			self.realTransmissionEfficiency = self.mrGbMTransmissionEfficiencyBackup 
			self.realThrottleIsManual       = false 
			self.realThrottleOnlyManual     = false 
			if self.mrGbMIdleRpmRatio          ~= nil then self.realEngine.idleRpmRatio    = self.mrGbMIdleRpmRatio                  end 
			if self.realTransmissionEfficiency ~= nil then self.realTransmissionEfficiency = self.mrGbMTransmissionEfficiencyBackup  end 
		end 
	end 
	
	self.realParkbrakeIsManual = false 
	
end 

function mrGearboxMogli:mrGbMSetState(level1, value, noEventSend)
	
	if self[level1] == nil or self[level1] ~= value then
	
		local valueEvent, valueNew 
		
		if value== true then
			valueEvent = "true"
		elseif value==false then
			valueEvent = "false"
		elseif value==nil then
			valueEvent = "nil"
		elseif value ~= "true" and value ~= "false" then
			valueEvent = string.format("%f", value)
		else
			valueEvent = value 
		end
		
		if valueEvent== "true" then
			valueNew = true
		elseif valueEvent=="false" then
			valueNew = false
		elseif valueEvent=="nil" then
			valueNew = nil
		elseif valueEvent ~= true and valueEvent ~= false then
			valueNew = valueEvent * 1.0
		else
			valueNew = valueEvent 
		end
	
		if noEventSend == nil or noEventSend == false then
			if g_server ~= nil then 
				g_server:broadcastEvent(mrGearboxMogliEvent:new(self, level1, valueEvent), nil, nil, object) 
			else
				g_client:getServerConnection():sendEvent(mrGearboxMogliEvent:new(self, level1, valueEvent)) 
			end 
		end 						
	
		if self.mrGbMOnSetState[level1] ~= nil then
			local noEventSend2 = true 
			if self.isServer then
				noEventSend2 = noEventSend 
			end 
			
			local state, message = pcall( self.mrGbMOnSetState[level1], self, self[level1], valueNew, noEventSend2 )
			if not state then
				print("Error: "..tostring(message)) 
				mrGearboxMogli.debugEvent( self, self[level1], valueNew, noEventSend ) 
				self[level1] = valueNew 	
			end
		else
			self[level1]= valueNew 	
		end 	
	end 	
end 


mrGearboxMogliEvent = {} 
mrGearboxMogliEvent_mt = Class(mrGearboxMogliEvent, Event) 

InitEventClass(mrGearboxMogliEvent, "mrGearboxMogliEvent") 

 
function mrGearboxMogliEvent:emptyNew()
	local self = Event:new(mrGearboxMogliEvent_mt) 
	self.className="mrGearboxMogliEvent" 
	return self 
end 

function mrGearboxMogliEvent:new(object, level1, value)
	local self = mrGearboxMogliEvent:emptyNew() 
  self.object = object 
  self.level1 = level1 
  self.value = value 
	return self 
end 

function mrGearboxMogliEvent:readStream(streamId, connection)
	--both clients and server can receive this event
  local id = streamReadInt32(streamId) 
  self.object = networkGetObject(id) 
  self.level1 = streamReadString(streamId) 
  self.value = streamReadString(streamId) 
  self:run(connection) 
end 

function mrGearboxMogliEvent:writeStream(streamId, connection)
	--both clients and server can send this event
  streamWriteInt32(streamId, networkGetObjectId(self.object)) 
  streamWriteString(streamId, self.level1 ) 
  streamWriteString(streamId, self.value ) 
end 

function mrGearboxMogliEvent:run(connection)
	----both clients and server can "run" this event (after reading it)	
	self.object:mrGbMSetState(self.level1, self.value, true) 
  if not connection:getIsServer() then  
    g_server:broadcastEvent(mrGearboxMogliEvent:new(self.object, self.level1, self.value), nil, connection, self.object) 
  end 
end 

