--
-- Autopilot
-- Specialization for AP Tractors
--
-- @author  zartask / Mr. F
-- @date  10/12/09
--
-- Copyright (C) www.planet-ls.de
--
--	edit by gotchTOM
--	@date: 20-Feb-2011
--  Specialization for AP Combine (corn harvester) 
--	add: inputbindings, new helpPanel, cornering maneuvers, use Lights when needed, aiTrailerTrigger, apBackTrafficCollisionTrigger, apOtherCombineCollisionTrigger(left&right)+otherCombineColliTriggerActiv, 
--       workwidthArrows, waitMode, stop@rain
--  code source: AICombine.lua by Giants Software    
 
APCombine = {};

function APCombine.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Hirable, specializations) and SpecializationUtil.hasSpecialization(Steerable, specializations);
end;

function APCombine:load(xmlFile)



	self.apDelayTimeToStopMovement = 12;	
	self.apDelayTimeToMoveBack = 30;
	self.apDelayTimeToStopAutoPilot = 250;
	self.otherCombineColliTriggerActiv = false;
	self.waitMode = true;

    self.startAutopilot = SpecializationUtil.callSpecializationsFunction("startAutopilot");
    self.stopAutopilot = SpecializationUtil.callSpecializationsFunction("stopAutopilot");   
	
	self.onTrafficCollisionTrigger = APCombine.onTrafficCollisionTrigger;
	self.onOtherCombineCollisionTrigger = APCombine.onOtherCombineCollisionTrigger;
	self.addBackTrafficCollisionTrigger = APCombine.addBackTrafficCollisionTrigger;
	self.removeBackTrafficCollisionTrigger = APCombine.removeBackTrafficCollisionTrigger;
	self.addOtherCombineCollisionTrigger = APCombine.addOtherCombineCollisionTrigger;
	self.removeOtherCombineCollisionTrigger = APCombine.removeOtherCombineCollisionTrigger;	
	
	self.apTrafficCollisionTrigger = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.autoPilotAreas.apTrafficCollisionTrigger#index"));
	self.apBackTrafficCollisionTrigger = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.autoPilotAreas.apBackTrafficCollisionTrigger#index"));
	self.apOtherCombineCollisionTriggerL = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.autoPilotAreas.apOtherCombineCollisionTriggerL#index"));
	self.apOtherCombineCollisionTriggerR = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.autoPilotAreas.apOtherCombineCollisionTriggerR#index"));	
	self.otherCombineColliTriggerActiv = false;
	
	self.trafficCollisionIgnoreList = {};
    for k,v in pairs(self.components) do
        self.trafficCollisionIgnoreList[v.node] = true;
    end;
    self.numCollidingVehicles = 0;
    self.numToolsCollidingVehicles = {};
		
	self.onTrailerTrigger = APCombine.onTrailerTrigger;
	self.aiTrailerTriggers = {};
    local i = 0;
    while true do
        local key = string.format("vehicle.aiTrailerTriggers.aiTrailerTrigger(%d)", i);
        if not hasXMLProperty(xmlFile, key) then
            break;
        end;
        local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index"));
        local pipeState = getXMLInt(xmlFile, key.."#pipeState");
        if node ~= nil and pipeState ~= nil then
            self.aiTrailerTriggers[node] = {node=node, pipeState=pipeState};
        end;
        i = i + 1;
    end;
    local aiTrailerTrigger = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.aiTrailerTrigger#index"));
    if aiTrailerTrigger ~= nil then
        self.aiTrailerTriggers[aiTrailerTrigger] = {node=aiTrailerTrigger, pipeState=2};
    end;
    for _, aiTrailerTrigger in pairs(self.aiTrailerTriggers) do
        addTrigger(aiTrailerTrigger.node, "onTrailerTrigger", self);
    end;
  
    self.trailersInRange = {};
    self.isTrailerInRange = false;
    self.trailerInRangePipeState = 0;
	self.waitingForTrailerToUnload = false;
    self.waitingForDischarge = false;
    self.waitForDischargeTime = 0;
    self.waitForDischargeTimeout = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.waitForDischargeTime"), 5000);
 
    self.isAutopilotActivated = false;
    self.dtSum = 0;

    local aiMotorSound  = getXMLString(xmlFile, "vehicle.aiMotorSound#file");
    if aiMotorSound  ~= nil and aiMotorSound  ~= "" then
        aiMotorSound  = Utils.getFilename(aiMotorSound, self.baseDirectory);
        self.aiMotorSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSoundRun#pitchOffset"), 0);
        self.aiMotorSoundRadius = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSoundRun#radius"), 50);
        self.aiMotorSoundInnerRadius = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSoundRun#innerRadius"), 10);
        self.aiMotorSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSoundRun#volume"), 1);
        self.aiMotorSound = createAudioSource("aiMotorSound", aiMotorSound, self.aiMotorSoundRadius, self.aiMotorSoundInnerRadius, self.aiMotorSoundVolume, 0);
        link(self.components[1].node, self.aiMotorSound);
        setVisibility(self.aiMotorSound, false);
    end;

    local translationPartNodeLeft = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#index"));
    if translationPartNodeLeft ~= nil then
        self.translationPartLeft = {};
        self.translationPartLeft.node = translationPartNodeLeft;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#minTrans"));
        self.translationPartLeft.minTrans = {};
        self.translationPartLeft.minTrans[1] = Utils.getNoNil(x, 0);
        self.translationPartLeft.minTrans[2] = Utils.getNoNil(y, 0);
        self.translationPartLeft.minTrans[3] = Utils.getNoNil(z, 0);

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#maxTrans"));
        self.translationPartLeft.maxTrans = {};
        self.translationPartLeft.maxTrans[1] = Utils.getNoNil(x, 0);
        self.translationPartLeft.maxTrans[2] = Utils.getNoNil(y, 0);
        self.translationPartLeft.maxTrans[3] = Utils.getNoNil(z, 0);

        self.translationPartLeft.transTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#transTime"), 5)*2500;
        self.translationPartLeft.touchTransLimit = Utils.getNoNil(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#touchTransLimit"), 5);
    end;
	
	local translationPartNodeRight = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#index"));
    if translationPartNodeRight ~= nil then
        self.translationPartRight = {};
        self.translationPartRight.node = translationPartNodeRight;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#minTrans"));
        self.translationPartRight.minTrans = {};
        self.translationPartRight.minTrans[1] = Utils.getNoNil(x, 0);
        self.translationPartRight.minTrans[2] = Utils.getNoNil(y, 0);
        self.translationPartRight.minTrans[3] = Utils.getNoNil(z, 0);

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#maxTrans"));
        self.translationPartRight.maxTrans = {};
        self.translationPartRight.maxTrans[1] = Utils.getNoNil(x, 0);
        self.translationPartRight.maxTrans[2] = Utils.getNoNil(y, 0);
        self.translationPartRight.maxTrans[3] = Utils.getNoNil(z, 0);

        self.translationPartRight.transTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#transTime"), 5)*2500;
        self.translationPartRight.touchTransLimit = Utils.getNoNil(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#touchTransLimit"), 5);
    end;

    self.autoPilotAreaLeft = {};
    self.autoPilotAreaLeft.available = getXMLBool(xmlFile, "vehicle.autoPilotAreas#left");
    self.autoPilotAreaLeft.startOutside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#startOutside"));
    self.autoPilotAreaLeft.widthOutside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#widthOutside"));
    self.autoPilotAreaLeft.heightOutside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#heightOutside"));
    self.autoPilotAreaLeft.startInside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#startInside"));
    self.autoPilotAreaLeft.widthInside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#widthInside"));
    self.autoPilotAreaLeft.heightInside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#heightInside"));
	self.autoPilotAreaLeft.startCheck = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#startCheck"));
	self.autoPilotAreaLeft.widthCheck = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#widthCheck"));
	self.autoPilotAreaLeft.heightCheck = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#heightCheck"));
    self.autoPilotAreaLeft.active = true;

    self.autoPilotAreaRight = {};
    self.autoPilotAreaRight.available = getXMLBool(xmlFile, "vehicle.autoPilotAreas#right");
    self.autoPilotAreaRight.startOutside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#startOutside"));
    self.autoPilotAreaRight.widthOutside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#widthOutside"));
    self.autoPilotAreaRight.heightOutside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#heightOutside"));
    self.autoPilotAreaRight.startInside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#startInside"));
    self.autoPilotAreaRight.widthInside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#widthInside"));
	self.autoPilotAreaRight.heightInside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#heightInside"));	
	self.autoPilotAreaRight.startCheck = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#startCheck"));
	self.autoPilotAreaRight.widthCheck = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#widthCheck"));
	self.autoPilotAreaRight.heightCheck = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#heightCheck"));
    self.autoPilotAreaRight.active = false;

    if self.autoPilotAreaLeft.available or self.autoPilotAreaRight.available then
        self.autoPilotPresent = true;
    else
        self.autoPilotPresent = false;
    end;  	
	
	self.workWidth = nil;
    self.autoPilotEnabled = false;
	self.apDelayLeftCounting = false;
    self.autoPilotDelayLeft = 0;
    self.autoPilotDelayRight = 0;
    self.autopilotId = 0;
	self.gotFruitArea = nil;	
    self.autoPilotAreaLeft.arrowLeft = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#arrowL"));
	self.autoPilotAreaRight.arrowRight = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#arrowR"));
	
	self.turnDirection = 0;
    self.autoRotateBackSpeedBackup = self.autoRotateBackSpeed;	

	self.apCombHelpPanelPath = Utils.getFilename("ApHud.png", self.baseDirectory);
	self.apCombHudWidth =  0.35  
	self.apCombHudHeight = 0.377;  --0.255 
	self.apCombHudPosX = 0.35;   
	self.apCombHudPosY = 0.0108;  
	self.apCombHelpPanelTextPosX = 0.355;     
	self.apCombHelpPanelTextPosY = 0.554;  --0.4254 
	self.apCombHelpPanelOverlay = Overlay:new("ApHud", self.apCombHelpPanelPath, self.apCombHudPosX, self.apCombHudPosY, self.apCombHudWidth, self.apCombHudHeight);
	self.helpPanelActive = false;	
end;

function APCombine:delete()

    self:stopAutopilot();
	for _, aiTrailerTrigger in pairs(self.aiTrailerTriggers) do
        removeTrigger(aiTrailerTrigger.node);
    end;
	self:removeOtherCombineCollisionTrigger()
	self:removeBackTrafficCollisionTrigger();
end;

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

function APCombine:keyEvent(unicode, sym, modifier, isDown)
	
	if isDown and sym == Input.KEY_s then
		self.speed2Level = 0;
	end;	
end;

function APCombine:update(dt)

	if self:getIsActiveForInput() then	
		if InputBinding.hasEvent(InputBinding.AP_COMBINE_HELPPANEL) then
				self.helpPanelActive = not self.helpPanelActive;
		end;
		if	InputBinding.hasEvent(InputBinding.SPEED_LEVEL1) then
			self.speed2Level = 1;
		elseif InputBinding.hasEvent(InputBinding.SPEED_LEVEL2) then
			self.speed2Level = 2;
		--elseif InputBinding.hasEvent(InputBinding.SPEED_LEVEL3) then
			--self.speed2Level = 2;
		elseif InputBinding.hasEvent(InputBinding.SPEED_LEVEL4) then
			self.speed2Level = 4;
		end;
		if self.helpPanelActive then			
			if	InputBinding.hasEvent(InputBinding.AP_COMBINE_AREALEFT) then
				self.autoPilotAreaLeft.active = self.autoPilotAreaLeft.available;
				self.autoPilotAreaRight.active = false;
				self.autoPilotDelayLeft = 0;
				self.autoPilotDelayRight = 0;           
			end;
			if	InputBinding.hasEvent(InputBinding.AP_COMBINE_AREARIGHT) then
				self.autoPilotAreaRight.active = self.autoPilotAreaRight.available;
				self.autoPilotAreaLeft.active = false;
				self.autoPilotDelayRight = 0;
				self.autoPilotDelayLeft = 0;
			end;
			if	InputBinding.isPressed(InputBinding.AP_COMBINE_WORKWIDTHUP) then
				self.translationMaxLeft = true;
				self.translationMaxRight = true;
			else
				self.translationMaxLeft = false;
				self.translationMaxRight = false;
			end;
			if	InputBinding.isPressed(InputBinding.AP_COMBINE_WORKWIDTHDOWN) then
				self.translationMinLeft = true;
				self.translationMinRight = true ;				
			else
				self.translationMinLeft = false;
				self.translationMinRight = false ;
			end;
			if	InputBinding.hasEvent(InputBinding.AP_COMBINE_MENUEUP) then
				self.autopilotId = self.autopilotId - 1;
				if self.autopilotId < 0 then
					self.autopilotId = 1;
				end;
			end;
			if	InputBinding.hasEvent(InputBinding.AP_COMBINE_MENUEDOWN) then
				self.autopilotId = self.autopilotId + 1;
				if self.autopilotId > 1 then
					self.autopilotId = 0;
				end;
			end;					
			if InputBinding.hasEvent(InputBinding.AP_COMBINE_STARTSTOP) then
				if self.isAutopilotActivated then
					self:stopAutopilot();
					self.autoPilotEnabled = false;
				else
					if	self.motor.speedLevel == 0 then
						self.speed2Level = 1;
					end;
					self:startAutopilot();
					self.autoPilotEnabled = true;
				end;
			end;
			if InputBinding.hasEvent(InputBinding.AP_COMBINE_WAITMODE_ONOFF) then 
				self.waitMode = not self.waitMode 
			end;
			if InputBinding.hasEvent(InputBinding.AP_COMBINE_COLTRGGER_ONOFF) then 
				self.otherCombineColliTriggerActiv = not self.otherCombineColliTriggerActiv
				if not self.otherCombineColliTriggerActiv then
					self.numCollidingVehicles = 0;
				end;	
			end;			
		end;
	end;
end;

function APCombine:updateTick(dt)
	self:removeOtherCombineCollisionTrigger();
	self:removeBackTrafficCollisionTrigger();	
	if self.isServer then
		self.workWidth = getTranslation(self.translationPartLeft.node) * 2;		
		if self.isEntered then
			if self.autoPilotAreaRight.available then
				if self.translationPartRight ~= nil and (self.translationMaxRight or self.translationMinRight) then
				local x, y, z = getTranslation(self.translationPartRight.node);
				local trans = {x,y,z};
				local newTrans = Utils.getMovedLimitedValues(trans, self.translationPartRight.maxTrans, self.translationPartRight.minTrans, 3, self.translationPartRight.transTime, dt, not self.translationMaxRight);
				setTranslation(self.translationPartRight.node, unpack(newTrans));
				end;
			end;	
			if self.autoPilotAreaLeft.available then
				if self.translationPartLeft ~= nil and (self.translationMaxLeft or self.translationMinLeft) then
				local x, y, z = getTranslation(self.translationPartLeft.node);
				local trans = {x,y,z};
				local newTrans = Utils.getMovedLimitedValues(trans, self.translationPartLeft.maxTrans, self.translationPartLeft.minTrans, 3, self.translationPartLeft.transTime, dt, not self.translationMaxRight);
				setTranslation(self.translationPartLeft.node, unpack(newTrans));
				end;
			end;
			if self.helpPanelActive then
				setVisibility(self.autoPilotAreaLeft.arrowLeft, true);
				setVisibility(self.autoPilotAreaRight.arrowRight, true);
			else
				setVisibility(self.autoPilotAreaLeft.arrowLeft, false);
				setVisibility(self.autoPilotAreaRight.arrowRight, false);
			end;
		else
			setVisibility(self.autoPilotAreaLeft.arrowLeft, false);
			setVisibility(self.autoPilotAreaRight.arrowRight, false);
		end;
		if self.isAutopilotActivated then
			if self.isBroken then
				self:stopAutopilot();
			end;		
			self.dtSum = self.dtSum + dt;
			if self.dtSum > 20 then
				APCombine.updateAIMovement(self, self.dtSum);
				self.dtSum = 0;
			end;
			if (self.grainTankFillLevel > 0 or self.grainTankCapacity <= 0) and (self.grainTankFillLevel >= self.grainTankCapacity or self.isTrailerInRange) then
                if self.trailerInRangePipeState > 0 then
                    self:setPipeState(self.trailerInRangePipeState);
					if self.waitMode then
						self.waitingForDischarge = true;
					end;
                else
                    self:setPipeState(2);
                end;
                --self:setPipeOpening(true);
                if self.isTrailerInRange then
                    self.waitForDischargeTime = self.time + self.waitForDischargeTimeout;
                end;
                if self.waitMode then 
					if self.grainTankFillLevel >= self.grainTankCapacity and self.grainTankCapacity > 0 then                    
						self.waitingForDischarge = true;
						self.waitForDischargeTime = self.time + self.waitForDischargeTimeout;
					end;
				else
					if self.grainTankFillLevel < self.grainTankCapacity and self.grainTankCapacity > 0 then                    
						self.waitingForDischarge = false;
						self.waitForDischargeTime = self.time + self.waitForDischargeTimeout;
						if self:getIshreshingAllowed(true) then
							self:setIsThreshing(true);
						end; 
					end;
				end;
            else
                -- no trailer in range and not full
					if (self.waitingForDischarge and self.grainTankFillLevel <= 0) or self.waitForDischargeTime <= self.time then
						self.waitingForDischarge = false;
						if not self.isTrailerInRange then
							-- only close the pipe if no trailer is in range
							self:setPipeState(1);
						end;
						--self:setPipeOpening(false);
						if self:getIshreshingAllowed(true) then
							self:setIsThreshing(true);
						end;                
					end;
            end;			
			if self.speed2Level == 2 or self.speed2Level == 4 then
				self.apDelayTimeToStopMovement = 8;	
			else
				self.apDelayTimeToStopMovement = 12;
			end;
			self:addOtherCombineCollisionTrigger()
		else
			self.dtSum = 0;
			self:removeOtherCombineCollisionTrigger()
			self:removeBackTrafficCollisionTrigger();
		end;		
	end;
		
end;

function APCombine:startAutopilot()
    self:hire();
    if not self.isAutopilotActivated then
        self.isAutopilotActivated = true;		
		self.isTrailerInRange = false;
		self.waitingForDischarge = false;
		if self.autoPilotPresent then
			if not self.autoPilotAreaLeft.active and not self.autoPilotAreaRight.active then
				if self.autoPilotAreaLeft.available then
					self.autoPilotAreaLeft.active = true;
				elseif self.autoPilotAreaRight.available then
					self.autoPilotAreaRight.active = true;
				end;
			end;
			if self.autoPilotEnabled then
				self.autoRotateBackSpeed = 0;
			else
				self.autoRotateBackSpeed = self.autoRotateBackSpeedBackup;
			end;
		end;
        self.numCollidingVehicles = 0;
		if self.apTrafficCollisionTrigger ~= nil then
            addTrigger(self.apTrafficCollisionTrigger, "onTrafficCollisionTrigger", self);
        end;  		
        self.checkSpeedLimit = false;
        setVisibility(self.aiMotorSound, true);
    end;
end;

function APCombine:stopAutopilot()
    self:dismiss();
    if self.isAutopilotActivated then
        self.isAutopilotActivated = false;
		self.motor:setSpeedLevel(0, false);
        self.motor.maxRpmOverride = nil;
        WheelsUtil.updateWheelsPhysics(self, 0, self.lastSpeed, 0, false, self.requiredDriveMode);	
		if self.apTrafficCollisionTrigger ~= nil then
			removeTrigger(self.apTrafficCollisionTrigger, "onTrafficCollisionTrigger", self);
		end;         
        self.checkSpeedLimit = true;
        setVisibility(self.aiMotorSound, false);			
		self.autoPilotDelayRight = 0;
		self.autoPilotDelayLeft = 0;
		self:setIsThreshing(false);		
    end;
end;

function APCombine.updateAIMovement(self, dt, onLeave)

    local allowedToDrive = true;
	
--use Lights when needed_begin	
	if not self.isControlled then
        if g_currentMission.environment.needsLights then
            self:setLightsVisibility(true);
        else
            self:setLightsVisibility(false);
        end;
    end;
--use Lights when needed_end
	
	if self.grainTankCapacity == 0 and ((self.pipeParticleActivated and not self.isPipeUnloading) or not self.pipeStateIsUnloading[self.currentPipeState]) then
        -- there is some fruit to unload, but there is no trailer. Stop and wait for a trailer
        self.waitingForTrailerToUnload = true;
    end;
    if self.waitingForTrailerToUnload then
        if self.lastValidOutputFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then
            local trailer = self:findTrailerToUnload(self.lastValidOutputFruitType);
            if trailer ~= nil then
               -- there is a trailer to unload. Continue working
                self.waitingForTrailerToUnload = false;
            end;
        else
           -- we did not cut anything yet. We shouldn't have ended in this state. Just continue working
            self.waitingForTrailerToUnload = false;
        end;
    end;
  
    if (self.grainTankFillLevel >= self.grainTankCapacity and self.grainTankCapacity > 0) or self.waitingForTrailerToUnload or self.waitingForDischarge or self.numCollidingVehicles > 0 then
        allowedToDrive = false;
    end;
	if not self:getIshreshingAllowed(true) then
        allowedToDrive = false;
        self:setIsThreshing(false);
        self.waitingForWeather = true;
    else
        if self.waitingForWeather then
            self:startThreshing();
            self.waitingForWeather = false;
        end;
    end;
	
	if self.numCollidingVehicles > 0 then
        allowedToDrive = false;
    end;
    for k,v in pairs(self.numToolsCollidingVehicles) do
        if v > 0 then
            allowedToDrive = false;
            break;
        end;
    end;

 	if self.autoPilotPresent then
		if self.autoPilotEnabled then --and self.attachedCutter.hasGroundContact then | and self.movingDirection > 0
										
			self.turnDirection = 0;

if self.autoPilotAreaRight.available and self.autoPilotAreaRight.active and self.autopilotId == 0  then
                    local x,y,z = getWorldTranslation(self.autoPilotAreaRight.startOutside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaRight.widthOutside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaRight.heightOutside);
                    local right = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRASS, x, z, x1, z1, x2, z2);

                    local x,y,z = getWorldTranslation(self.autoPilotAreaRight.startInside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaRight.widthInside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaRight.heightInside);
                    local left = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRASS, x, z, x1, z1, x2, z2);
                    
					local x,y,z = getWorldTranslation(self.autoPilotAreaRight.startCheck);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaRight.widthCheck);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaRight.heightCheck);
                    local rightCheck = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRASS, x, z, x1, z1, x2, z2);                    
					
					local x,y,z = getWorldTranslation(self.autoPilotAreaLeft.startOutside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaLeft.widthOutside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaLeft.heightOutside);
                    local checkLeft = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRASS, x, z, x1, z1, x2, z2);					
					
					self.turnDirection = right -(9 -left);
                    self.turnDirection = right*4 -(20 -left);

                    if (left < 1 and right < 1) then
                        self.apDelayRightCounting = true;
						self.gotFruitArea = false;
                    else
						self.apDelayRightCounting = false;
                        self.autoPilotDelayRight = 0;
						self.gotFruitArea = true;
                    end;					
					if self.autoPilotDelayRight >= self.apDelayTimeToStopMovement then
						allowedToDrive = false;						
						for cutter,implement in pairs(self.attachedCutters) do
							local jointDesc = self.attacherJoints[implement.jointDescIndex];
							jointDesc.moveDown = false;
						end;						
					end;
					if self.autoPilotDelayRight >= self.apDelayTimeToMoveBack then
						if self.numCollidingVehicles == 0 then
						allowedToDrive = true;
						self.apDelayRightCounting = true;
						else
						allowedToDrive = false;
						self.apDelayRightCounting = false;
						end;
						moveForwards = false;
						self.turnDirection = ((20 -right) -left*4);
					end;
					if not self.gotFruitArea and rightCheck >0 then
						moveForwards = true;
						self.turnDirection = 0;
						self.apDelayRightCounting = false;
						self.autoPilotDelayRight = 0;
						for cutter,implement in pairs(self.attachedCutters) do
							local jointDesc = self.attacherJoints[implement.jointDescIndex];
							jointDesc.moveDown = true;
						end;
						if checkLeft > 0 then
							self.turnDirection = right -(9 -left);
							self.turnDirection = right*4 -(20 -left);
						end;
					elseif self.gotFruitArea then
						moveForwards = true;
						self.turnDirection = right -(9 -left);
						self.turnDirection = right*4 -(20 -left);
						for cutter,implement in pairs(self.attachedCutters) do
							local jointDesc = self.attacherJoints[implement.jointDescIndex];
							jointDesc.moveDown = true;
						end;						
					end;
                end;

				if self.autoPilotAreaLeft.available and self.autoPilotAreaLeft.active and self.autopilotId == 0 then
                    local x,y,z = getWorldTranslation(self.autoPilotAreaLeft.startOutside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaLeft.widthOutside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaLeft.heightOutside);
                    local left = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRASS, x, z, x1, z1, x2, z2);

                    local x,y,z = getWorldTranslation(self.autoPilotAreaLeft.startInside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaLeft.widthInside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaLeft.heightInside);
                    local right = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRASS, x, z, x1, z1, x2, z2);

                    local x,y,z = getWorldTranslation(self.autoPilotAreaLeft.startCheck);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaLeft.widthCheck);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaLeft.heightCheck);
                    local leftCheck = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRASS, x, z, x1, z1, x2, z2); 

                    local x,y,z = getWorldTranslation(self.autoPilotAreaRight.startOutside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaRight.widthOutside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaRight.heightOutside);
                    local checkRight = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRASS, x, z, x1, z1, x2, z2);

                    self.turnDirection = ((20 -right) -left*4);
					
                    if (left < 1 and right < 1) then
                        self.apDelayLeftCounting = true;
						self.gotFruitArea = false;
                    else
                        self.apDelayLeftCounting = false;
						self.autoPilotDelayLeft = 0;
						self.gotFruitArea = true;
                    end;
					if self.autoPilotDelayLeft >= self.apDelayTimeToStopMovement then
						allowedToDrive = false;						
						for cutter,implement in pairs(self.attachedCutters) do
							local jointDesc = self.attacherJoints[implement.jointDescIndex];
							jointDesc.moveDown = false;
						end;						
					end;
					if self.autoPilotDelayLeft >= self.apDelayTimeToMoveBack then 
						if self.numCollidingVehicles == 0 then
						allowedToDrive = true;
						self.apDelayLeftCounting = true;
						else
						allowedToDrive = false;
						self.apDelayLeftCounting = false;
						end;
						moveForwards = false;
						self.turnDirection = right -(9 -left);
						self.turnDirection = right*4 -(20 -left);						
					end;
					if not self.gotFruitArea and leftCheck > 0 then
						moveForwards = true;
						self.turnDirection = 0;
						self.apDelayLeftCounting = false;
						self.autoPilotDelayLeft = 0;
						for cutter,implement in pairs(self.attachedCutters) do
							local jointDesc = self.attacherJoints[implement.jointDescIndex];
							jointDesc.moveDown = true;
						end;
						if checkRight > 0 then
							self.turnDirection = ((20 -right) -left*4);
						end;
					elseif self.gotFruitArea then
						moveForwards = true;
						self.turnDirection = ((20 -right) -left*4);
						for cutter,implement in pairs(self.attachedCutters) do
							local jointDesc = self.attacherJoints[implement.jointDescIndex];
							jointDesc.moveDown = true;
						end;
					end;	
                end;
				
if self.autoPilotAreaRight.available and self.autoPilotAreaRight.active and self.autopilotId == 1 then
                    local x,y,z = getWorldTranslation(self.autoPilotAreaRight.startOutside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaRight.widthOutside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaRight.heightOutside);
                    local right = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRYGRASS, x, z, x1, z1, x2, z2);

                    local x,y,z = getWorldTranslation(self.autoPilotAreaRight.startInside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaRight.widthInside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaRight.heightInside);
                    local left = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRYGRASS, x, z, x1, z1, x2, z2);
                    
					local x,y,z = getWorldTranslation(self.autoPilotAreaRight.startCheck);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaRight.widthCheck);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaRight.heightCheck);
                    local rightCheck = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRYGRASS, x, z, x1, z1, x2, z2);                    
					
					local x,y,z = getWorldTranslation(self.autoPilotAreaLeft.startOutside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaLeft.widthOutside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaLeft.heightOutside);
                    local checkLeft = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRYGRASS, x, z, x1, z1, x2, z2);					
					
					self.turnDirection = right -(9 -left);
                    self.turnDirection = right*4 -(20 -left);

                    if (left < 1 and right < 1) then
                        self.apDelayRightCounting = true;
						self.gotFruitArea = false;
                    else
						self.apDelayRightCounting = false;
                        self.autoPilotDelayRight = 0;
						self.gotFruitArea = true;
                    end;					
					if self.autoPilotDelayRight >= self.apDelayTimeToStopMovement then
						allowedToDrive = false;						
						for cutter,implement in pairs(self.attachedCutters) do
							local jointDesc = self.attacherJoints[implement.jointDescIndex];
							jointDesc.moveDown = false;
						end;						
					end;
					if self.autoPilotDelayRight >= self.apDelayTimeToMoveBack then
						if self.numCollidingVehicles == 0 then
						allowedToDrive = true;
						self.apDelayRightCounting = true;
						else
						allowedToDrive = false;
						self.apDelayRightCounting = false;
						end;
						moveForwards = false;
						self.turnDirection = ((20 -right) -left*4);
					end;
					if not self.gotFruitArea and rightCheck >0 then
						moveForwards = true;
						self.turnDirection = 0;
						self.apDelayRightCounting = false;
						self.autoPilotDelayRight = 0;
						for cutter,implement in pairs(self.attachedCutters) do
							local jointDesc = self.attacherJoints[implement.jointDescIndex];
							jointDesc.moveDown = true;
						end;
						if checkLeft > 0 then
							self.turnDirection = right -(9 -left);
							self.turnDirection = right*4 -(20 -left);
						end;
					elseif self.gotFruitArea then
						moveForwards = true;
						self.turnDirection = right -(9 -left);
						self.turnDirection = right*4 -(20 -left);
						for cutter,implement in pairs(self.attachedCutters) do
							local jointDesc = self.attacherJoints[implement.jointDescIndex];
							jointDesc.moveDown = true;
						end;						
					end;
                end;

				if self.autoPilotAreaLeft.available and self.autoPilotAreaLeft.active and self.autopilotId == 1 then
                    local x,y,z = getWorldTranslation(self.autoPilotAreaLeft.startOutside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaLeft.widthOutside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaLeft.heightOutside);
                    local left = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRYGRASS, x, z, x1, z1, x2, z2);

                    local x,y,z = getWorldTranslation(self.autoPilotAreaLeft.startInside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaLeft.widthInside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaLeft.heightInside);
                    local right = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRYGRASS, x, z, x1, z1, x2, z2);

                    local x,y,z = getWorldTranslation(self.autoPilotAreaLeft.startCheck);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaLeft.widthCheck);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaLeft.heightCheck);
                    local leftCheck = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRYGRASS, x, z, x1, z1, x2, z2); 

                    local x,y,z = getWorldTranslation(self.autoPilotAreaRight.startOutside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaRight.widthOutside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaRight.heightOutside);
                    local checkRight = Utils.getFruitArea(FruitUtil.FRUITTYPE_GRYGRASS, x, z, x1, z1, x2, z2);

                    self.turnDirection = ((20 -right) -left*4);
					
                    if (left < 1 and right < 1) then
                        self.apDelayLeftCounting = true;
						self.gotFruitArea = false;
                    else
                        self.apDelayLeftCounting = false;
						self.autoPilotDelayLeft = 0;
						self.gotFruitArea = true;
                    end;
					if self.autoPilotDelayLeft >= self.apDelayTimeToStopMovement then
						allowedToDrive = false;						
						for cutter,implement in pairs(self.attachedCutters) do
							local jointDesc = self.attacherJoints[implement.jointDescIndex];
							jointDesc.moveDown = false;
						end;						
					end;
					if self.autoPilotDelayLeft >= self.apDelayTimeToMoveBack then 
						if self.numCollidingVehicles == 0 then
						allowedToDrive = true;
						self.apDelayLeftCounting = true;
						else
						allowedToDrive = false;
						self.apDelayLeftCounting = false;
						end;
						moveForwards = false;
						self.turnDirection = right -(9 -left);
						self.turnDirection = right*4 -(20 -left);						
					end;
					if not self.gotFruitArea and leftCheck > 0 then
						moveForwards = true;
						self.turnDirection = 0;
						self.apDelayLeftCounting = false;
						self.autoPilotDelayLeft = 0;
						for cutter,implement in pairs(self.attachedCutters) do
							local jointDesc = self.attacherJoints[implement.jointDescIndex];
							jointDesc.moveDown = true;
						end;
						if checkRight > 0 then
							self.turnDirection = ((20 -right) -left*4);
						end;
					elseif self.gotFruitArea then
						moveForwards = true;
						self.turnDirection = ((20 -right) -left*4);
						for cutter,implement in pairs(self.attachedCutters) do
							local jointDesc = self.attacherJoints[implement.jointDescIndex];
							jointDesc.moveDown = true;
						end;
					end;	
                end;

				
				local acceleration = 0;					
				if self.isMotorStarted then
					if self.motor.speedLevel ~= 0 then
						acceleration = 1.0;
					end;
				end;
				if self.fuelFillLevel == 0 then
					acceleration = 0;
				end;
				
				if self.apDelayLeftCounting then
					self.autoPilotDelayLeft = self.autoPilotDelayLeft +1;
				end;
				if self.apDelayRightCounting then
					self.autoPilotDelayRight = self.autoPilotDelayRight +1;
				end;

				local rotScale = math.min(1.0/(self.lastSpeed*50+1), 1);
				if self.autoPilotAreaLeft.active and self.turnDirection < -19 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*rotScale, 0.90);-----self.minRotTime
				elseif self.turnDirection < -18 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*70, 0.84);----self.maxRotTime
				elseif self.turnDirection < -17 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*65, 0.78);----self.maxRotTime
				elseif self.turnDirection < -16 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*55, 0.72);----self.maxRotTime
                elseif self.turnDirection < -15 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*45, 0.66);----self.maxRotTime
				elseif self.turnDirection < -14 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*35, 0.60);----self.maxRotTime
				elseif self.turnDirection < -13 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*30, 0.54);----self.maxRotTime
				elseif self.turnDirection < -12 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*25, 0.36);----self.maxRotTime
				elseif self.turnDirection < -11 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*20, 0.28);----self.maxRotTime
				elseif self.turnDirection < -10 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*15, 0.22);----self.maxRotTime
				elseif self.turnDirection < -9 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*10, 0.18);----self.maxRotTime
                elseif self.turnDirection < -8 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*5, 0.16);----self.maxRotTime
				elseif self.turnDirection < -7 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*1, 0.14);----self.maxRotTime
				elseif self.turnDirection < -6 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.5, 0.12);----self.maxRotTime
				elseif self.turnDirection < -5 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.1, 0.10);----self.maxRotTime
				elseif self.turnDirection < -4 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.08, 0.08);----self.maxRotTime
				elseif self.turnDirection < -3 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.06, 0.06);----self.maxRotTime
				elseif self.turnDirection < -2 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.04, 0.04);----self.maxRotTime
				elseif self.turnDirection < -1 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.02, 0.02);----self.maxRotTime
				elseif self.autoPilotAreaLeft.active and self.turnDirection > 19 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*rotScale, -0.90);-----self.minRotTime
				elseif self.turnDirection > 18 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*70, -0.84);-----self.minRotTime
				elseif self.turnDirection > 17 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*65, -0.78);-----self.minRotTime
				elseif self.turnDirection > 16 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*55, -0.72);-----self.minRotTime
				elseif self.turnDirection > 15 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*45, -0.66);-----self.minRotTime
				elseif self.turnDirection > 14 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*35, -0.60);-----self.minRotTime
				elseif self.turnDirection > 13 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*30, -0.54);-----self.minRotTime
                elseif self.turnDirection > 12 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*25, -0.36);-----self.minRotTime
				elseif self.turnDirection > 11 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*20, -0.28);-----self.minRotTime
				elseif self.turnDirection > 10 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*15, -0.22);-----self.minRotTime
				elseif self.turnDirection > 9 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*10, -0.18);-----self.minRotTime
				elseif self.turnDirection > 8 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*5, -0.16);-----self.minRotTime
				elseif self.turnDirection > 7 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*1, -0.14);-----self.minRotTime
				elseif self.turnDirection > 6 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.5, -0.12);-----self.minRotTime
                elseif self.turnDirection > 5 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.10, -0.10);-----self.minRotTime
				elseif self.turnDirection > 4 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.08, -0.08);-----self.minRotTime
				elseif self.turnDirection > 3 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.06, -0.06);-----self.minRotTime
                elseif self.turnDirection > 2 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.04, -0.04);-----self.minRotTime
				elseif self.turnDirection > 1 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.02, -0.02);-----self.minRotTime
                else
                    self.rotatedTime = 0;
                end;
				
				local rotScale = math.min(1.0/(self.lastSpeed*50+1), 1);
				if self.autoPilotAreaRight.active and self.turnDirection < -19 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*rotScale, 0.90);-----self.minRotTime
				elseif self.turnDirection < -18 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*70, 0.84);----self.maxRotTime
				elseif self.turnDirection < -17 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*65, 0.78);----self.maxRotTime
				elseif self.turnDirection < -16 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*55, 0.72);----self.maxRotTime
                elseif self.turnDirection < -15 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*45, 0.66);----self.maxRotTime
				elseif self.turnDirection < -14 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*35, 0.60);----self.maxRotTime
				elseif self.turnDirection < -13 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*30, 0.54);----self.maxRotTime
				elseif self.turnDirection < -12 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*25, 0.36);----self.maxRotTime
				elseif self.turnDirection < -11 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*20, 0.28);----self.maxRotTime
				elseif self.turnDirection < -10 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*15, 0.22);----self.maxRotTime
				elseif self.turnDirection < -9 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*10, 0.18);----self.maxRotTime
                elseif self.turnDirection < -8 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*5, 0.16);----self.maxRotTime
				elseif self.turnDirection < -7 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*1, 0.14);----self.maxRotTime
				elseif self.turnDirection < -6 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.5, 0.12);----self.maxRotTime
				elseif self.turnDirection < -5 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.1, 0.10);----self.maxRotTime
				elseif self.turnDirection < -4 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.08, 0.08);----self.maxRotTime
				elseif self.turnDirection < -3 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.06, 0.06);----self.maxRotTime
				elseif self.turnDirection < -2 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.04, 0.04);----self.maxRotTime
				elseif self.turnDirection < -1 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.02, 0.02);----self.maxRotTime
				elseif self.autoPilotAreaRight.active and self.turnDirection > 19 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*rotScale, -0.90);-----self.minRotTime
				elseif self.turnDirection > 18 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*70, -0.84);-----self.minRotTime
				elseif self.turnDirection > 17 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*65, -0.78);-----self.minRotTime
				elseif self.turnDirection > 16 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*55, -0.72);-----self.minRotTime
				elseif self.turnDirection > 15 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*45, -0.66);-----self.minRotTime
				elseif self.turnDirection > 14 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*35, -0.60);-----self.minRotTime
				elseif self.turnDirection > 13 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*30, -0.54);-----self.minRotTime
                elseif self.turnDirection > 12 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*25, -0.36);-----self.minRotTime
				elseif self.turnDirection > 11 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*20, -0.28);-----self.minRotTime
				elseif self.turnDirection > 10 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*15, -0.22);-----self.minRotTime
				elseif self.turnDirection > 9 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*10, -0.18);-----self.minRotTime
				elseif self.turnDirection > 8 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*5, -0.16);-----self.minRotTime
				elseif self.turnDirection > 7 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*1, -0.14);-----self.minRotTime
				elseif self.turnDirection > 6 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.5, -0.12);-----self.minRotTime
                elseif self.turnDirection > 5 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.10, -0.10);-----self.minRotTime
				elseif self.turnDirection > 4 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.08, -0.08);-----self.minRotTime
				elseif self.turnDirection > 3 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.06, -0.06);-----self.minRotTime
                elseif self.turnDirection > 2 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.04, -0.04);-----self.minRotTime
				elseif self.turnDirection > 1 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.02, -0.02);-----self.minRotTime
                else
                    self.rotatedTime = 0;
                end;

					if self.firstTimeRun then
						local acc = acceleration;
						if speedLevel ~= nil and speedLevel ~= 0 then
							acc = self.motor.accelerations[speedLevel];
							self.motor:setSpeedLevel(speedLevel, true);
							if math.abs(angle) >= slowAngleLimit then
								self.motor.maxRpmOverride = self.motor.maxRpm[speedLevel]*slowMaxRpmFactor;
							else
								self.motor.maxRpmOverride = nil;
							end;
						end;
						if not allowedToDrive then
							acc = 0;
						end;
						if not moveForwards then
							acc = -acc;
							self:addBackTrafficCollisionTrigger()
						else
							self:removeBackTrafficCollisionTrigger()
						end;
						if self.maxAccelerationSpeed ~= nil then
							acc = Steerable.calculateRealAcceleration(self, acc, dt);
						end;
						WheelsUtil.updateWheelsPhysics(self, dt, self.lastSpeed, acc, not allowedToDrive, self.requiredDriveMode);
					end;
				
					if self.steering ~= nil then
						setRotation(self.steering, 0, self.rotatedTime*self.steeringSpeed, 0);
					end;
					
					if self.autoPilotDelayLeft > self.apDelayTimeToStopAutoPilot or self.autoPilotDelayRight > self.apDelayTimeToStopAutoPilot then
						self:stopAutopilot();		
					end;					
					
					if allowedToDrive then				
						self.motor.speedLevel = self.speed2Level;		
					else
						self.motor.speedLevel = 0;
					end;
					
					
		else
			self.autoPilotDelayLeft = 0;
			self.autoPilotDelayRight = 0;

		end;	
	end; 
end;

function APCombine:addBackTrafficCollisionTrigger()
	
	if self.apBackTrafficCollisionTrigger ~= nil then
		addTrigger(self.apBackTrafficCollisionTrigger, "onTrafficCollisionTrigger", self);
	end;
end;
function APCombine:removeBackTrafficCollisionTrigger()
	
	if self.apBackTrafficCollisionTrigger ~= nil then		
		removeTrigger(self.apBackTrafficCollisionTrigger);
	end;
end;

function APCombine:addOtherCombineCollisionTrigger()

	if self.otherCombineColliTriggerActiv then	
		if self.apOtherCombineCollisionTriggerL ~= nil and self.apOtherCombineCollisionTriggerR ~= nil then
			if self.autoPilotAreaLeft.active then
				addTrigger(self.apOtherCombineCollisionTriggerL, "onOtherCombineCollisionTrigger", self);
				removeTrigger(self.apOtherCombineCollisionTriggerR, "onOtherCombineCollisionTrigger", self);
				
			elseif self.autoPilotAreaRight.active then
				addTrigger(self.apOtherCombineCollisionTriggerR, "onOtherCombineCollisionTrigger", self);
				removeTrigger(self.apOtherCombineCollisionTriggerL, "onOtherCombineCollisionTrigger", self);
			end;
		end;
	end;	
end;
function APCombine:removeOtherCombineCollisionTrigger()

	if self.apOtherCombineCollisionTriggerL ~= nil and self.apOtherCombineCollisionTriggerR ~= nil then
		removeTrigger(self.apOtherCombineCollisionTriggerL);		
		removeTrigger(self.apOtherCombineCollisionTriggerR);	
    end;
end;
		
function APCombine:onTrafficCollisionTrigger(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
    if onEnter or onLeave then
        if otherId == g_currentMission.player.rootNode then
            if onEnter then
                self.numCollidingVehicles = self.numCollidingVehicles+1;
            elseif onLeave then
                self.numCollidingVehicles = math.max(self.numCollidingVehicles-1, 0);
            end;
        else
            local vehicle = g_currentMission.nodeToVehicle[otherId];
            if vehicle ~= nil and self.trafficCollisionIgnoreList[otherId] == nil then
                if onEnter then
                    self.numCollidingVehicles = self.numCollidingVehicles+1;
                elseif onLeave then
                    self.numCollidingVehicles = math.max(self.numCollidingVehicles-1, 0);
                end;
            end;
        end;
    end;
end;

function APCombine:onOtherCombineCollisionTrigger(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
    if onEnter or onLeave then
        if otherId == Player.rootNode then
            if onEnter then
                self.numCollidingVehicles = self.numCollidingVehicles+1;
            elseif onLeave then
                self.numCollidingVehicles = math.max(self.numCollidingVehicles-1, 0);
            end;
        else            
			local cutter = g_currentMission.nodeToVehicle[otherId];
            if cutter ~= nil and self.trafficCollisionIgnoreList[otherId] == nil then
                if onEnter then
                    self.numCollidingVehicles = self.numCollidingVehicles+1;
                elseif onLeave then
                    self.numCollidingVehicles = math.max(self.numCollidingVehicles-1, 0);
                end;
            end;
        end;
    end;
end;

function APCombine:onTrailerTrigger(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
    if onEnter or onLeave then
		local trailer = g_currentMission.nodeToVehicle[otherId];
        if trailer ~= nil and trailer.fillRootNode ~= nil then
            if onEnter then
                self.trailersInRange[trailer] = self.aiTrailerTriggers[triggerId].pipeState;
                self.trailerInRangePipeState = math.max(self.trailerInRangePipeState, self.aiTrailerTriggers[triggerId].pipeState);
                self.isTrailerInRange = true;
            else
                self.trailersInRange[trailer] = nil;
                self.isTrailerInRange = false;
                self.trailerInRangePipeState = 0;
                for trailer, pipeState in pairs(self.trailersInRange) do
                    self.trailerInRangePipeState = math.max(self.trailerInRangePipeState, pipeState);
                    self.isTrailerInRange = true;
                end;
            end;
        end;
    end;
end;

function APCombine:draw()

	if self.helpPanelActive then
		g_currentMission:addHelpButtonText(string.format(g_i18n:getText("AP_COMBINE_TEXTHELPPANELOFF"), self.typeDesc), InputBinding.AP_COMBINE_HELPPANEL);
		self.apCombHelpPanelOverlay:render();
		
		-- Labels
		setTextColor(0.0, 0.80, 1.0, 1.0);
		setTextBold(false);
		setTextAlignment(1);
		renderText(self.apCombHelpPanelTextPosX+0.055, self.apCombHelpPanelTextPosY-0.38, 0.018, "Working Width");

		
		renderText(self.apCombHelpPanelTextPosX+0.31, self.apCombHelpPanelTextPosY-0.39, 0.018, "Power" );
		
		renderText(self.apCombHelpPanelTextPosX+0.265, self.apCombHelpPanelTextPosY-0.38, 0.018, "Active");
		renderText(self.apCombHelpPanelTextPosX+0.265, self.apCombHelpPanelTextPosY-0.4, 0.018, "Side");
		
		setTextAlignment(0);
		renderText(self.apCombHelpPanelTextPosX+0.13, self.apCombHelpPanelTextPosY-0.37, 0.018, "Crop Selector" );
		
		renderText(self.apCombHelpPanelTextPosX+0.033, self.apCombHelpPanelTextPosY-0.225, 0.015, "Unload Mode:" );
		renderText(self.apCombHelpPanelTextPosX+0.2, self.apCombHelpPanelTextPosY-0.225, 0.015, "Anti-Collision Mode:" );

		-- Keys
		setTextColor(0.41, 0.70, 0.19, 1.0);
		renderText(self.apCombHelpPanelTextPosX+0.237, self.apCombHelpPanelTextPosY-0.455, 0.015, "KP4" );
		renderText(self.apCombHelpPanelTextPosX+0.271, self.apCombHelpPanelTextPosY-0.455, 0.015, "KP6" );
			
		renderText(self.apCombHelpPanelTextPosX+0.01, self.apCombHelpPanelTextPosY-0.225, 0.015, "KP7" );
		renderText(self.apCombHelpPanelTextPosX+0.17, self.apCombHelpPanelTextPosY-0.225, 0.015, "KP8" );


		renderText(self.apCombHelpPanelTextPosX+0.105, self.apCombHelpPanelTextPosY-0.45, 0.015, "KP2" );		
		renderText(self.apCombHelpPanelTextPosX+0.105, self.apCombHelpPanelTextPosY-0.4, 0.015, "KP5" );

		setTextAlignment(1);
		renderText(self.apCombHelpPanelTextPosX+0.31, self.apCombHelpPanelTextPosY-0.375, 0.015, "KP9" );
		
		
		if self.workWidth < 20 then
			renderText(self.apCombHelpPanelTextPosX+0.05, self.apCombHelpPanelTextPosY-0.455, 0.015, "KP1");
		end;		
		if self.workWidth > 0 then
			renderText(self.apCombHelpPanelTextPosX+0.005, self.apCombHelpPanelTextPosY-0.455, 0.015, "KP3");
	    end;
		
		-- ON/OFF Display
		setTextColor(1.0, 1.0, 1.0, 1.0);
		setTextBold(true);
		setTextAlignment(0);
		if not self.isAutopilotActivated then
		    renderText(self.apCombHelpPanelTextPosX+0.302, self.apCombHelpPanelTextPosY-0.4255, 0.016,string.format(g_i18n:getText("AP_COMBINE_TXT_STOP")));
		else
		    renderText(self.apCombHelpPanelTextPosX+0.287, self.apCombHelpPanelTextPosY-0.3425, 0.016,string.format(g_i18n:getText("AP_COMBINE_TXT_START")));
		end;

		-- Working Width Display
		setTextBold(false);
		renderText(self.apCombHelpPanelTextPosX+0.01, self.apCombHelpPanelTextPosY-0.425, 0.015,string.format(" %0.1f",self.workWidth));
		
		-- Crop Selector
		if self.autopilotId == 0 then
			setTextBold(false);			
			setTextColor(0.0, 0.9, 0.0, 1.0);
			setTextBold(true);
			renderText(self.apCombHelpPanelTextPosX+0.13, self.apCombHelpPanelTextPosY-0.425, 0.017, string.format(g_i18n:getText("AP_COMBINE_TXT_GRASS")));		
		end;
		if self.autopilotId == 1 then
			setTextBold(false);			
			setTextColor(0.0, 0.9, 0.0, 1.0);
			setTextBold(true);
			renderText(self.apCombHelpPanelTextPosX+0.13, self.apCombHelpPanelTextPosY-0.425, 0.017, string.format(g_i18n:getText("AP_COMBINE_TXT_GRYGRASS")));		
		end;				
		-- Active Side Display
		setTextColor(1.0, 1.0, 1.0, 1.0);
		setTextBold(false);		
		if self.autoPilotAreaRight.active then
			setTextColor(1.0, 1.0, 1.0, 1.0);
			setTextBold(true);
			renderText(self.apCombHelpPanelTextPosX+0.272, self.apCombHelpPanelTextPosY-0.43, 0.025, string.format(g_i18n:getText("AP_COMBINE_TXT_RIGHT")));
			setTextColor(0.56, 0.56, 0.56, 1.0);
			setTextBold(false);
			renderText(self.apCombHelpPanelTextPosX+0.24, self.apCombHelpPanelTextPosY-0.43, 0.025, string.format(g_i18n:getText("AP_COMBINE_TXT_LEFT")));
		end;
			
		if self.autoPilotAreaLeft.active then
			setTextColor(1.0, 1.0, 1.0, 1.0);
			setTextBold(true);
			renderText(self.apCombHelpPanelTextPosX+0.24, self.apCombHelpPanelTextPosY-0.43, 0.025, string.format(g_i18n:getText("AP_COMBINE_TXT_LEFT")));
			setTextColor(0.56, 0.56, 0.56, 1.0);
			setTextBold(false);
			renderText(self.apCombHelpPanelTextPosX+0.272, self.apCombHelpPanelTextPosY-0.43, 0.025, string.format(g_i18n:getText("AP_COMBINE_TXT_RIGHT")));
		end;
		
		-- Waitmode Display
		setTextColor(1.0, 1.0, 1.0, 1.0);	
		setTextBold(true);
		if self.waitMode then 
			renderText(self.apCombHelpPanelTextPosX+0.1, self.apCombHelpPanelTextPosY-0.225, 0.016,string.format(g_i18n:getText("AP_COMBINE_WAITMODE_ON"))); 
			--renderText(self.apCombHelpPanelTextPosX, self.apCombHelpPanelTextPosY-0.46, 0.019,string.format(g_i18n:getText("AP_COMBINE_WAITMODE_ON_EXPLANATION")));  
		else
			renderText(self.apCombHelpPanelTextPosX+0.1, self.apCombHelpPanelTextPosY-0.225, 0.016,string.format(g_i18n:getText("AP_COMBINE_WAITMODE_OFF")));
			--renderText(self.apCombHelpPanelTextPosX, self.apCombHelpPanelTextPosY-0.46, 0.019,string.format(g_i18n:getText("AP_COMBINE_WAITMODE_OFF_EXPLANATION")));  
		end;
		
		-- Anti-Collision Display
		if self.otherCombineColliTriggerActiv then 
			renderText(self.apCombHelpPanelTextPosX+0.31, self.apCombHelpPanelTextPosY-0.225, 0.016,string.format(g_i18n:getText("AP_COMBINE_COLLISIONTRIGGERMODE_ON")));  
			--renderText(self.apCombHelpPanelTextPosX, self.apCombHelpPanelTextPosY-0.4515, 0.019,string.format(g_i18n:getText("AP_COMBINE_COLLISIONTRIGGER_ON_EXPLANATION")));  
		else
			renderText(self.apCombHelpPanelTextPosX+0.31, self.apCombHelpPanelTextPosY-0.225, 0.016,string.format(g_i18n:getText("AP_COMBINE_COLLISIONTRIGGERMODE_OFF")));
			--renderText(self.apCombHelpPanelTextPosX, self.apCombHelpPanelTextPosY-0.515, 0.019,string.format(g_i18n:getText("AP_COMBINE_COLLISIONTRIGGER_OFF_EXPLANATION")));
		end;
		
		setTextBold(false);
		
		
	else
		g_currentMission:addHelpButtonText(string.format(g_i18n:getText("AP_COMBINE_TEXTHELPPANELON"), self.typeDesc), InputBinding.AP_COMBINE_HELPPANEL);
	end;
end;
