-- NI Modding
--
-- author  	Henly20 
-- date  	03-11-2012.
-- ni_modding@hotmail.com
-- http://nimodding.wordpress.com
  
JF1060 = {};

function JF1060.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Fillable, specializations) and SpecializationUtil.hasSpecialization(Attachable, specializations);
end;

function JF1060:load(xmlFile)
    self.setIsTurnedOn = SpecializationUtil.callSpecializationsFunction("setIsTurnedOn");
    self.fillScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fillScale#value"), 1);
    self.wasToFast = false;
    self.isTurnedOn = false;
	self.currentFruitType = FruitUtil.FRUITTYPE_UNKNOWN;
	
	self.lastArea = 0;
	self.lastAreaBiggerZero = self.lastArea > 0;

	self.pipeChaffParticleSystems = {};
    local i = 0;
    while true do
        local namei = string.format("vehicle.pipeChaffParticleSystems.pipeChaffParticleSystem(%d)", i);
		local nodei = Utils.indexToObject(self.components, getXMLString(xmlFile, namei .. "#index"));
		if nodei == nil then
			break;
		end; 
        Utils.loadParticleSystem(xmlFile, self.pipeChaffParticleSystems, namei, nodei, false, nil, self.baseDirectory)		
		Utils.setEmittingState(self.pipeChaffParticleSystems,false)
		i = i +1;		
    end;
	
	self.pipeGrassParticleSystems = {};
    local i = 0;
    while true do
        local namei = string.format("vehicle.pipeGrassParticleSystems.pipeGrassParticleSystem(%d)", i);
		local nodei = Utils.indexToObject(self.components, getXMLString(xmlFile, namei .. "#index"));
		if nodei == nil then
			break;
		end; 
        Utils.loadParticleSystem(xmlFile, self.pipeGrassParticleSystems, namei, nodei, false, nil, self.baseDirectory)		
		Utils.setEmittingState(self.pipeGrassParticleSystems,false)
		i = i +1;		
    end;
	
	self.isLoading = true;
	
    self.setPipeOpening = SpecializationUtil.callSpecializationsFunction("setPipeOpening");
    self.setPipeState = SpecializationUtil.callSpecializationsFunction("setPipeState");
    self.findAutoAimTrailerToUnload = JF1060.findAutoAimTrailerToUnload;
    self.findTrailerToUnload = JF1060.findTrailerToUnload;
    self.findTrailerRaycastCallback = JF1060.findTrailerRaycastCallback;
    self.onTrailerTrigger = JF1060.onTrailerTrigger;
  
      if self.isClient then

          local pipeSound = getXMLString(xmlFile, "vehicle.pipeSound#file");
          if pipeSound ~= nil and pipeSound ~= "" then
              pipeSound = Utils.getFilename(pipeSound, self.baseDirectory);
              self.pipeSound = createSample("pipeSound");
              loadSample(self.pipeSound, pipeSound, false);
              self.pipeSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pipeSound#pitchOffset"), 1);
              self.pipeSoundPitchScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pipeSound#pitchScale"), 0);
              self.pipeSoundPitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pipeSound#pitchMax"), 2.0);
          end;
      end;
 
      self.pipeNodes = {};
      self.numPipeStates = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.pipe#numStates"), 2);
      self.currentPipeState = 1;
      self.targetPipeState = 1;
      self.pipeStateIsUnloading = {};
      self.pipeStateIsAutoAiming = {};
      local unloadingPipeStates = Utils.getVectorNFromString(getXMLString(xmlFile, "vehicle.pipe#unloadingStates"));
      if unloadingPipeStates ~= nil then
          for i=1, table.getn(unloadingPipeStates) do
              if unloadingPipeStates[i] ~= nil then
                  self.pipeStateIsUnloading[unloadingPipeStates[i] ] = true;
              end;
          end;
      end;
      local autoAimPipeStates = Utils.getVectorNFromString(getXMLString(xmlFile, "vehicle.pipe#autoAimStates"));
      if autoAimPipeStates ~= nil then
          for i=1, table.getn(autoAimPipeStates) do
              if autoAimPipeStates[i] ~= nil then
                  self.pipeStateIsAutoAiming[autoAimPipeStates[i] ] = true;
              end;
          end;
      end;
      local i = 0;
      while true do
          local key = string.format("vehicle.pipe.node(%d)", i);
          if not hasXMLProperty(xmlFile, key) then
              break;
          end;
          local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index"));
          if node ~= nil then
              local entry = {};
              entry.node = node;
              entry.autoAimXRotation = Utils.getNoNil(getXMLBool(xmlFile, key.."#autoAimXRotation"), false);
              entry.autoAimYRotation = Utils.getNoNil(getXMLBool(xmlFile, key.."#autoAimYRotation"), false);
              entry.autoAimInvertZ = Utils.getNoNil(getXMLBool(xmlFile, key.."#autoAimInvertZ"), false);
              entry.states = {};
              for state=1,self.numPipeStates do
                  local stateKey = key..string.format(".state%d", state);
                  entry.states[state] = {};
                  local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, stateKey.."#translation"));
                  if x == nil or y == nil or z == nil then
                      x,y,z = getTranslation(node);
                  end;
                  entry.states[state].translation = {x,y,z};
                  local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, stateKey.."#rotation"));
                  if x == nil or y == nil or z == nil then
                      x,y,z = getRotation(node);
                  else
                      x,y,z = math.rad(x),math.rad(y),math.rad(z);
                  end;
                  entry.states[state].rotation = {x,y,z};
             end;
              local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#translationSpeeds"));
              if x ~= nil and y ~= nil and z ~= nil then
                  x,y,z = x*0.001,y*0.001,z*0.001;
                  if x ~= 0 or y ~= 0 or z ~= 0 then
                      entry.translationSpeeds = {x,y,z};
                  end;
              end;
              local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#rotationSpeeds"));
              if x ~= nil and y ~= nil and z ~= nil then
                  x,y,z = math.rad(x)*0.001,math.rad(y)*0.001,math.rad(z)*0.001;
                   if x ~= 0 or y ~= 0 or z ~= 0 then
                      entry.rotationSpeeds = {x,y,z};
                  end;
              end;
  
              local x,y,z = getTranslation(node);
              entry.curTranslation = {x,y,z};
              local x,y,z = getRotation(node);
              entry.curRotation = {x,y,z};
              table.insert(self.pipeNodes, entry);
          end;
          i = i + 1;
      end;
      if table.getn(self.pipeNodes) == 0 then
          -- use the old format
  
          local node = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.pipe#index"));
          if node ~= nil then
              self.numPipeStates = 2;
  
              local entry = {};
              entry.node = node;
              entry.states = {};
              entry.states[1] = {};
              entry.states[2] = {};
  
              local x,y,z = getRotation(node);
              entry.states[1].rotation = {0,0,z};
              entry.states[2].rotation = {math.rad(10),math.rad(-90),z};
  
              entry.rotationSpeeds = {0.00006, 0.0006, 0};
  
              local x,y,z = getRotation(node);
              entry.curRotation = {x,y,z};
  
              table.insert(self.pipeNodes, entry);
  
              self.pipeStateIsUnloading[2] = true;
          end;
      end;
  
      local pipeFlapLid = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.pipeFlapLid#index"));
      if pipeFlapLid ~= nil then
          if self.numPipeStates ~= 2 then
              print("Error: pipeFlapLid is only support with 2 pipe states in '"..self.configFileName.."'.");
          else
              local entry = {};
              entry.node = pipeFlapLid;
              entry.states = {};
              entry.states[1] = {};
              entry.states[2] = {};
  
              entry.states[1].rotation = {0,0,0};
              entry.states[2].rotation = {0,math.rad(-90),0};
 
              entry.rotationSpeeds = {0, 0.0006, 0};
  
              local x,y,z = getRotation(pipeFlapLid);
              entry.curRotation = {x,y,z};
  
              table.insert(self.pipeNodes, entry);
          end;
      end;
  
      if table.getn(self.pipeNodes) > 0 then
  
          self.pipeRaycastNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.pipe#raycastNodeIndex"));
   
          if self.pipeRaycastNode == nil then
              self.pipeRaycastNode = self.components[1].node;
          end;
      end;
      self.pipeRaycastDistance = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pipe#raycastDistance"), 10);
	  
      self.onTrailerTrigger = JF1060.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.rotateSpinners = {};
	local i=0;
	while true do
		local baseName = string.format("vehicle.rotateSpinners.node(%d)", i);
		local index = getXMLString(xmlFile, baseName.. "#index");
		local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.. "#rotationSpeed"));
		local rotationSpeed = {x,y,z};
		local runOutTime = Utils.getNoNil(getXMLFloat(xmlFile, baseName.. "#runOutTime"), 2)*1000;
		if index == nil or rotationSpeed == nil or runOutTime == nil then
			break;
		end;
		local node = Utils.indexToObject(self.components, index);
		if node ~= nil then
			local entry = {};
			entry.node = node;
			entry.runOutTime = runOutTime;
			entry.rotationSpeedMax = rotationSpeed;
			entry.rotationSpeedMin = {0,0,0};
			entry.rotationSpeedCurrent = {0,0,0};
			table.insert(self.rotateSpinners, entry);
		end;
		i = i+1;
	end;	
	
	local rotarySound = getXMLString(xmlFile, "vehicle.rotarySound#file");
	if rotarySound ~= nil and rotarySound ~= "" then
		rotarySound = Utils.getFilename(rotarySound, self.baseDirectory);
		self.rotarySound = createSample("rotarySound");
		loadSample(self.rotarySound, rotarySound, false);
		self.rotarySoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.rotarySound#pitchOffset"), 0);
		self.rotarySoundVolume = 0.0;
		self.rotarySoundVolumeMin = 0.0;
		self.rotarySoundVolumeMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.rotarySound#volume"), 1.0);
		self.rotarySoundVolumeAve = self.rotarySoundVolumeMax/2;		
		self.rotarySoundEnabled = false;
	end; 
	
	self.spinners = {};
	local count = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.spinners#count"), 0);
    for i=1, count do
		local spinner = {};
        local name = string.format("vehicle.spinners.spinner" .. "%d", i);
	    spinner.node = Utils.indexToObject(self.components, getXMLString(xmlFile, name .. "#index"));
	    spinner.direction = Utils.getNoNil(getXMLInt(xmlFile, name .. "#direction"), 1);
		table.insert(self.spinners, spinner);
    end;
	
	  self.pickupParticleSystems = {};
      local i = 0;
      while true do
        local namei = string.format("vehicle.pickupParticleSystems.pickupParticleSystems(%d)", i);
		local nodei = Utils.indexToObject(self.components, getXMLString(xmlFile, namei .. "#index"));
		if nodei == nil then
			break;
		end; 
        Utils.loadParticleSystem(xmlFile, self.pickupParticleSystems, namei, nodei, false, nil, self.baseDirectory)		
		i = i +1;		
      end;

	self.setTransRot = SpecializationUtil.callSpecializationsFunction("setTransRot");
	self.TransRotAnimation = getXMLString(xmlFile, "vehicle.TransRot#animationName");
	self.TransRot = false;
    self.setFruitOutput = SpecializationUtil.callSpecializationsFunction("setFruitOutput");	
	self.fruitOutputChange = true;	
	self.setPickup = SpecializationUtil.callSpecializationsFunction("setPickup");
	self.PickupAnimation = getXMLString(xmlFile, "vehicle.Pickup#animationName");
	self.Pickup = false;
	self.setArmOne = SpecializationUtil.callSpecializationsFunction("setArmOne");
	self.ArmOneAnimation = getXMLString(xmlFile, "vehicle.armOne#animationName");
	self.ArmOne = false;	
    self.printWarningTime = 0; 	
    self.setVehicleRpmUp = SpecializationUtil.callSpecializationsFunction("setVehicleRpmUp");
    self.saveMinRpm = 0; 	
	
end;

function JF1060:delete()
	if self.rotarySound ~= nil then
		delete(self.rotarySound);
	end;
    if self.pipeSound ~= nil then
        delete(self.pipeSound);
    end;
    for _, aiTrailerTrigger in pairs(self.aiTrailerTriggers) do
        removeTrigger(aiTrailerTrigger.node);
    end;
	Utils.deleteParticleSystem(self.pipeChaffParticleSystems);	
	Utils.deleteParticleSystem(self.pipeGrassParticleSystems);	
	if self.pickupParticleSystems ~= nil then
		Utils.deleteParticleSystem(self.pickupParticleSystems);
	end;	
end;

function JF1060:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	if not resetVehicles then
		if self.TransRotAnimation ~= nil then
			local isTransRotOn = getXMLBool(xmlFile, key.."#isTransRotOn");
			if isTransRotOn ~= nil then
				self:setTransRot(isTransRotOn, true);
				if self.playAnimation ~= nil then
					AnimatedVehicle.updateAnimationByName(self, self.TransRotAnimation, 99999999);
					if self.updateCylinderedInitial ~= nil then
						self:updateCylinderedInitial();
					end
				end
			end;
		end;
		if self.ArmOneAnimation ~= nil then
			local isArmOneOn = getXMLBool(xmlFile, key.."#isArmOneOn");
			if isArmOneOn ~= nil then
				self:setArmOne(isArmOneOn, true);
				if self.playAnimation ~= nil then
					AnimatedVehicle.updateAnimationByName(self, self.ArmOneAnimation, 99999999);
					if self.updateCylinderedInitial ~= nil then
						self:updateCylinderedInitial();
					end
				end
			end;
		end;		
	end;
    return BaseMission.VEHICLE_LOAD_OK;
end;

function JF1060:getSaveAttributesAndNodes(nodeIdent)
	local attributes = ' ';

	local mystring = 'isTransRotOn="' .. tostring(self.isTransRotOn) ..'"';	
	attributes = attributes .. mystring;
	local mystring = 'isArmOneOn="' .. tostring(self.isArmOneOn) ..'"';	
	attributes = attributes .. mystring;	

    local node = nil;
	return attributes, node;
end;

function JF1060:readStream(streamId, connection)
    local turnedOn = streamReadBool(streamId);
    self:setIsTurnedOn(turnedOn, true);
    local fruitOut = streamReadBool(streamId);
    self:setFruitOutput(fruitOut, true);
	self.isLoading = true;
	self.lastAreaBiggerZero = streamReadBool(streamId);
	self.currentFruitType = streamReadInt8(streamId);
    local pipeState = streamReadUIntN(streamId, 3);
    self:setPipeState(pipeState, true);
    self:setTransRot(streamReadBool(streamId), true);
	self:setPickup(streamReadBool(streamId), true);
	self:setArmOne(streamReadBool(streamId), true);
end;

function JF1060:writeStream(streamId, connection)
    streamWriteBool(streamId, self.isTurnedOn);
    streamWriteBool(streamId, self.fruitOutputChange);
	streamWriteBool(streamId, self.lastAreaBiggerZero);
	streamWriteInt8(streamId, self.currentFruitType);
    streamWriteUIntN(streamId, self.targetPipeState, 3);
    streamWriteBool(streamId, self.TransRot);
    streamWriteBool(streamId, self.Pickup);
	streamWriteBool(streamId, self.ArmOne);	
end;

function JF1060:readUpdateStream(streamId, timestamp, connection)
	if connection:getIsServer() then
		self.lastAreaBiggerZero = streamReadBool(streamId);
		self.currentFruitType = streamReadInt8(streamId);
	end;
end;

function JF1060:writeUpdateStream(streamId, connection, dirtyMask)
	if not connection:getIsServer() then
		streamWriteBool(streamId, self.lastAreaBiggerZero);
		streamWriteInt8(streamId, self.currentFruitType);
	end;
end;

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

function JF1060:keyEvent(unicode, sym, modifier, isDown)
end;

function JF1060:update(dt)
    if self:getIsActive() then 
	
		if self.isClient and self:getIsActiveForInput(false) and not self:hasInputConflictWithSelection() then
			if self.isTransRotOn then
				if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA) and not self.PTOId then
					self:setIsTurnedOn(not self.isTurnedOn);
				end;	
			end;
			if InputBinding.isPressed(InputBinding.IMPLEMENT_EXTRA) and self.PTOId then
				self.printWarningTime = self.time + 1000;
			end;			
		end;
		if self.isClient and self:getIsActiveForInput() and not self:hasInputConflictWithSelection() then
			if not self.isArmOneOn then
				if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) then
					self:setTransRot(false);
				end;	
			else
				if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) then
					self:setTransRot(not self.isTransRotOn);
				end;
			end;	 
			if self.isTransRotOn then
				if InputBinding.hasEvent(InputBinding.LOWER_IMPLEMENT) then
					self:setPickup(not self.isPickupOn);
				end;
				if InputBinding.hasEvent(InputBinding.TOGGLEOUPUT) then
					self:setFruitOutput(not self.fruitOutputChange);
				end;				
			else
				if InputBinding.hasEvent(InputBinding.EMPTY_GRAIN) then
					self:setArmOne(not self.isArmOneOn);					
				end;						
			end;	
	
		end;
	
        local doAutoAiming = self.pipeStateIsAutoAiming[self.currentPipeState];
        local targetTrailer = nil;
        if doAutoAiming then
            targetTrailer = self:findAutoAimTrailerToUnload(self.currentFruitType);
	
            if targetTrailer == nil then
                doAutoAiming = false;
            end;
        end;
        if (self.currentPipeState ~= self.targetPipeState or doAutoAiming) and self.targetPipeState <= self.numPipeStates then
            local autoAimX, autoAimY, autoAimZ;
            if doAutoAiming then
                autoAimX, autoAimY, autoAimZ = getWorldTranslation(targetTrailer.fillAutoAimTargetNode);
            end;
 
              local moved = false;
              for i=1, table.getn(self.pipeNodes) do
                  local nodeMoved = false;
                  local pipeNode = self.pipeNodes[i];
  
                  local state = pipeNode.states[self.targetPipeState];
                  if pipeNode.translationSpeeds ~= nil then
                      for i=1, 3 do
                          if pipeNode.curTranslation[i] ~= state.translation[i] then
                              nodeMoved = true;
                              if pipeNode.curTranslation[i] < state.translation[i] then
                                  pipeNode.curTranslation[i] = math.min(pipeNode.curTranslation[i] + dt*pipeNode.translationSpeeds[i], state.translation[i]);
                              else
                                  pipeNode.curTranslation[i] = math.max(pipeNode.curTranslation[i] - dt*pipeNode.translationSpeeds[i], state.translation[i]);
                              end;
                         end;
                     end;
                      setTranslation(pipeNode.node, pipeNode.curTranslation[1],pipeNode.curTranslation[2],pipeNode.curTranslation[3])
                  end;
                  if pipeNode.rotationSpeeds ~= nil then
                      for i=1, 3 do
                          local targetRotation = state.rotation[i];
                          if doAutoAiming then
                              if pipeNode.autoAimXRotation and i == 1 then
                                  local x,y,z = getWorldTranslation(pipeNode.node);
                                  local x,y,z = worldDirectionToLocal(getParent(pipeNode.node), autoAimX-x, autoAimY-y, autoAimZ-z);
                                  targetRotation = -math.atan2(y,z);
                                  if pipeNode.autoAimInvertZ then
                                      targetRotation = targetRotation+math.pi;
                                  end;
                                  targetRotation = Utils.normalizeRotationForShortestPath(targetRotation, pipeNode.curRotation[i]);
                              elseif pipeNode.autoAimYRotation and i == 2 then
                                  local x,y,z = getWorldTranslation(pipeNode.node);
                                  local x,y,z = worldDirectionToLocal(getParent(pipeNode.node), autoAimX-x, autoAimY-y, autoAimZ-z);
                                  targetRotation = math.atan2(x,z);
                                  if pipeNode.autoAimInvertZ then
                                      targetRotation = targetRotation+math.pi;
                                  end;
                                  targetRotation = Utils.normalizeRotationForShortestPath(targetRotation, pipeNode.curRotation[i]);
                              end;
                          end;
                          if pipeNode.curRotation[i] ~= targetRotation then
                              nodeMoved = true;
                              if pipeNode.curRotation[i] < targetRotation then
                                  pipeNode.curRotation[i] = math.min(pipeNode.curRotation[i] + dt*pipeNode.rotationSpeeds[i], targetRotation);
                              else
                                  pipeNode.curRotation[i] = math.max(pipeNode.curRotation[i] - dt*pipeNode.rotationSpeeds[i], targetRotation);
                              end;
                          end;
                      end;
                      setRotation(pipeNode.node, pipeNode.curRotation[1],pipeNode.curRotation[2],pipeNode.curRotation[3])
                  end;
                  moved = moved or nodeMoved;
  
                  if nodeMoved and self.setMovingToolDirty ~= nil then
                      self:setMovingToolDirty(pipeNode.node);
                  end;
              end;
              if not moved then
                  self.currentPipeState = self.targetPipeState;
              end;
          end;
  
          if self.isClient then
              if self.currentPipeState ~= self.targetPipeState then
                  if self.pipeSound ~= nil and not self.pipeSoundEnabled then
                      if self:getIsActiveForSound() then
                          setSamplePitch(self.pipeSound, self.pipeSoundPitchOffset);
                          playSample(self.pipeSound, 0, 1, 0);
                          self.pipeSoundEnabled = true;
                      end;
                  end;
              else
                  if self.pipeSound ~= nil and self.pipeSoundEnabled then
                      stopSample(self.pipeSound);
                      self.pipeSoundEnabled = false;
                  end;
              end;
          end;
	end;
	
	for i, jointDesc in pairs(self.componentJoints) do
	   setJointFrame(self.componentJoints[i].jointIndex, 0, self.componentJoints[i].jointNode);
	end;
end;

function JF1060:updateTick(dt)
    self.wasToFast = false;
    self.lastArea = 0;
			
    if self:getIsActive() then
		if self.PTOId then
			self:setIsTurnedOn(false);
		end;
		if not self.isTransRotOn then
			self:setIsTurnedOn(false);
		end;	
        if not self.isTurnedOn then		
			self.currentFruitType = FruitUtil.FRUITTYPE_UNKNOWN;	
		end;
		local deltaLevel = 0;
        self:setVehicleRpmUp(dt, self.isTurnedOn);		
		
		local volume = Utils.getMovedLimitedValues({self.rotarySoundVolume}, {self.rotarySoundVolumeMax}, {self.rotarySoundVolumeMin}, 1, 1200, dt, not self.isTurnedOn);
		local volumeAve = Utils.getMovedLimitedValues({self.rotarySoundVolume}, {self.rotarySoundVolumeAve}, {self.rotarySoundVolumeMin}, 1, 1200, dt, not self.isTurnedOn);
		-- self.rotarySoundVolume = volume[1];	
		if self.lastAreaBiggerZero then
			self.rotarySoundVolume = volume[1];	
		else
			self.rotarySoundVolume = volumeAve[1];		
		end;
		
		-- rotarySoundVolumeAve
			if self.isTurnedOn and not self.PTOId then
				if not self.rotarySoundEnabled and self:getIsActiveForSound() then
					playSample(self.rotarySound, 0, self.rotarySoundVolume, 0);
					setSamplePitch(self.rotarySound, self.rotarySoundPitchOffset);
					self.rotarySoundEnabled = true;
				end;
				if self.rotarySoundVolume < self.rotarySoundVolumeMax then
					setSampleVolume(self.rotarySound, self.rotarySoundVolume);
				end;
				else
				if self.rotarySoundEnabled then
					if self.rotarySoundVolume <= self.rotarySoundVolumeMin then
						stopSample(self.rotarySound);
						self.rotarySoundEnabled = false;
					else
						setSampleVolume(self.rotarySound, self.rotarySoundVolume);
					end;
				end;

			end;	
 		for k, spinner in pairs(self.rotateSpinners) do
			local values = Utils.getMovedLimitedValues(spinner.rotationSpeedCurrent, spinner.rotationSpeedMax, spinner.rotationSpeedMin, 3, spinner.runOutTime, dt, not self.isTurnedOn);
			spinner.rotationSpeedCurrent = values;
			rotate(spinner.node, unpack(spinner.rotationSpeedCurrent));
		end;
		
        if self.isTurnedOn then
            local toFast = self:doCheckSpeedLimit() and self.attacherVehicle.lastSpeed*3600 > 20;
            if self.isServer then
                if not toFast and self.isPickupOn then
                    local workAreasSend = {};
                    for k, workArea in pairs(self.workAreas) do
                        if self:getIsAreaActive(workArea) then
                            local x,y,z = getWorldTranslation(workArea.start);
                            local x1,y1,z1 = getWorldTranslation(workArea.width);
                            local x2,y2,z2 = getWorldTranslation(workArea.height);
                            table.insert(workAreasSend, {x,z,x1,z1,x2,z2});
                        end;
                    end;
                    if (table.getn(workAreasSend) > 0) then
					    local fruitTypeFix = false;
						local lastArea, fillType, fruitType = CutAreaEvent.runLocally(workAreasSend, self.fillTypes, self.currentFillType);
						self.lastArea = lastArea;
						self.lastAreaBiggerZero = (self.lastArea > 0);
						local pixelToSqm = g_currentMission:getFruitPixelsToSqm();
                        local sqm = lastArea*pixelToSqm;
                        local fruitType = FruitUtil.FRUITTYPE_UNKNOWN;
                        if self.fillLevel > self.capacity*self.fillTypeChangeThreshold and FruitUtil.fillTypeToFruitType[self.currentFillType] ~= nil and FruitUtil.fillTypeIsWindrow[self.currentFillType] then
                            fruitTypeFix = true;
                            fruitType = FruitUtil.fillTypeToFruitType[self.currentFillType];
                          end						
						
							if lastArea > 0 then
								self.currentFruitType = FruitUtil.fillTypeToFruitType[fillType];

								local pixelToSqm = g_currentMission:getFruitPixelsToSqm();
								local literPerSqm = FruitUtil.fruitIndexToDesc[self.currentFruitType].literPerSqm;
								local sqm = lastArea * pixelToSqm;
								
								local deltaLevel = 0;		
								local fruitType = FruitUtil.fillTypeToFruitType[fillType]
								deltaLevel = sqm * literPerSqm * 8 * self.fillScale;								
								self.pipeIsUnloading = false;
								if self.pipeStateIsUnloading[self.currentPipeState] then
									if not self.fruitOutputChange then
										if self.currentFruitType == FruitUtil.FRUITTYPE_GRASS or self.currentFruitType == FruitUtil.FRUITTYPE_DRYGRASS then 
												local trailer = self:findTrailerToUnload(Fillable.FILLTYPE_GRASS_WINDROW);
												if trailer == nil then
													self.pipeIsUnloading = false;
												else
													if trailer:allowFillType(Fillable.FILLTYPE_GRASS_WINDROW) then
														trailer:resetFillLevelIfNeeded(Fillable.FILLTYPE_GRASS_WINDROW);
													end;
													trailer:setFillLevel(trailer.fillLevel+deltaLevel, Fillable.FILLTYPE_GRASS_WINDROW);
													self.pipeIsUnloading = true;						
												end;
										elseif self.currentFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then
											local trailer = self:findTrailerToUnload(Fillable.FILLTYPE_CHAFF);
											if trailer == nil then
												self.pipeIsUnloading = false;
											else
												if trailer:allowFillType(Fillable.FILLTYPE_CHAFF) then
													trailer:resetFillLevelIfNeeded(Fillable.FILLTYPE_CHAFF);
												end;
												trailer:setFillLevel(trailer.fillLevel+deltaLevel, Fillable.FILLTYPE_CHAFF);
												self.pipeIsUnloading = true;
											end;
										end;
									else
										if self.currentFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then
											local trailer = self:findTrailerToUnload(Fillable.FILLTYPE_CHAFF);
											if trailer == nil then
												self.pipeIsUnloading = false;
											else
												if trailer:allowFillType(Fillable.FILLTYPE_CHAFF) then
													trailer:resetFillLevelIfNeeded(Fillable.FILLTYPE_CHAFF);
												end;
												trailer:setFillLevel(trailer.fillLevel+deltaLevel, Fillable.FILLTYPE_CHAFF);
												self.pipeIsUnloading = true;
											end;
										end;
									end;	
								end;
								g_server:broadcastEvent(CutAreaEvent:new(workAreasSend, fillType, fruitType));
							end;
                    end;
                end;
            end;
            self.wasToFast = toFast;
        end;
		if self.isTurnedOn and self.attacherVehicle.lastSpeed*3600 < 20 and self.lastAreaBiggerZero and self.isPickupOn then
			if not self.fruitOutputChange then
				if self.currentFruitType == FruitUtil.FRUITTYPE_GRASS or self.currentFruitType == FruitUtil.FRUITTYPE_DRYGRASS then 		
					Utils.setEmittingState(self.pipeGrassParticleSystems, true);	
					Utils.setEmittingState(self.pipeChaffParticleSystems, false);	
					Utils.setEmittingState(self.pickupParticleSystems, true);					
				else
					Utils.setEmittingState(self.pipeChaffParticleSystems, true);
					Utils.setEmittingState(self.pipeGrassParticleSystems, false);	
					Utils.setEmittingState(self.pickupParticleSystems, true);					
				end;
			else
				if self.currentFruitType == FruitUtil.FRUITTYPE_GRASS or self.currentFruitType == FruitUtil.FRUITTYPE_DRYGRASS then 		
					Utils.setEmittingState(self.pipeGrassParticleSystems, false);	
					Utils.setEmittingState(self.pipeChaffParticleSystems, true);	
					Utils.setEmittingState(self.pickupParticleSystems, true);					
				else
					Utils.setEmittingState(self.pipeChaffParticleSystems, true);
					Utils.setEmittingState(self.pipeGrassParticleSystems, false);	
					Utils.setEmittingState(self.pickupParticleSystems, true);					
				end;
			end;
		else
			Utils.setEmittingState(self.pipeChaffParticleSystems, false);
			Utils.setEmittingState(self.pipeGrassParticleSystems, false);	
			Utils.setEmittingState(self.pickupParticleSystems, false);			
		end;	
		if self.isTurnedOn and self.lastAreaBiggerZero then
			for k,spinner in pairs(self.spinners) do
				rotate(spinner.node, (3 * spinner.direction)*dt*2, 0, 0);
			end;
		end;
		
		if not self.isTransRotOn then	
			self:setPickup(false);
		end;
		if self:getIsActive() then
			if self.isTurnedOn then
				self:setPipeState(2);
			else
				self:setPipeState(1);
				self.isTrailerInRange = false;			
			end;
		end;		
    end;
end;

function JF1060:draw()
    if self:getIsActive() then
		if self.wasToFast and self.isPickupOn then
			g_currentMission:addWarning(g_i18n:getText("Dont_drive_to_fast") .. "\n" .. string.format(g_i18n:getText("Cruise_control_levelN"), "1", InputBinding.getKeyNamesOfDigitalAction(InputBinding.SPEED_LEVEL1)), 0.07+0.022, 0.019+0.029);
		end;

		if self.printWarningTime > self.time then
			g_currentMission:addWarning(g_i18n:getText("turnON_Error"), 0.018, 0.033);
		end;
		if self.isArmOneOn then 		
			if self.isTransRotOn then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("TRANSPORT"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA2);
			else
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("FIELD"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA2);
			end;
		end;

		if self.isClient then
			if self.currentFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then
				g_currentMission:setFruitOverlayFruitType(self.currentFruitType);
			end;
		end;
		if self.isTransRotOn then
			if not self.isPickupOn then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("LOWERPICKUP"), self.typeDesc), InputBinding.LOWER_IMPLEMENT);
			else
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("RAISEPICKUP"), self.typeDesc), InputBinding.LOWER_IMPLEMENT);
			end;
			if not self.PTOId then 
				if self.isTurnedOn then
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("turn_off_OBJECT"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA);
				else
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("turn_on_OBJECT"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA);
				end;
			end;	
			if (self.currentFruitType == FruitUtil.FRUITTYPE_GRASS or self.currentFruitType == FruitUtil.FRUITTYPE_DRYGRASS) or self.currentFruitType == FruitUtil.FRUITTYPE_UNKNOWN then		
				if self.fruitOutputChange then
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("Chaff"), self.typeDesc), InputBinding.TOGGLEOUPUT);
				else
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("Grass"), self.typeDesc), InputBinding.TOGGLEOUPUT);			
				end;		
			end;			
		else
			if self.isArmOneOn then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("TRANSPORTSPOUT"), self.typeDesc), InputBinding.EMPTY_GRAIN);
			else
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("FIELDSPOUT"), self.typeDesc), InputBinding.EMPTY_GRAIN);	   				
			end;	
			
		end;	
		
	end;
end;

function JF1060:onDetach()
	Utils.setEmittingState(self.pipeChaffParticleSystems, false);
	Utils.setEmittingState(self.pipeGrassParticleSystems, false);
	Utils.setEmittingState(self.pickupParticleSystems, false);	
    if self.deactivateOnDetach then
        JF1060.onDeactivate(self);
    else
    end;
    for _, aiTrailerTrigger in pairs(self.aiTrailerTriggers) do
        removeTrigger(aiTrailerTrigger.node);
    end;
    self.isTrailerInRange = false;
	self.isTurnedOn	= false;
	self.currentFruitType = FruitUtil.FRUITTYPE_UNKNOWN;
    for k, steerable in pairs(g_currentMission.steerables) do
        if self.attacherVehicleCopy == steerable then
            steerable.motor.minRpm = self.saveMinRpm;
            self.attacherVehicleCopy = nil;
        end;
    end;		
end;

function JF1060:onAttach(attacherVehicle)
    for _, aiTrailerTrigger in pairs(self.aiTrailerTriggers) do
        addTrigger(aiTrailerTrigger.node, "onTrailerTrigger", self);
    end;
    if self.attacherVehicleCopy == nil then
        self.attacherVehicleCopy = self.attacherVehicle;
    end;
    self.saveMinRpm = self.attacherVehicle.motor.minRpm;	
end;

function JF1060:onLeave()
	Utils.setEmittingState(self.pipeChaffParticleSystems, false);
	Utils.setEmittingState(self.pipeGrassParticleSystems, false);
	Utils.setEmittingState(self.pickupParticleSystems, false);	
    if self.deactivateOnLeave then
        JF1060.onDeactivate(self);
    else
       JF1060.onDeactivateSounds(self)
    end;
end;

function JF1060:onDeactivate()
	Utils.setEmittingState(self.pipeChaffParticleSystems, false);
	Utils.setEmittingState(self.pipeGrassParticleSystems, false);
	Utils.setEmittingState(self.pickupParticleSystems, false);	
    self.isTurnedOn = false;
    JF1060.onDeactivateSounds(self);
end;

function JF1060:onDeactivateSounds()
      if self.pipeSound ~= nil and self.pipeSoundEnabled then
          stopSample(self.pipeSound);
          self.pipeSoundEnabled = false;
      end;
	if self.rotarySoundEnabled then
		stopSample(self.rotarySound);
		self.rotarySoundEnabled = false;
	end;
 end;

function JF1060:setIsTurnedOn(turnedOn, noEventSend)
    SetTurnedOnEvent.sendEvent(self, turnedOn, noEventSend)
    self.isTurnedOn = turnedOn;
end;

function JF1060:setFruitOutput(fruitOut, noEventSend)
	FruitOutputEvent.sendEvent(self, fruitOut, noEventSend);
	self.fruitOutputChange = fruitOut;
end;

function JF1060:setPipeOpening(pipeOpening, noEventSend)
      if pipeOpening then
          self:setPipeState(2, noEventSend);
      else
          self:setPipeState(1, noEventSend);
      end;
end;
  
function JF1060:setPipeState(pipeState, noEventSend)
      if self.targetPipeState ~= pipeState then
          if noEventSend == nil or noEventSend == false then
              if g_server ~= nil then
                  g_server:broadcastEvent(SetPipeStateEvent:new(self, pipeState));
              else
                  g_client:getServerConnection():sendEvent(SetPipeStateEvent:new(self, pipeState), nil, nil, self);
              end;
          end;
          self.targetPipeState = pipeState;
          self.currentPipeState = 0;
      end;
end;
 
function JF1060:findAutoAimTrailerToUnload(fruitType)
    local trailer = nil;
    local trailerIsAttached = false;
    local smallestTrailerId = nil;
    if self.trailersInRange ~= nil then
        for trailerInRange, pipeStage in pairs(self.trailersInRange) do
		    if trailerInRange.isDeleted then
				self.trailersInRange[trailerInRange] = nil;
			else
            if (trailerInRange:allowFillType(Fillable.FILLTYPE_GRASS_WINDROW) or trailerInRange:allowFillType(Fillable.FILLTYPE_CHAFF)) and trailerInRange.allowFillFromAir and trailerInRange.fillLevel < trailerInRange.capacity then
                local id = networkGetObjectId(trailerInRange);
                 local isAttached = trailerInRange:getIsAttachedTo(self)
                  if trailer == nil or (isAttached and not trailerIsAttached) or (isAttached == trailerIsAttached and id < smallestTrailerId) then
                      trailer = trailerInRange;
                      smallestTrailerId = id;
                      trailerIsAttached = isAttached
                  end;
                end;
            end;
		end;
	end;
    return trailer;
end;
  
function JF1060:findTrailerToUnload(fruitType)
  
      local x,y,z = getWorldTranslation(self.pipeRaycastNode);
      local dx,dy,dz = localDirectionToWorld(self.pipeRaycastNode, 0,-1,0);
  
      self.trailerFound = 0;
      self.trailerFoundDistance = 0;	  
      raycastAll(x, y, z, dx,dy,dz, "findTrailerRaycastCallback", self.pipeRaycastDistance, self);
		
      local trailer = g_currentMission.nodeToVehicle[self.trailerFound];
      if trailer == nil or not (trailer:allowFillType(Fillable.FILLTYPE_GRASS_WINDROW) or trailer:allowFillType(Fillable.FILLTYPE_CHAFF)) or not trailer.allowFillFromAir or trailer.fillLevel >= trailer.capacity then
          return nil;
      end;
      return trailer, self.trailerFoundDistance;
	  

end;
  
function JF1060:findTrailerRaycastCallback(transformId, x, y, z, distance)
 
    local vehicle = g_currentMission.nodeToVehicle[transformId];
    if vehicle ~= nil then
		if vehicle.exactFillRootNode == transformId then
			self.trailerFound = transformId;
            self.trailerFoundDistance = distance;			
			return false;
		end;
    end;
    return true;
end;

function JF1060: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 or onStay then
                  self.trailersInRange[trailer] = self.aiTrailerTriggers[triggerId].pipeState;
                  self.trailerInRangePipeState = math.max(self.trailerInRangePipeState, self.aiTrailerTriggers[triggerId].pipeState);
                  self.isTrailerInRange = true;
            elseif onLeave then
                  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 = false;
                 end;
              end;
          end;
      end; 

end;

function JF1060:setVehicleRpmUp(dt, isActive)
    if self.attacherVehicle ~= nil and self.saveMinRpm ~= 0 then
        if dt ~= nil then
            if isActive == true then
                self.attacherVehicle.motor.minRpm = math.max(self.attacherVehicle.motor.minRpm-dt, -1000);
            else
                self.attacherVehicle.motor.minRpm = math.min(self.attacherVehicle.motor.minRpm+dt*2, self.saveMinRpm);
            end;
        else
            self.attacherVehicle.motor.minRpm = self.saveMinRpm;
        end;
        if self.attacherVehicle.isMotorStarted then
            local fuelUsed = 0.00000011*math.abs(self.attacherVehicle.motor.minRpm);
            self.attacherVehicle:setFuelFillLevel(self.attacherVehicle.fuelFillLevel-fuelUsed);
            g_currentMission.missionStats.statistics.fuelUsage.total = g_currentMission.missionStats.statistics.fuelUsage.total + fuelUsed;
            g_currentMission.missionStats.statistics.fuelUsage.session = g_currentMission.missionStats.statistics.fuelUsage.session + fuelUsed;
        end;
    end;
end;

function JF1060:setTransRot(isTransRot,noEventSend)
	SetTransRotEvent.sendEvent(self, isTransRot, noEventSend);
	-- Play TransRot animation --
	self.isTransRotOn = isTransRot;
	if self.isTransRotOn then
		if self.TransRotAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.TransRotAnimation, 1, nil, true);
			self.TransRot = true;
		end;
	else
		if self.TransRotAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.TransRotAnimation, -1, nil, true);
			self.TransRot = false;
		end;
	end;	
end;

function JF1060:setPickup(isPickup,noEventSend)
	SetPickupEvent.sendEvent(self, isPickup, noEventSend);
	-- Play Pickup animation --
	self.isPickupOn = isPickup;
	if self.isPickupOn then
		if self.PickupAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.PickupAnimation, 1, nil, true);
			self.Pickup = true;

		end;
	else
		if self.PickupAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.PickupAnimation, -1, nil, true);
			self.Pickup = false;
	
		end;
	end;
end;

function JF1060:setArmOne(isArmOne,noEventSend)
	SetArmOneEvent.sendEvent(self, isArmOne, noEventSend);
	-- Play ArmOne animation --
	self.isArmOneOn = isArmOne;
	if self.isArmOneOn then
		if self.ArmOneAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.ArmOneAnimation, -1, nil, true);
			self.ArmOne = true;
		end;
	else
		if self.ArmOneAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.ArmOneAnimation, 1, nil, true);
			self.ArmOne = false;
		end;
	end;	
end;

SetTransRotEvent = {};
SetTransRotEvent_mt = Class(SetTransRotEvent, Event);

InitEventClass(SetTransRotEvent, "SetTransRotEvent");

function SetTransRotEvent:emptyNew()
    local self = Event:new(SetTransRotEvent_mt);
    self.className="SetTransRotEvent";
    return self;
end;

function SetTransRotEvent:new(vehicle, isTransRot)
    local self = SetTransRotEvent:emptyNew()
    self.vehicle = vehicle;
	self.isTransRot = isTransRot;
    return self;
end;

function SetTransRotEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.isTransRot = streamReadBool(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function SetTransRotEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteBool(streamId, self.isTransRot);
end;

function SetTransRotEvent:run(connection)  
	if self.vehicle ~= nil then 
		self.vehicle:setTransRot(self.isTransRot, true);
	end;
    if not connection:getIsServer() then
        g_server:broadcastEvent(SetTransRotEvent:new(self.vehicle, self.isTransRot), nil, connection, self.vehicle);
    end;
end;

function SetTransRotEvent.sendEvent(vehicle, isTransRot, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(SetTransRotEvent:new(vehicle, isTransRot), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(SetTransRotEvent:new(vehicle, isTransRot));
		end;
	end;
end;

SetPipeStateEvent = {};
SetPipeStateEvent_mt = Class(SetPipeStateEvent, Event);
  
InitEventClass(SetPipeStateEvent, "SetPipeStateEvent");
  
function SetPipeStateEvent:emptyNew()
      local self = Event:new(SetPipeStateEvent_mt);
      self.className = "SetPipeStateEvent";
      return self;
end;
  
function SetPipeStateEvent:new(object, pipeState)
      local self = SetPipeStateEvent:emptyNew()
      self.object = object;
      self.pipeState = pipeState;
      assert(self.pipeState >= 0 and self.pipeState < 8);
      return self;
end;
  
function SetPipeStateEvent:readStream(streamId, connection)
      local id = streamReadInt32(streamId);
      self.pipeState = streamReadUIntN(streamId, 3);
      self.object = networkGetObject(id);
      self:run(connection);
end;
  
function SetPipeStateEvent:writeStream(streamId, connection)
      streamWriteInt32(streamId, networkGetObjectId(self.object));
      streamWriteUIntN(streamId, self.pipeState, 3);
end;
  
function SetPipeStateEvent:run(connection)
	if self.object ~= nil then
		self.object:setPipeState(self.pipeState, true);
	end;
      if not connection:getIsServer() then
          g_server:broadcastEvent(SetPipeStateEvent:new(self.object, self.pipeState), nil, connection, self.object);
      end;
end;

FruitOutputEvent = {};
FruitOutputEvent_mt = Class(FruitOutputEvent, Event);
  
InitEventClass(FruitOutputEvent, "FruitOutputEvent");
  
function FruitOutputEvent:emptyNew()
     local self = Event:new(FruitOutputEvent_mt);
      self.className="FruitOutputEvent";
      return self;
end;
  
function FruitOutputEvent:new(object, fruitOut)
      local self = FruitOutputEvent:emptyNew()
      self.object = object;
      self.fruitOut = fruitOut;
      return self;
end;
  
function FruitOutputEvent:readStream(streamId, connection)
      local id = streamReadInt32(streamId);
      self.fruitOut = streamReadBool(streamId);
      self.object = networkGetObject(id);
      self:run(connection);
end;
  
function FruitOutputEvent:writeStream(streamId, connection)
      streamWriteInt32(streamId, networkGetObjectId(self.object));
      streamWriteBool(streamId, self.fruitOut);
end;
  
function FruitOutputEvent:run(connection)
      if not connection:getIsServer() then
         g_server:broadcastEvent(self, false, connection, self.object);
      end;
	if self.object ~= nil then	  
		self.object:setFruitOutput(self.fruitOut, true);
	end;
end;
  
function FruitOutputEvent.sendEvent(vehicle, fruitOut, noEventSend)
      if fruitOut ~= vehicle.fruitOutputChange then
          if noEventSend == nil or noEventSend == false then
              if g_server ~= nil then
                  g_server:broadcastEvent(FruitOutputEvent:new(vehicle, fruitOut), nil, nil, vehicle);
              else
                  g_client:getServerConnection():sendEvent(FruitOutputEvent:new(vehicle, fruitOut));
              end;
          end;
      end;
end;


SetPickupEvent = {};
SetPickupEvent_mt = Class(SetPickupEvent, Event);

InitEventClass(SetPickupEvent, "SetPickupEvent");

function SetPickupEvent:emptyNew()
    local self = Event:new(SetPickupEvent_mt);
    self.className="SetPickupEvent";
    return self;
end;

function SetPickupEvent:new(vehicle, isPickup)
    local self = SetPickupEvent:emptyNew()
    self.vehicle = vehicle;
	self.isPickup = isPickup;
    return self;
end;

function SetPickupEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.isPickup = streamReadBool(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function SetPickupEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteBool(streamId, self.isPickup);
end;

function SetPickupEvent:run(connection)  
 	if self.vehicle ~= nil then
		self.vehicle:setPickup(self.isPickup, true);
	end;
    if not connection:getIsServer() then
        g_server:broadcastEvent(SetPickupEvent:new(self.vehicle, self.isPickup), nil, connection, self.vehicle);
    end;
end;

function SetPickupEvent.sendEvent(vehicle, isPickup, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(SetPickupEvent:new(vehicle, isPickup), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(SetPickupEvent:new(vehicle, isPickup));
		end;
	end;
end;


SetArmOneEvent = {};
SetArmOneEvent_mt = Class(SetArmOneEvent, Event);

InitEventClass(SetArmOneEvent, "SetArmOneEvent");

function SetArmOneEvent:emptyNew()
    local self = Event:new(SetArmOneEvent_mt);
    self.className="SetArmOneEvent";
    return self;
end;

function SetArmOneEvent:new(vehicle, isArmOne)
    local self = SetArmOneEvent:emptyNew()
    self.vehicle = vehicle;
	self.isArmOne = isArmOne;
    return self;
end;

function SetArmOneEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.isArmOne = streamReadBool(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function SetArmOneEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteBool(streamId, self.isArmOne);
end;

function SetArmOneEvent:run(connection)   
	if self.vehicle ~= nil then
		self.vehicle:setArmOne(self.isArmOne, true);
	end;
    if not connection:getIsServer() then
        g_server:broadcastEvent(SetArmOneEvent:new(self.vehicle, self.isArmOne), nil, connection, self.vehicle);
    end;
end;

function SetArmOneEvent.sendEvent(vehicle, isArmOne, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(SetArmOneEvent:new(vehicle, isArmOne), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(SetArmOneEvent:new(vehicle, isArmOne));
		end;
	end;
end;

