--
--	Agromet-Famarol Z211/2
--
--	Author: Burner
--	Date: 28.08.2013
--

Agromet_Z211_2 = {};

Agromet_Z211_2.TransportMode = 1;
Agromet_Z211_2.TedderMode = 2;
Agromet_Z211_2.WindrowerMode = 3;

function Agromet_Z211_2.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Attachable, specializations);
end;

function Agromet_Z211_2:load(xmlFile)
	self.objectInRange = Agromet_Z211_2.objectInRange;
	
	self.changeMode = SpecializationUtil.callSpecializationsFunction("changeMode");
	self.playLowerStarWheelsSound = SpecializationUtil.callSpecializationsFunction("playLowerStarWheelsSound");
	self.setTedderMode = SpecializationUtil.callSpecializationsFunction("setTedderMode");
	self.setWindrowerMode = SpecializationUtil.callSpecializationsFunction("setWindrowerMode");
	self.setTransportMode = SpecializationUtil.callSpecializationsFunction("setTransportMode");
	self.currentMode = Agromet_Z211_2.TransportMode;
	
	self.transportModeAnim = getXMLString(xmlFile, "vehicle.transportMode#animationName");
	self.tedderModeAnim = getXMLString(xmlFile, "vehicle.tedderMode#animationName");
	self.windrowerModeAnim = getXMLString(xmlFile, "vehicle.windrowerMode#animationName");
	
	self.lowerStarWheels = SpecializationUtil.callSpecializationsFunction("lowerStarWheels");
	self.lowerStarWheelsAnim = getXMLString(xmlFile, "vehicle.lowerStarWheels#animationName");
	self.starWheelsLowered = false;
	
	self.switchAttacher = SpecializationUtil.callSpecializationsFunction("switchAttacher");
	
	self.drawbar = {};
	self.drawbar.component = getXMLInt(xmlFile, "vehicle.drawbar#componentIndex");
	self.drawbar.component1 = getXMLInt(xmlFile, "vehicle.drawbar#component1");
	self.drawbar.component2 = getXMLInt(xmlFile, "vehicle.drawbar#component2");
	self.drawbar.componentJoint1 = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.drawbar#componentJoint1"));
	self.drawbar.componentJoint2 = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.drawbar#componentJoint2"));
	self.drawbar.rotLimits = getXMLString(xmlFile, "vehicle.drawbar#rotLimit");
	local jointIndexStr = getXMLInt(xmlFile, "vehicle.drawbar#jointIndex");
	self.drawbar.jointIndex = jointIndexStr;
	
	self.starWheelsActionPoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.starWheelsActionPoint#index"));
	self.changeModeActionPoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.changeModeActionPoint#index"));
	
	self.speedRotatingParts = {};
	local i=0;
	while true do
		local baseName = string.format("vehicle.speedRotatingParts.speedRotatingPart(%d)", i);
		local index = getXMLString(xmlFile, baseName.. "#index");
		if index == nil then
			break;
		end;
		local node = Utils.indexToObject(self.components, index);
		if node ~= nil then
			local entry = {};
			entry.node = node;
			entry.rotationSpeedScale = getXMLFloat(xmlFile, baseName.."#rotationSpeedScale");
			if entry.rotationSpeedScale == nil then
				entry.rotationSpeedScale = 1.0/Utils.getNoNil(getXMLFloat(xmlFile, baseName.."#radius"), 1);
			end;
			entry.foldMinLimit = Utils.getNoNil(getXMLFloat(xmlFile, baseName .. "#foldMinLimit"), 0);
			entry.foldMaxLimit = Utils.getNoNil(getXMLFloat(xmlFile, baseName .. "#foldMaxLimit"), 1);
			table.insert(self.speedRotatingParts, entry);
		end;
		i = i+1;
	end;
	
	local numTedderCuttingAreas = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.tedderCuttingAreas#count"), 0);
	self.tedderCuttingAreas = {}
	self.accumulatedTedderCuttingAreaValues = {};
	for i=1, numTedderCuttingAreas do
		local areanamei = string.format("vehicle.tedderCuttingAreas.tedderCuttingArea%d", i);
		local cuttingArea = {};
		if self:loadAreaFromXML(cuttingArea, xmlFile, areanamei) then
			table.insert(self.tedderCuttingAreas, cuttingArea);
		end;
		self.accumulatedTedderCuttingAreaValues[i] = 0;
	end;
 
	local numTedderDropAreas = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.tedderDropAreas#count"), 0);
	if numTedderDropAreas ~= table.getn(self.tedderCuttingAreas) then
		print("Warning: Number of cutting areas and drop areas should be equal");
	end;
	self.tedderDropAreas = {}
	for i=1, numTedderDropAreas do
		self.tedderDropAreas[i] = {};
		local areanamei = string.format("vehicle.tedderDropAreas.tedderDropArea%d", i);
		self.tedderDropAreas[i].start = Utils.indexToObject(self.components, getXMLString(xmlFile, areanamei .. "#startIndex"));
		self.tedderDropAreas[i].width = Utils.indexToObject(self.components, getXMLString(xmlFile, areanamei .. "#widthIndex"));
		self.tedderDropAreas[i].height = Utils.indexToObject(self.components, getXMLString(xmlFile, areanamei .. "#heightIndex"));
	end;
	
	local numWindrowerCuttingAreas = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.windrowerCuttingAreas#count"), 0);
	self.windrowerCuttingAreas = {}
	self.accumulatedWindrowerCuttingAreaValues = {};
	self.accumulatedWindrowerFruitType = FruitUtil.FRUITTYPE_UNKNOWN;
	for i=1, numWindrowerCuttingAreas do
		local areanamei = string.format("vehicle.windrowerCuttingAreas.windrowerCuttingArea%d", i);
		local cuttingArea = {};
		if self:loadAreaFromXML(cuttingArea, xmlFile, areanamei) then
			table.insert(self.windrowerCuttingAreas, cuttingArea);
		end;
		self.accumulatedWindrowerCuttingAreaValues[i] = 0;
	end;
	
	local numWindrowerDropAreas = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.windrowerDropAreas#count"), 0);
	if numWindrowerDropAreas == 0 then
		print("Warning: No drop areas specified in '"..self.configFileName.."'");
	else
		if numWindrowerDropAreas ~= 1 and numWindrowerDropAreas ~= table.getn(self.windrowerCuttingAreas) then
			print("Warning: Number of cutting areas and drop areas should be equal in '"..self.configFileName.."'");
		end;
	end;
	self.windrowerDropAreas = {}
	for i=1, numWindrowerDropAreas do
		self.windrowerDropAreas[i] = {};
		local areanamei = string.format("vehicle.windrowerDropAreas.windrowerDropArea%d", i);
		self.windrowerDropAreas[i].start = Utils.indexToObject(self.components, getXMLString(xmlFile, areanamei .. "#startIndex"));
		self.windrowerDropAreas[i].width = Utils.indexToObject(self.components, getXMLString(xmlFile, areanamei .. "#widthIndex"));
		self.windrowerDropAreas[i].height = Utils.indexToObject(self.components, getXMLString(xmlFile, areanamei .. "#heightIndex"));
	end;
	
	self.tedderParticleSystems = {};
	local i=0;
	while true do
		local baseName = string.format("vehicle.tedderParticleSystems.tedderParticleSystem(%d)", i);

		local particleSystem = {};
		particleSystem.ps = {};
		local ps = Utils.loadParticleSystem(xmlFile, particleSystem.ps, baseName, self.components, false, nil, self.baseDirectory)
		if ps == nil then
			break;
		end;
		table.insert(self.tedderParticleSystems, particleSystem);
		i = i+1;
	end;
	self.tedderParticleSystemDisableTime = 0;
	self.tedderParticleSystemEnabled = false;
	
	self.windrowerParticleSystems = {};
	local i=0;
	while true do
		local baseName = string.format("vehicle.windrowerParticleSystems.windrowerParticleSystem(%d)", i);
		local t = getXMLString(xmlFile, baseName .. "#type");
		if t == nil then
			break;
		end;
		local desc = FruitUtil.fruitTypes[t];
		if desc ~= nil then
			if self.windrowerParticleSystems[desc.index] == nil then
				self.windrowerParticleSystems[desc.index] = {}
			end;
			local ps = Utils.loadParticleSystem(xmlFile, self.windrowerParticleSystems[desc.index], baseName, self.components, false, nil, self.baseDirectory)
		end;
		i = i+1;
	end;
	self.windrowerParticleSystemDisableTime = 0;
	self.windrowerParticleSystemEnabled = false;
	
	self.customDownForces = {};
	local i=0;
	while true do
		local baseName = string.format("vehicle.customDownForces.customDownForce(%d)", i);
		local index = getXMLString(xmlFile, baseName.. "#componentIndex");
		if index == nil then
			break;
		end;
		local force = getXMLFloat(xmlFile, baseName.. "#force");
		if force ~= nil and self.components[index + 1] ~= nil then
			local entry = {};
			entry.componentIndex = index;
			entry.force = force;
			table.insert(self.customDownForces, entry);
		end;
		i = i+1;
	end;
	
	self.scrollParts = {};
	local i = 0;
	while true do
		local key = string.format("vehicle.scrollParts.scrollPart(%d)", i);
		if not hasXMLProperty(xmlFile, key) then
			break;
		end;
		local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index"));
		local speedRefNode = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#speedRefNode"));
		local speed = Utils.getVectorNFromString(getXMLString(xmlFile, key.."#speed"), 2);
		if node ~= nil and speed and speedRefNode ~= nil then
			table.insert(self.scrollParts, {node=node, speedRefNode=speedRefNode, speed=speed, currentLength=0});
		end;
		i = i +1;
	end;
	
	if self.isClient then
		local workSound = getXMLString(xmlFile, "vehicle.workSound#file");
		if workSound ~= nil and workSound ~= "" then
			workSound = Utils.getFilename(workSound, self.baseDirectory);
			self.workSound = createSample("workSound");
			self.workSoundEnabled = false;
			loadSample(self.workSound, workSound, false);
			self.workSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.workSound#pitchOffset"), 1);
			self.workSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.workSound#volume"), 1.0);
		end;
	end;
	
	self.wasToFast = false;
	self.currentWindrowerFruitType = FruitUtil.FRUITTYPE_UNKNOWN;
	
	local lowerStarWheelsSound = getXMLString(xmlFile, "vehicle.lowerStarWheelsSound#file");
	if lowerStarWheelsSound ~= nil and lowerStarWheelsSound ~= "" then
		lowerStarWheelsSound = Utils.getFilename(lowerStarWheelsSound, self.baseDirectory);
		self.lowerStarWheelsSound = createSample("lowerStarWheelsSound");
		loadSample(self.lowerStarWheelsSound, lowerStarWheelsSound, false);
		self.lowerStarWheelsSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.lowerStarWheelsSound#volume"), 1.0);
		self.lowerStarWheelsSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.lowerStarWheelsSound#pitchOffset"), 0);
		setSamplePitch(self.lowerStarWheelsSound, self.lowerStarWheelsSoundPitchOffset);
	end;
end;

function Agromet_Z211_2:getSaveAttributesAndNodes(nodeIdent)
	local attributes = 'currentMode="'.. tostring(self.currentMode) ..'" starWheelsLowered="'.. tostring(self.starWheelsLowered) ..'"';
	return attributes, nil;
end

function Agromet_Z211_2:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	if not resetVehicles then
		local currentMode = Utils.getNoNil(getXMLInt(xmlFile, key.."#currentMode"), 1);
		local starWheelsLowered = Utils.getNoNil(getXMLBool(xmlFile, key.."#starWheelsLowered"), false);
		if currentMode ~= 1 then
			self:changeMode(currentMode);
		end;
		if starWheelsLowered then
			self:lowerStarWheels(true);
		end;
	end;
	return BaseMission.VEHICLE_LOAD_OK;
end

function Agromet_Z211_2:delete()
	for k,v in pairs(self.tedderParticleSystems) do
		Utils.deleteParticleSystem(v.ps);
	end;
	for k, ps in pairs(self.windrowerParticleSystems) do
		Utils.deleteParticleSystem(self.windrowerParticleSystems[k]);
	end;
	if self.workSound ~= nil then
		delete(self.workSound);
	end;
	if self.lowerStarWheelsSound ~= nil then
		delete(self.lowerStarWheelsSound);
	end;
end;

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

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

function Agromet_Z211_2:readStream(streamId, connection)  
	self:lowerStarWheels(streamReadBool(streamId), true);
	self:changeMode(streamReadInt8(streamId), true);
end;

function Agromet_Z211_2:writeStream(streamId, connection)
	streamWriteBool(streamId, self.starWheelsLowered);
	streamWriteInt8(streamId, self.currentMode);
end;

function Agromet_Z211_2:update(dt)
	-- force update components position (for MP clients)
	if not self.isServer and not self:getIsActive() and self.attacherVehicle ~= nil then
		self.positionIsDirty = true;
	end;
	
	-- handling work modes
	if self:objectInRange(self.changeModeActionPoint) then
		local getIsChangeModeAllowed = (self:getAnimationTime(self.transportModeAnim) < 0.1 or self:getAnimationTime(self.transportModeAnim) > 0.9) and (self:getAnimationTime(self.tedderModeAnim) < 0.1 or self:getAnimationTime(self.tedderModeAnim) > 0.9) and (self:getAnimationTime(self.windrowerModeAnim) < 0.1 or self:getAnimationTime(self.windrowerModeAnim) > 0.9);
		if getIsChangeModeAllowed then
			if self.currentMode ~= Agromet_Z211_2.TransportMode then
				g_currentMission:addHelpButtonText(g_i18n:getText("Agromet_Z211_2_TransportMode"), InputBinding.Agromet_Z211_2_TransportMode);
				if InputBinding.hasEvent(InputBinding.Agromet_Z211_2_TransportMode) then
					self:changeMode(Agromet_Z211_2.TransportMode);
					self:playAttachSound();
				end;
			end;
			if self.currentMode ~= Agromet_Z211_2.TedderMode then
				g_currentMission:addHelpButtonText(g_i18n:getText("Agromet_Z211_2_TedderMode"), InputBinding.Agromet_Z211_2_TedderMode);
				if InputBinding.hasEvent(InputBinding.Agromet_Z211_2_TedderMode) then
					self:changeMode(Agromet_Z211_2.TedderMode);
					self:playAttachSound();
				end;
			end;
			if self.currentMode ~= Agromet_Z211_2.WindrowerMode then
				g_currentMission:addHelpButtonText(g_i18n:getText("Agromet_Z211_2_WindrowerMode"), InputBinding.Agromet_Z211_2_WindrowerMode);
				if InputBinding.hasEvent(InputBinding.Agromet_Z211_2_WindrowerMode) then
					self:changeMode(Agromet_Z211_2.WindrowerMode);
					self:playAttachSound();
				end;
			end
		end;
	end;
	
	-- handling star wheels
	if self:objectInRange(self.starWheelsActionPoint) then
		if self.starWheelsLowered then
			g_currentMission:addHelpButtonText(g_i18n:getText("Agromet_Z211_2_RaiseStarWheels"), InputBinding.Agromet_Z211_2_LowerStarWheels);
		else
			g_currentMission:addHelpButtonText(g_i18n:getText("Agromet_Z211_2_LowerStarWheels"), InputBinding.Agromet_Z211_2_LowerStarWheels);
		end
		if InputBinding.hasEvent(InputBinding.Agromet_Z211_2_LowerStarWheels) then
			self:lowerStarWheels(not self.starWheelsLowered);
			self:playLowerStarWheelsSound();
		end;
	end;
	
	-- custom down forces
	if self.isServer then
		for k,force in pairs(self.customDownForces) do
			local worldX,worldY,worldZ = localDirectionToWorld(self.components[force.componentIndex + 1].node, 0, -force.force*dt/1000, 0);
			addForce(self.components[force.componentIndex + 1].node, worldX, worldY, worldZ, 0, 0, 0, true);
		end;
	end;
	
	-- scroll shaders
	for k, part in pairs(self.scrollParts) do
		local x,y,z = getRotation(part.speedRefNode);
		setShaderParameter(part.node, "UVPlaySpeed", x*part.speed[1], x*part.speed[2], 0, 0, false);
	end;
end;

function Agromet_Z211_2:updateTick(dt)
	-- update moving parts also if not active
	if not self:getIsActive() then
		for _, part in pairs(self.activeDirtyMovingParts) do
			Cylindered.setDirty(self, part);
		end
	end;
	
	self.wasToFast = false;
	if self:getIsActive() then
		-- rotate star wheels if lowered
		if self.starWheelsLowered then
			for k,v in pairs(self.speedRotatingParts) do
				rotate(v.node, v.rotationSpeedScale * self.lastSpeedReal * self.movingDirection * dt, 0, 0);
			end;
		end;
		
		if self.starWheelsLowered then
			local toFast = self:doCheckSpeedLimit() and self.lastSpeed*3600 > 21;
			if not toFast then
				-- tedder mode function
				if self.currentMode == Agromet_Z211_2.TedderMode then
					local cuttingAreasSend = {};
					local numAreas = math.min(table.getn(self.tedderDropAreas), table.getn(self.tedderCuttingAreas));
					for i=1, numAreas do
						local cuttingArea = self.tedderCuttingAreas[i];
						if self:getIsAreaActive(cuttingArea) then
							local x,y,z = getWorldTranslation(cuttingArea.start);
							local x1,y1,z1 = getWorldTranslation(cuttingArea.width);
							local x2,y2,z2 = getWorldTranslation(cuttingArea.height);
							
							local dropArea = self.tedderDropAreas[i];
							local dx,dy,dz = getWorldTranslation(dropArea.start);
							local dx1,dy1,dz1 = getWorldTranslation(dropArea.width);
							local dx2,dy2,dz2 = getWorldTranslation(dropArea.height);
							table.insert(cuttingAreasSend, {x,z,x1,z1,x2,z2,dx, dz, dx1, dz1, dx2, dz2, 0, i});
						end;
					end;
					if (table.getn(cuttingAreasSend) > 0) then
						local cuttingAreasSend, bitType = TedderAreaEvent.runLocally(cuttingAreasSend, self.accumulatedTedderCuttingAreaValues);
						if (table.getn(cuttingAreasSend) > 0) and self.lastSpeed*3600 > 3 then
							self.tedderParticleSystemDisableTime = self.time + 800;
							self.tedderParticleSystemEnabled = true;
							for k,v in ipairs(self.tedderParticleSystems) do
								Utils.setEmittingState(v.ps, true);
							end;
							if self.isServer then
								g_server:broadcastEvent(TedderAreaEvent:new(cuttingAreasSend, bitType));
							end;
						end;
					end;
				-- windrower mode function
				elseif self.currentMode == Agromet_Z211_2.WindrowerMode then
					local numDropAreas = table.getn(self.windrowerDropAreas);
					local numAreas = table.getn(self.windrowerCuttingAreas);
					if numDropAreas > 0 and numAreas > 0 then
						local cuttingAreasSend = {};
						local dropAreasSend = {};
						for i=1, numAreas do
							local cuttingArea = self.windrowerCuttingAreas[i];
							if self:getIsAreaActive(cuttingArea) then
								local x,_,z = getWorldTranslation(cuttingArea.start);
								local x1,_,z1 = getWorldTranslation(cuttingArea.width);
								local x2,_,z2 = getWorldTranslation(cuttingArea.height);
								table.insert(cuttingAreasSend, {x,z,x1,z1,x2,z2});
							end;
						end;
						for i=1, numDropAreas do
							local dropArea = self.windrowerDropAreas[i];
							local dx,dy,dz = getWorldTranslation(dropArea.start);
							local dx1,dy1,dz1 = getWorldTranslation(dropArea.width);
							local dx2,dy2,dz2 = getWorldTranslation(dropArea.height);
							table.insert(dropAreasSend, {dx, dz, dx1, dz1, dx2, dz2});
						end;
						if table.getn(cuttingAreasSend) > 0 then
							local cuttingAreasSend, dropAreasSend, fruitType, bitType = WindrowAreaEvent.runLocally(cuttingAreasSend, dropAreasSend, self.accumulatedWindrowerCuttingAreaValues, self.accumulatedWindrowerFruitType);
							if (table.getn(cuttingAreasSend) > 0 or table.getn(dropAreasSend) > 0) and self.lastSpeed*3600 > 3 then
								self.accumulatedWindrowerFruitType = fruitType;
								self.currentWindrowerFruitType = fruitType;
								
								-- enable grass particle system for dryGrass if dryGrass particle system not exists
								if self.currentWindrowerFruitType == FruitUtil.FRUITTYPE_DRYGRASS then
									if self.windrowerParticleSystems[FruitUtil.FRUITTYPE_DRYGRASS] == nil then
										self.currentWindrowerFruitType = FruitUtil.FRUITTYPE_GRASS;
									end;
								end;
								
								self.windrowerParticleSystemDisableTime = self.time + 800;
								self.windrowerParticleSystemEnabled = true;
								
								if self.windrowerParticleSystems[self.currentWindrowerFruitType] ~= nil then
									Utils.setEmittingState(self.windrowerParticleSystems[self.currentWindrowerFruitType], true);
								end;
								if self.isServer then
									g_server:broadcastEvent(WindrowAreaEvent:new(cuttingAreasSend, dropAreasSend, fruitType, bitType));
								end;
							end;
						end;
					end;
				end;
				
			end;
			self.wasToFast = toFast;
		end;
	end
	
	-- handling work sound
	if self.isClient then
		if self.starWheelsLowered and self.lastSpeed*3600 > 3 then
			if not self.workSoundEnabled and self:getIsActiveForSound() then
				playSample(self.workSound, 0, self.workSoundVolume, 0);
				setSamplePitch(self.workSound, self.workSoundPitchOffset);
				self.workSoundEnabled = true;
			end;
		elseif self.workSoundEnabled then
			stopSample(self.workSound);
			self.workSoundEnabled = false;
		end;
	end;
	
	-- handling particle systems
	for k,v in ipairs(self.tedderParticleSystems) do
		if self.time > self.tedderParticleSystemDisableTime then
			self.tedderParticleSystemEnabled = false;
			Utils.setEmittingState(v.ps, false);
		end;
	end;
	for k, ps in pairs(self.windrowerParticleSystems) do
		if k == self.currentWindrowerFruitType then
			if self.time > self.windrowerParticleSystemDisableTime then
				self.windrowerParticleSystemEnabled = false;
				Utils.setEmittingState(self.windrowerParticleSystems[k], false);
			end;
		else
			Utils.setEmittingState(self.windrowerParticleSystems[k], false);
		end
	end;
end

function Agromet_Z211_2:draw()
	if self.wasToFast then
		g_currentMission:addWarning(g_i18n:getText("Dont_drive_to_fast") .. "\n" .. string.format(g_i18n:getText("Cruise_control_levelN"), "2"), 0.07+0.022, 0.019+0.029);
	end;
	g_currentMission:addExtraPrintText(g_i18n:getText("Agromet_Z211_2_FunctionsInfo"));
end;

function Agromet_Z211_2:onDetach()
	if self.deactivateOnDetach then
		Agromet_Z211_2.onDeactivate(self);
	else
		Agromet_Z211_2.onDeactivateSounds(self)
	end;
end;

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

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

function Agromet_Z211_2:onDeactivateSounds()
	if self.workSoundEnabled then
		stopSample(self.workSound);
		self.workSoundEnabled = false;
	end;
end;

function Agromet_Z211_2:objectInRange(object)
	if g_currentMission.player ~= nil and object ~= nil then
		local nearestDistance = 1.5;
		local vx, vy, vz = getWorldTranslation(g_currentMission.player.rootNode);
		local px, py, pz = getWorldTranslation(object); 
		local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);	
		if distance < nearestDistance then
			return true;
		else
			return false;
		end;
	else
		return false;
	end;
end;

function Agromet_Z211_2:changeMode(mode, noEventSend)
	ChangeModeEvent.sendEvent(self, mode, noEventSend);
	self.currentMode = mode;
	if mode == 1 then
		self:setTransportMode()
	elseif mode == 2 then
		self:setTedderMode()
	elseif mode == 3 then
		self:setWindrowerMode()
	end
end;

function Agromet_Z211_2:setTedderMode()
	if self.tedderModeAnim ~= nil and self.playAnimation ~= nil then
		self:playAnimation(self.tedderModeAnim, 1, nil, true);
	end;
	self:switchAttacher(self.drawbar.component2, self.drawbar.componentJoint2);
end;

function Agromet_Z211_2:setWindrowerMode()
	if self.windrowerModeAnim ~= nil and self.playAnimation ~= nil then
		self:playAnimation(self.windrowerModeAnim, 1, nil, true);
	end;
	self:switchAttacher(self.drawbar.component1, self.drawbar.componentJoint1);
end;

function Agromet_Z211_2:setTransportMode()
	if self.transportModeAnim ~= nil and self.playAnimation ~= nil then
		self:playAnimation(self.transportModeAnim, 1, nil, true);
	end;
	self:switchAttacher(self.drawbar.component1, self.drawbar.componentJoint1);
end;

function Agromet_Z211_2:lowerStarWheels(lowerStarWheels, noEventSend)
	LowerStarWheelsEvent.sendEvent(self, lowerStarWheels, noEventSend);
	self.starWheelsLowered = lowerStarWheels;
	if not lowerStarWheels then
		if self.lowerStarWheelsAnim ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.lowerStarWheelsAnim, -1, nil, true);
		end;
	else
		if self.lowerStarWheelsAnim ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.lowerStarWheelsAnim, 1, nil, true);
		end;
	end;
end;

function Agromet_Z211_2:switchAttacher(component, componentJoint)
	if self.attacherVehicle ~= nil then
		self.attacherVehicle:detachImplementByObject(self, true);
	end;
	setRigidBodyType(self.components[self.drawbar.component + 1].node, "NoRigidBody");
	removeJoint(self.componentJoints[self.drawbar.jointIndex + 1].jointIndex);
	
	local tx, ty, tz = getWorldTranslation(componentJoint);
	local rx, ry, rz = getWorldRotation(componentJoint);
	setTranslation(self.components[self.drawbar.component + 1].node, tx, ty, tz);
	setRotation(self.components[self.drawbar.component + 1].node, rx, ry, rz);
	
	local constr = JointConstructor:new();					
	constr:setActors(self.components[component + 1].node, self.components[self.drawbar.component + 1].node);
	constr:setJointTransforms(componentJoint, componentJoint);
		
	local x, y, z = Utils.getVectorFromString(self.drawbar.rotLimits);
	local rotLimits = {};
	rotLimits[1] = math.rad(Utils.getNoNil(x, 0));
	rotLimits[2] = math.rad(Utils.getNoNil(y, 0));
	rotLimits[3] = math.rad(Utils.getNoNil(z, 0));
		
	for i=1, 3 do
		constr:setTranslationLimit(i-1, true, 0, 0);
		constr:setRotationLimit(i-1, -rotLimits[i], rotLimits[i]);
	end;
		
	local jointDesc = {};
	jointDesc.componentIndices = {component, self.drawbar.component};
	jointDesc.jointNode = componentJoint;
	jointDesc.jointIndex = constr:finalize();
	self.componentJoints[self.drawbar.jointIndex + 1] = jointDesc;
	setRigidBodyType(self.components[self.drawbar.component + 1].node, "Dynamic");
end;

function Agromet_Z211_2:playLowerStarWheelsSound()
	if self.lowerStarWheelsSound ~= nil then
		playSample(self.lowerStarWheelsSound, 1, self.lowerStarWheelsSoundVolume, 0);
	end;
end;

-- events
ChangeModeEvent = {};
ChangeModeEvent_mt = Class(ChangeModeEvent, Event);

InitEventClass(ChangeModeEvent, "ChangeModeEvent");

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

function ChangeModeEvent:new(vehicle, activeMode)
    local self = ChangeModeEvent:emptyNew()
    self.vehicle = vehicle;
	self.activeMode = activeMode;
    return self;
end;

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

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

function ChangeModeEvent:run(connection)   
	self.vehicle:changeMode(self.activeMode, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(ChangeModeEvent:new(self.vehicle, self.activeMode), nil, connection, self.vehicle);
    end;
end;

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

LowerStarWheelsEvent = {};
LowerStarWheelsEvent_mt = Class(LowerStarWheelsEvent, Event);

InitEventClass(LowerStarWheelsEvent, "LowerStarWheelsEvent");

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

function LowerStarWheelsEvent:new(vehicle, starWheelsState)
    local self = LowerStarWheelsEvent:emptyNew()
    self.vehicle = vehicle;
	self.starWheelsState = starWheelsState;
    return self;
end;

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

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

function LowerStarWheelsEvent:run(connection)   
	self.vehicle:lowerStarWheels(self.starWheelsState, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(LowerStarWheelsEvent:new(self.vehicle, self.starWheelsState), nil, connection, self.vehicle);
    end;
end;

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