--
-- Ropa Euro Maus 3
--
-- @author: 	Burner
-- @date: 		22.02.2012
--

RopaEuroMaus = {};

RopaEuroMaus.PICKUP = 1;
RopaEuroMaus.FRONTARM = 2;
RopaEuroMaus.COUNTERWEIGHT = 3;
RopaEuroMaus.ELEVATOR = 4;
RopaEuroMaus.ELEVATOR_PART2 = 5;
RopaEuroMaus.SEAT = 6;

function RopaEuroMaus.prerequisitesPresent(specializations)
	return SpecializationUtil.hasSpecialization(Steerable, specializations);
end;

function RopaEuroMaus:load(xmlFile)
	self.setIsTurnedOn = SpecializationUtil.callSpecializationsFunction("setIsTurnedOn");
	self.isTurnedOn = false;
	
	self.foldPickup = SpecializationUtil.callSpecializationsFunction("foldPickup");
	self.foldElevator = SpecializationUtil.callSpecializationsFunction("foldElevator");
	self.setCurrentTool = SpecializationUtil.callSpecializationsFunction("setCurrentTool");
	
	self.fallOut = true;
	self.isShovel = nil;
	self.isInActiveTipRange = false;
	self.isSugarbeetCleanerLoader = true;
	
	if self.isClient then
		local threshingStartSound = getXMLString(xmlFile, "vehicle.threshingStartSound#file");
		if threshingStartSound ~= nil and threshingStartSound ~= "" then
			threshingStartSound = Utils.getFilename(threshingStartSound, self.baseDirectory);
			self.threshingStartSound = createSample("threshingStartSound");
			loadSample(self.threshingStartSound, threshingStartSound, false);
			self.threshingStartSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.threshingStartSound#pitchOffset"), 1);
			self.threshingStartSoundPitchScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.threshingStartSound#pitchScale"), 0);
			self.threshingStartSoundPitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.threshingStartSound#pitchMax"), 2.0);
		end;
		self.threshingSoundActive = false;
		local threshingSound = getXMLString(xmlFile, "vehicle.threshingSound#file");
		if threshingSound ~= nil and threshingSound ~= "" then
			threshingSound = Utils.getFilename(threshingSound, self.baseDirectory);
			self.threshingSound = createSample("threshingSound");
			loadSample(self.threshingSound, threshingSound, false);
			self.threshingSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.threshingSound#pitchOffset"), 1);
			self.threshingSoundPitchScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.threshingSound#pitchScale"), 0);
			self.threshingSoundPitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.threshingSound#pitchMax"), 2.0);
		end;

		local threshingStopSound = getXMLString(xmlFile, "vehicle.threshingStopSound#file");
		if threshingStopSound ~= nil and threshingStopSound ~= "" then
			threshingStopSound = Utils.getFilename(threshingStopSound, self.baseDirectory);
			self.threshingStopSound = createSample("threshingStopSound");
			loadSample(self.threshingStopSound, threshingStopSound, false);
			self.threshingStopSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.threshingStopSound#pitchOffset"), 1);
			self.threshingStopSoundPitchScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.threshingStopSound#pitchScale"), 0);
			self.threshingStopSoundPitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.threshingStopSound#pitchMax"), 2.0);
		end;
	end;
	
	local aiThreshingSound  = getXMLString(xmlFile, "vehicle.aiTreshingSound#file");
	if aiThreshingSound  ~= nil and aiThreshingSound  ~= "" then
		aiThreshingSound  = Utils.getFilename(aiThreshingSound, self.baseDirectory);
		self.aiThreshingSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.aiTreshingSound#pitchOffset"), 0);
		self.aiThreshingSoundRadius = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.aiTreshingSound#radius"), 50);
		self.aiThreshingSoundInnerRadius = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.aiTreshingSound#innerRadius"), 10);
		self.aiThreshingSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.aiTreshingSound#volume"), 1);
		self.aiThreshingSound = createAudioSource("aiThreshingSound", aiThreshingSound, self.aiThreshingSoundRadius, self.aiThreshingSoundInnerRadius, self.aiThreshingSoundVolume, 0);
		link(self.components[1].node, self.aiThreshingSound);
		setVisibility(self.aiThreshingSound, false);
	end;
	
	self.trailerRaycastCallback = RopaEuroMaus.trailerRaycastCallback;
	self.unloadingTrigger = {};
	self.unloadingTrigger.node = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.unloadingTrigger#index"));
	self.unloadingTrigger.distance = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.unloadingTrigger#raycastDistance"), 7);
	self.unloadingCapacity = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.unloadingCapacity"), 180);

	self.currentTool = RopaEuroMaus.PICKUP;
	
	self.planeScrollParts = {};
	local i = 0;
	while true do
		local key = string.format("vehicle.planeScrollParts.planeScrollPart(%d)", i);
		if not hasXMLProperty(xmlFile, key) then
			break;
		end;
		local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index"));
		local speed = Utils.getVectorNFromString(getXMLString(xmlFile, key.."#speed"), 2);
		if node ~= nil and speed then
			table.insert(self.planeScrollParts, {node=node, speed=speed, currentLength=0});
		end;
		i = i +1;
	end;
	
	self.driveShaftPart1 = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.driveShaft#part1"));
	self.driveShaftPart2 = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.driveShaft#part2"));
	
	self.conveyorScrollParts = {};
	local i = 0;
	while true do
		local key = string.format("vehicle.conveyorScrollParts.conveyorScrollPart(%d)", i);
		if not hasXMLProperty(xmlFile, key) then
			break;
		end;
		local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index"));
		local length = Utils.getNoNil(getXMLFloat(xmlFile, key.."#length"), 1);
		local speed = Utils.getVectorNFromString(getXMLString(xmlFile, key.."#speed"), 2);
		if node ~= nil and length then
			table.insert(self.conveyorScrollParts, {node=node, speed=speed, currentLength=0});
		end;
		i = i +1;
	end;
	
	self.displayEmptyInfo = false;
	self.displayEmptyInfoTime = 0;
	
	self.fillDelta = 0;
	
	self.unloadingParticleSystems = {};
	local i=0;
	while true do
		local key = string.format("vehicle.unloadingParticleSystems.unloadingParticleSystem(%d)", i);
		local node = getXMLString(xmlFile, key.. "#node");
		local t = getXMLString(xmlFile, key .. "#type");
		local desc = FruitUtil.fruitTypes[t];
		if node == nil or t == nil then
			break;
		end;
		node = Utils.indexToObject(self.components, node);
		if node ~= nil and desc ~= nil then
			local psFile = getXMLString(xmlFile, key.. "#file");
			local unloadingParticleSystem = {};
			unloadingParticleSystem.particleSystem = {};
			local fillType = FruitUtil.fruitTypeToFillType[desc.index];
			if self.unloadingParticleSystems[fillType] == nil then
				self.unloadingParticleSystems[fillType] = {}
			end;
			StaticParticleSystem.loadParticleSystem(xmlFile, self.unloadingParticleSystems[fillType], key, self.components, false, nil, self.baseDirectory);
		end;
		i = i+1;
	end;
	
	self.groundParticleSystems = {};
	local i=0;
	while true do
		local baseName = string.format("vehicle.groundParticleSystems.groundParticleSystem(%d)", i);
		if not hasXMLProperty(xmlFile, baseName) then
			break;
		end;
		local entry = {};
		entry.ps = {};
		Utils.loadParticleSystem(xmlFile, entry.ps, baseName, self.components, false, nil, self.baseDirectory);
		if table.getn(entry.ps) > 0 then
			entry.isActive = false;
				table.insert(self.groundParticleSystems, entry);
			end;
		i = i+1;
	end;
	
	self.psActive = false;
	
	self.trailerUnderElevator = false;
	self.displayNoTrailerInfo = false;
	self.displayNoTrailerInfoTime = 0;
	
	self.fillTypesBackup = {}
	self.fillTypesBackup = self.fillTypes;
	
	local attacherJoint = {};
	attacherJoint.node = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.attacherJoint#index"));
	if attacherJoint.node ~= nil then
		attacherJoint.topReferenceNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.attacherJoint#topReferenceNode"));
		attacherJoint.rootNode = Utils.getNoNil(Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.attacherJoint#rootNode")), self.components[1].node);
		attacherJoint.fixedRotation = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.attacherJoint#fixedRotation"), false);

		attacherJoint.allowsJointRotLimitMovement = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.attacherJoint#allowsJointRotLimitMovement"), true);
		attacherJoint.allowsJointTransLimitMovement = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.attacherJoint#allowsJointTransLimitMovement"), true);

		--load joint limit scales
		local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile,  "vehicle.attacherJoint#rotLimitScale"));
		attacherJoint.rotLimitScale = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) };
		local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile,  "vehicle.attacherJoint#transLimitScale"));
		attacherJoint.transLimitScale = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) };

		local jointTypeStr = getXMLString(xmlFile, "vehicle.attacherJoint#jointType")
		local jointType;

		if jointTypeStr ~= nil then
			jointType = Vehicle.jointTypeNameToInt[jointTypeStr];
			if jointType == nil then
				print("Warning: invalid jointType " .. jointTypeStr);
			end;
		else
			print("Warning: missing jointType");
		end;
		if jointType == nil then
			local needsTrailerJoint = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.attacherJoint#needsTrailerJoint"), false);
			local needsLowTrailerJoint = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.attacherJoint#needsLowJoint"), false);
			if needsTrailerJoint then
				if needsLowTrailerJoint then
					jointType = Vehicle.JOINTTYPE_TRAILERLOW;
				else
					jointType = Vehicle.JOINTTYPE_TRAILER;
				end;
			else
				jointType = Vehicle.JOINTTYPE_IMPLEMENT;
			end;
		end;
		attacherJoint.jointType = jointType;
		self.attacherJoint = attacherJoint;
	end;
	
	table.insert(g_currentMission.attachables, self);
	
	self.hydraulicSoundEnabled = false;
	local hydraulicSound = getXMLString(xmlFile, "vehicle.hydraulicSound#file");
	if hydraulicSound ~= nil and hydraulicSound ~= "" then
		hydraulicSound  = Utils.getFilename(hydraulicSound, self.baseDirectory);
		self.hydraulicSound = createSample("hydraulicSound");
		loadSample(self.hydraulicSound, hydraulicSound, false);
		self.hydraulicSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.hydraulicSound#pitchOffset"), 1);
		self.hydraulicSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.hydraulicSound#pitchMax"), 2.0);
	end;
	--[[
	self.tipReferencePoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.tipReferencePoint#index"));
	if self.tipReferencePoint == nil then
		self.tipReferencePoint = self.components[1].node;
	end;
]]
	self.tipReferencePoints = {};
	local tipRef = {};
	tipRef.node = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.tipReferencePoint#index"));
	table.insert(self.tipReferencePoints, tipRef);
	if self.tipReferencePoints[1].node == nil then
		self.tipReferencePoints[1].node = self.components[1].node;
	end;

	self.allowFillFromShovelTrigger = false;
	
	if self.altTipPoint ~= nil then
		self.altTipPointBackup = self.altTipPoint;
		self.altTipPoint = nil;
	end;
end;

function RopaEuroMaus:readStream(streamId, connection)
	self:setIsTurnedOn(streamReadBool(streamId), true);
	self:setCurrentTool(streamReadInt8(streamId), true);
end;

function RopaEuroMaus:writeStream(streamId, connection)
	streamWriteBool(streamId, self.isTurnedOn);
	streamWriteInt8(streamId, self.currentTool);
end;

function RopaEuroMaus:delete()
	if self.threshingStartSound ~= nil then
		delete(self.threshingStartSound);
	end;
	if self.threshingSoundActive then
		delete(self.threshingSound);
		self.threshingSoundActive = false;
	end;
	if self.threshingStopSound ~= nil then
		delete(self.threshingStopSound);
	end;
	--if self.hydraulicSound ~= nil then
		--delete(self.hydraulicSound);
	--end;
	for k, ps in pairs(self.unloadingParticleSystems) do
		Utils.deleteParticleSystem(self.unloadingParticleSystems[k]);
	end;
	for _, entry in ipairs(self.groundParticleSystems) do
		Utils.deleteParticleSystem(entry.ps);
	end;
end;

function RopaEuroMaus:update(dt)
	self.isInActiveTipRange = true;
	
	if self:getIsActive() then
		if self.isClient then
			-- work sound
			if self.isTurnedOn and self:getIsActiveForSound() then
				if not self.threshingSoundActive and self.threshingSound ~= nil and self.playThreshingSoundTime <= self.time then
					playSample(self.threshingSound, 0, 1, 0);
					self.threshingSoundActive = true;
				end;
			end;
		end;
		
		-- rotate driveshaft
		rotate(self.driveShaftPart1, 0, 0, 2.5 * self.lastSpeedReal * self.movingDirection * dt);
		rotate(self.driveShaftPart2, 0, 0, 2.5 * self.lastSpeedReal * self.movingDirection * dt);
	end;
	
	-- work sound outside vehicle
	if self.isTurnedOn and not self:getIsActiveForSound() then
		if self.aiThreshingSound ~= nil then
			setVisibility(self.aiThreshingSound, true);
		end;
	else
		if self.aiThreshingSound ~= nil then
			setVisibility(self.aiThreshingSound, false);
		end;		
	end;
	
	if self:getIsActiveForInput() then
		-- select active tool
		if InputBinding.hasEvent(InputBinding.EuroMaus_ActivatePickup) then
			self:setCurrentTool(RopaEuroMaus.PICKUP);
		elseif InputBinding.hasEvent(InputBinding.EuroMaus_ActivateFrontArm) then
			self:setCurrentTool(RopaEuroMaus.FRONTARM);
		elseif InputBinding.hasEvent(InputBinding.EuroMaus_ActivateCounterweight) then
			self:setCurrentTool(RopaEuroMaus.COUNTERWEIGHT);
		elseif InputBinding.hasEvent(InputBinding.EuroMaus_ActivateSeat) then
			self:setCurrentTool(RopaEuroMaus.SEAT);
		end;
		
		if self.animationParts[8].clipEndTime then
			if InputBinding.hasEvent(InputBinding.EuroMaus_ActivateElevator) then
				self:setCurrentTool(RopaEuroMaus.ELEVATOR);
			end;
			if InputBinding.hasEvent(InputBinding.EuroMaus_ActivateElevator_Part2) then
				self:setCurrentTool(RopaEuroMaus.ELEVATOR_PART2);
			end;
		end;
		
		-- pickup fold
		if InputBinding.hasEvent(InputBinding.EuroMaus_FoldPickup) then
			self:foldPickup();
		end;
		
		-- elevator fold
		if InputBinding.hasEvent(InputBinding.EuroMaus_FoldElevator) then
			self:foldElevator();
		end;

		-- pickup control
		if self.currentTool == RopaEuroMaus.PICKUP then
			if InputBinding.isPressed(InputBinding.EuroMaus_MoveUp) --[[or (self.mouseDirectionY < 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]] then
				self:setAnimationTime(3, self.animationParts[3].currentPosition-(self.animationParts[3].offSet+dt), false);
			elseif InputBinding.isPressed(InputBinding.EuroMaus_MoveDown) --[[or (self.mouseDirectionY > 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]] then
				self:setAnimationTime(3, self.animationParts[3].currentPosition+(self.animationParts[3].offSet+dt), false);
			end;
		
		-- front arm control
		elseif self.currentTool == RopaEuroMaus.FRONTARM then
			if InputBinding.isPressed(InputBinding.EuroMaus_MoveRight) --[[or (self.mouseDirectionX > 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]] then
				self:setAnimationTime(4, self.animationParts[4].currentPosition+(self.animationParts[4].offSet+dt), false);
			elseif InputBinding.isPressed(InputBinding.EuroMaus_MoveLeft) --[[or (self.mouseDirectionX < 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]] then
				self:setAnimationTime(4, self.animationParts[4].currentPosition-(self.animationParts[4].offSet+dt), false);
			end;
			if InputBinding.isPressed(InputBinding.EuroMaus_MoveDown) --[[or (self.mouseDirectionY > 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]] then
				self:setAnimationTime(5, self.animationParts[5].currentPosition-(self.animationParts[5].offSet+dt), false);
			elseif InputBinding.isPressed(InputBinding.EuroMaus_MoveUp) --[[or (self.mouseDirectionY < 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]]  then
				self:setAnimationTime(5, self.animationParts[5].currentPosition+(self.animationParts[5].offSet+dt), false);
			end;
			if InputBinding.isPressed(InputBinding.EuroMaus_MoveBack) --[[or (self.mouseDirectionY > 0 and self.mouseButton == MouseControlsVehicle.BUTTON_RIGHT)]] then
				self:setAnimationTime(6, self.animationParts[6].currentPosition-(self.animationParts[6].offSet+dt), false);
			elseif InputBinding.isPressed(InputBinding.EuroMaus_MoveFront) --[[or (self.mouseDirectionY < 0 and self.mouseButton == MouseControlsVehicle.BUTTON_RIGHT)]] then
				self:setAnimationTime(6, self.animationParts[6].currentPosition+(self.animationParts[6].offSet+dt), false);
			end;
		
		-- counterweight control
		elseif self.currentTool == RopaEuroMaus.COUNTERWEIGHT then
			if InputBinding.isPressed(InputBinding.EuroMaus_MoveRight) --[[or (self.mouseDirectionX > 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]] then
				self:setAnimationTime(1, self.animationParts[1].currentPosition+(self.animationParts[1].offSet+dt), false);
			elseif InputBinding.isPressed(InputBinding.EuroMaus_MoveLeft) --[[or (self.mouseDirectionX < 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]] then
				self:setAnimationTime(1, self.animationParts[1].currentPosition-(self.animationParts[1].offSet+dt), false);
			end;
			if InputBinding.hasEvent(InputBinding.EuroMaus_MoveDown) then
				self:setAnimationTime(1, 4000);
			end;
		
		-- elevator control
		elseif self.currentTool == RopaEuroMaus.ELEVATOR then
			if InputBinding.isPressed(InputBinding.EuroMaus_MoveLeft) --[[or (self.mouseDirectionX < 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]]  then
				self:setAnimationTime(9, self.animationParts[9].currentPosition-(self.animationParts[9].offSet+dt), false);
			elseif InputBinding.isPressed(InputBinding.EuroMaus_MoveRight) --[[or (self.mouseDirectionX > 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]]  then
				self:setAnimationTime(9, self.animationParts[9].currentPosition+(self.animationParts[9].offSet+dt), false);
			end;
		
		-- elevator part2 control
		elseif self.currentTool == RopaEuroMaus.ELEVATOR_PART2 then
			if InputBinding.isPressed(InputBinding.EuroMaus_MoveRight) --[[or (self.mouseDirectionX > 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]] then
				self:setAnimationTime(10, self.animationParts[10].currentPosition-(self.animationParts[10].offSet+dt), false);
			elseif InputBinding.isPressed(InputBinding.EuroMaus_MoveLeft) --[[or (self.mouseDirectionX < 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]]  then
				self:setAnimationTime(10, self.animationParts[10].currentPosition+(self.animationParts[10].offSet+dt), false);
			end;
			if InputBinding.isPressed(InputBinding.EuroMaus_MoveUp) --[[or (self.mouseDirectionY < 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]] then
				self:setAnimationTime(11, self.animationParts[11].currentPosition-(self.animationParts[11].offSet+dt), false);
			elseif InputBinding.isPressed(InputBinding.EuroMaus_MoveDown) --[[or (self.mouseDirectionY > 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]] then
				self:setAnimationTime(11, self.animationParts[11].currentPosition+(self.animationParts[11].offSet+dt), false);
			end;
			if InputBinding.isPressed(InputBinding.EuroMaus_MoveBack) --[[or (self.mouseDirectionY > 0 and self.mouseButton == MouseControlsVehicle.BUTTON_RIGHT)]]  then
				self:setAnimationTime(12, self.animationParts[12].currentPosition-(self.animationParts[12].offSet+dt), false);
			elseif InputBinding.isPressed(InputBinding.EuroMaus_MoveFront) --[[or (self.mouseDirectionY < 0 and self.mouseButton == MouseControlsVehicle.BUTTON_RIGHT)]]  then
				self:setAnimationTime(12, self.animationParts[12].currentPosition+(self.animationParts[12].offSet+dt), false);
			end;
		
		-- seat control
		elseif self.currentTool == RopaEuroMaus.SEAT then
			if InputBinding.isPressed(InputBinding.EuroMaus_MoveLeft) --[[or (self.mouseDirectionX < 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]]  then
				self:setAnimationTime(13, self.animationParts[13].currentPosition-(self.animationParts[13].offSet+dt), false);
			elseif InputBinding.isPressed(InputBinding.EuroMaus_MoveRight) --[[or (self.mouseDirectionX > 0 and self.mouseButton == MouseControlsVehicle.BUTTON_LEFT)]]  then
				self:setAnimationTime(13, self.animationParts[13].currentPosition+(self.animationParts[13].offSet+dt), false);
			end;
			if InputBinding.hasEvent(InputBinding.EuroMaus_MoveDown) then
				self:setAnimationTime(13, 2000);
			end;
		end;
		
		-- turn on
		if self.animationParts[2].clipEndTime and self.animationParts[8].clipEndTime then
			if InputBinding.hasEvent(InputBinding.EuroMaus_TurnOn) then
				self:setIsTurnedOn(not self.isTurnedOn);
			end;
		end;
	end;
	
	-- shader animations
	for _, part in pairs(self.conveyorScrollParts) do
		part.currentLength = part.currentLength + (self.animationParts[7].loopSpeed);
		setShaderParameter(part.node, "scrollPosition", part.currentLength*part.speed[1], part.currentLength*part.speed[2], 0, 0, false);
	end;
	
	for k, part in pairs(self.planeScrollParts) do
		part.currentLength = part.currentLength + (self.animationParts[7].loopSpeed);
		setShaderParameter(part.node, "UVPlaySpeed", part.currentLength*part.speed[1], part.currentLength*part.speed[2], 0, 0, false);
	end;
	
	-- work animation
	if self.isTurnedOn then
		self:setAnimationTime(7, 1);
	else
		self:setAnimationTime(7, 0);
	end;
	
	-- hydraulics sounds
	if self:getIsActiveForSound() then
		local hydraulicSoundEnabled = false;
		for i=1, 6 do
			if not self.animationParts[i].inputDone then
				hydraulicSoundEnabled = true;
			end;
		end;
		for i=8, 13 do
			if not self.animationParts[i].inputDone then
				hydraulicSoundEnabled = true;
			end;
		end;
		if hydraulicSoundEnabled then
			if not self.hydraulicSoundEnabled and self.hydraulicSound ~= nil then
				playSample(self.hydraulicSound, 0, self.hydraulicSoundVolume, 0);
				setSamplePitch(self.hydraulicSound, self.hydraulicSoundPitchOffset-0.4);
				self.hydraulicSoundEnabled = true;
			end;
		else
			if self.hydraulicSoundEnabled then
				stopSample(self.hydraulicSound);
				self.hydraulicSoundEnabled = false;
			end;
		end;
	end;
	
	-- display info
	if self.displayEmptyInfo then
		self.displayEmptyInfoTime = self.displayEmptyInfoTime + dt;
		if self.displayEmptyInfoTime > 2000 then
			self.displayEmptyInfo = false;
			self.displayEmptyInfoTime = 0;
		end;
	end;
	
	-- display info
	if self.displayNoTrailerInfo then
		self.displayNoTrailerInfoTime = self.displayNoTrailerInfoTime + dt;
		if self.displayNoTrailerInfoTime > 2000 then
			self.displayNoTrailerInfo = false;
			self.displayNoTrailerInfoTime = 0;
		end;
	end;
	
	-- trailer detect and fill
	self.trailerFoundId = 0;
	self.trailerUnderElevator = false;
	local x, y, z = getWorldTranslation(self.unloadingTrigger.node);
	local dx, dy, dz = localDirectionToWorld(self.unloadingTrigger.node, 0, -0.5, 0);
	raycastAll(x, y, z, dx, dy, dz, "trailerRaycastCallback", self.unloadingTrigger.distance, self);
	
	local deltaLevel = 0;
	self.fillDelta = 0;
	
	if self.trailerFoundId ~= nil and self.trailerFoundId ~= 0 then
		local trailer = g_currentMission.nodeToVehicle[self.trailerFoundId];
		if trailer ~= nil and trailer ~= self then
			self.trailerUnderElevator = true;
			if self.fillLevel > 0 then
				if trailer:allowFillType(self.currentFillType, true) then
					if trailer.allowFillFromAir then
						if trailer.capacity > trailer.fillLevel and self.fillLevel > 0 and self.isTurnedOn then
							local deltaLevel = self.unloadingCapacity*dt/1000.0;
							local fillDelta = math.min(deltaLevel, self.fillLevel);
							self.fillDelta = fillDelta;
							self:setFillLevel(self.fillLevel - fillDelta, self.currentFillType);
							trailer:setFillLevel(trailer.fillLevel + fillDelta, self.currentFillType);
							self.psActive = true;
						elseif trailer.fillLevel == trailer.capacity then
							self:setIsTurnedOn(false, true);
							if self:getIsActiveForInput() then
								g_currentMission:addWarning(g_i18n:getText("EuroMaus_TrailerFullInfo"), 0.07+0.022, 0.019+0.029);
							end;
							self.psActive = false;
						else
							self.psActive = false;
						end;
					else
						self.psActive = false;
					end;
				else
					self.psActive = false;
					self:setIsTurnedOn(false, true);
					if self:getIsActiveForInput() then
						g_currentMission:addWarning(string.format(g_i18n:getText("EuroMaus_TrailerFilltypeInfo"), Fillable.fillTypeIntToName[self.currentFillType]), 0.07+0.022, 0.019+0.029);	
					end;
				end;
			else
				self.psActive = false;
			end;
			-- render trailer filllevel
			if self:getIsActiveForInput() then
				if g_gui.currentGui == nil then
					local percent = (100/trailer.capacity)*trailer.fillLevel;
					local text = string.format("%d (%d%%)", trailer.fillLevel, percent);
					local x, y, z = getWorldTranslation(trailer.exactFillRootNode);
					local sx, sy, sz = project(x, y, z);
					setTextAlignment(RenderText.ALIGN_CENTER);
					setTextBold(false);		
					setTextColor(0.5, 1.0, 0.5, 1.0);                      
					renderText(sx, sy, 0.035, text);	
					setTextAlignment(RenderText.ALIGN_LEFT);
				end;
			end;
		else
			self.psActive = false;
			self:setIsTurnedOn(false, true);
		end;
	else
		self:setIsTurnedOn(false, true);
		self.psActive = false;
	end;
	
	if self.currentFillType ~= Fillable.FILLTYPE_UNKNOWN then
		Utils.setEmittingState(self.unloadingParticleSystems[self.currentFillType], self.psActive);
	else
		for k, ps in pairs(self.unloadingParticleSystems) do
			Utils.setEmittingState(self.unloadingParticleSystems[k], false);
		end;
	end;
	for k, ps in pairs(self.groundParticleSystems) do
		Utils.setEmittingState(ps.ps,  self.psActive);
	end;

	-- reset filltype if empty
	if self.fillLevel == 0 then
		self.currentFillType = Fillable.FILLTYPE_UNKNOWN;
	end;

end;

function RopaEuroMaus:updateTick(dt)
	if self.isMotorStarted == false then
		self:setIsTurnedOn(false, true);
	end;
end;

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

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

function RopaEuroMaus:draw()
	if self.isClient then
		if self.isMotorStarted then
			if self.animationParts[2].clipEndTime and self.animationParts[8].clipEndTime then
				if self.isTurnedOn then
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("turn_off_OBJECT"), self.typeDesc), InputBinding.EuroMaus_TurnOn);
				else
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("turn_on_OBJECT"), self.typeDesc), InputBinding.EuroMaus_TurnOn);
				end;
			end;
			
			if self.isTurnedOn == false then
				if self.animationParts[2].clipEndTime then
					g_currentMission:addHelpButtonText(g_i18n:getText("EuroMaus_FoldPickup"), InputBinding.EuroMaus_FoldPickup);
				else
					g_currentMission:addHelpButtonText(g_i18n:getText("EuroMaus_UnfoldPickup"), InputBinding.EuroMaus_FoldPickup);
				end;
				if self.animationParts[8].clipEndTime then
					g_currentMission:addHelpButtonText(g_i18n:getText("EuroMaus_FoldElevator"), InputBinding.EuroMaus_FoldElevator);
				else
					g_currentMission:addHelpButtonText(g_i18n:getText("EuroMaus_UnfoldElevator"), InputBinding.EuroMaus_FoldElevator);
				end;
			end;
		end;
		
		if self.displayEmptyInfo then
			g_currentMission:addWarning(g_i18n:getText("EuroMaus_EmptyMachineInfo"), 0.07+0.022, 0.019+0.029);	
		end;
		
		if self.displayNoTrailerInfo then
			g_currentMission:addWarning(g_i18n:getText("EuroMaus_NoTrailerInfo"), 0.07+0.022, 0.019+0.029);
		end;
	end;
end;

function RopaEuroMaus:setIsTurnedOn(turnedOn, noEventSend)
	if self.isMotorStarted then
		if self.trailerUnderElevator == false and turnedOn == true then
			self.displayNoTrailerInfo = true;
		else
			SetTurnedOnEvent.sendEvent(self, turnedOn, noEventSend)
			self.isTurnedOn = turnedOn;
			self.fallOut = not turnedOn;
			
			if self.isTurnedOn then
				self.isShovel = true;
				self.allowFillFromShovelTrigger = true;
				if self.altTipPointBackup ~= nil then
					self.altTipPoint = self.altTipPointBackup;
				end;
				if self.isClient then
					local threshingSoundOffset = 0;
					if self.threshingStartSound ~= nil then
						if self:getIsActiveForSound() then
							setSamplePitch(self.threshingStartSound, self.threshingStartSoundPitchOffset);
							playSample(self.threshingStartSound, 1, 1, 0);
						end;
						threshingSoundOffset = getSampleDuration(self.threshingStartSound);
					end;
					-- kill sounds --
					if self.threshingStopSound ~= nil then
						stopSample(self.threshingStopSound);
					end;
					self.playThreshingSoundTime = self.time+threshingSoundOffset;
				end;
			else
				self.isShovel = nil;
				self.allowFillFromShovelTrigger = false;
				self.altTipPoint = nil;
				if self.isClient then
					if self.threshingSound ~= nil then
						stopSample(self.threshingSound);
					end;
					-- kill sounds --
					if self.threshingStartSound ~= nil then
						stopSample(self.threshingStartSound);
					end;
					if self.threshingStopSound ~= nil and self.threshingSoundActive and self:getIsActiveForSound() then
						setSamplePitch(self.threshingStopSound, self.threshingStopSoundPitchOffset);
						playSample(self.threshingStopSound, 1, 1, 0);
						self.threshingSoundActive = false;
					end;
				end;
			end;
		end;
	end;
end;

function RopaEuroMaus:foldPickup()
	if self.isTurnedOn == false and self.isMotorStarted then
		if self.animationParts[2].clipEndTime then
			if self.fillLevel == 0 then
				self:setAnimationTime(2, self.animationParts[2].startPosition);
				self:setAnimationTime(4, 1500);
				self:setAnimationTime(5, 900);
				self:setAnimationTime(6, 750);
			else
				self.displayEmptyInfo = true;
			end;
		else
			self:setAnimationTime(2, self.animationParts[2].animDuration);
		end;
	end;
end;

function RopaEuroMaus:foldElevator()
	if self.isTurnedOn == false and self.isMotorStarted then
		if self.animationParts[8].clipEndTime then
			if self.fillLevel == 0 then
				self:setAnimationTime(8, self.animationParts[8].startPosition);
				self:setAnimationTime(9, 2500);
				self:setAnimationTime(10, self.animationParts[10].startPosition);
				self:setAnimationTime(11, 3020);
				self:setAnimationTime(12, self.animationParts[12].startPosition);
				if self.currentTool == RopaEuroMaus.ELEVATOR or self.currentTool == RopaEuroMaus.ELEVATOR_PART2 then
					self:setCurrentTool(RopaEuroMaus.PICKUP);
				end;
			else
				self.displayEmptyInfo = true;
			end;
		else
			self:setAnimationTime(8, self.animationParts[8].animDuration);
		end;
	end;
end;

function RopaEuroMaus:setCurrentTool(currentTool, noEventSend)
	SetCurrentToolEvent.sendEvent(self, currentTool, noEventSend)
	self.currentTool = currentTool;
end;

function RopaEuroMaus:onDeactivate()
	RopaEuroMaus.onDeactivateSounds(self)
end;

function RopaEuroMaus:onDeactivateSounds()
	if self.threshingSoundActive then
		stopSample(self.threshingSound);
		self.threshingSoundActive = false;
	end;
	if self.hydraulicSoundEnabled then
		stopSample(self.hydraulicSound);
		self.hydraulicSoundEnabled = false;
	end;
end;

function RopaEuroMaus:onLeave()
	if self.deactivateOnLeave then
		RopaEuroMaus.onDeactivate(self);
	else
		RopaEuroMaus.onDeactivateSounds(self)
	end;
end;

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

-- events
SetCurrentToolEvent = {};
SetCurrentToolEvent_mt = Class(SetCurrentToolEvent, Event);

InitEventClass(SetCurrentToolEvent, "SetCurrentToolEvent");

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

function SetCurrentToolEvent:new(vehicle, activeTool)
    local self = SetCurrentToolEvent:emptyNew()
    self.vehicle = vehicle;
	self.activeTool = activeTool;
    return self;
end;

function SetCurrentToolEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.activeTool = streamReadInt8(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function SetCurrentToolEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteInt8(streamId, self.activeTool);
end;

function SetCurrentToolEvent:run(connection)   
	self.vehicle:setCurrentTool(self.activeTool, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(SetCurrentToolEvent:new(self.vehicle, self.activeTool), nil, connection, self.vehicle);
    end;
end;

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