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

--
-- Konwert do FS2015: Rockstar94
-- 02.11.2015
--

Agromet_Z211_2 = {};

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

function Agromet_Z211_2.initSpecialization()
	WorkArea.registerAreaType("windrower");
	WorkArea.registerAreaType("windrowerDrop");
	WorkArea.registerAreaType("tedder");
	WorkArea.registerAreaType("tedderDrop");
end;

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

function Agromet_Z211_2:preLoad(xmlFile)
	self.loadWorkAreaFromXML = Utils.overwrittenFunction(self.loadWorkAreaFromXML, Agromet_Z211_2.loadWorkAreaFromXML);
end;

function Agromet_Z211_2:load(xmlFile)
	local numWindrowerDropAreas = table.getn(self:getTypedWorkAreas(WorkArea.AREATYPE_WINDROWERDROP));
	if numWindrowerDropAreas == 0 then
		print("Warning: No drop areas specified in '"..self.configFileName.."'");
	else
		if numWindrowerDropAreas ~= 1 and numWindrowerDropAreas ~= table.getn(self:getTypedWorkAreas(WorkArea.AREATYPE_WINDROWER)) then
			print("Warning: Number of cutting areas and drop areas should be equal in '"..self.configFileName.."'");
		end;
	end;
		
	local numTedderDropAreas = table.getn(self:getTypedWorkAreas(WorkArea.AREATYPE_TEDDERDROP));
	if numTedderDropAreas == 0 then
	    print("Warning: No drop work areas specified in '"..self.configFileName.."'");
	else
	    if numTedderDropAreas ~= 1 and numTedderDropAreas ~= table.getn(self:getTypedWorkAreas(WorkArea.AREATYPE_TEDDER)) then
	        print("Warning: Number of work areas and drop work areas should be equal in '"..self.configFileName.."'");
	    end;
	end; 

	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.speedRotatingParts1 = {};
	local i=0;
	while true do
		local baseName = string.format("vehicle.speedRotatingParts1.speedRotatingPart1(%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.speedRotatingParts1, entry);
		end;
		i = i+1;
	end;
	
	self.grassParticleSystems = {};
	local i=0;
	while true do
		local baseName = string.format("vehicle.grassParticleSystems.grassParticleSystem(%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;
		particleSystem.disableTime = 0;
		particleSystem.isEnabled = false;
		table.insert(self.grassParticleSystems, particleSystem);
		i = i+1;
	end;
	
    self.windrowerParticleSystems = {};
    local i=0;
    while true do
        local keyPS = string.format("vehicle.windrowerParticleSystems.windrowerParticleSystem(%d)", i);
        local t = getXMLString(xmlFile, keyPS .. "#type");
        if t == nil then
            break;
        end;
        local fillType = Fillable.fillTypeNameToInt[t];
        local fruitType = FruitUtil.fillTypeToFruitType[fillType];
        if fruitType ~= nil then
            local particleSystem = {};
            particleSystem.ps = {};

            local particleNode = Utils.loadParticleSystem(xmlFile, particleSystem.ps, keyPS, self.components, false, nil, self.baseDirectory);

            particleSystem.disableTime = 0;
            particleSystem.isEnabled = false;

            particleSystem.fruitType = fruitType;
            particleSystem.workAreaIndex = Utils.getNoNil(getXMLInt(xmlFile, keyPS.."#workAreaIndex"),0)+1;

            table.insert(self.windrowerParticleSystems, particleSystem);
        end
        i=i+1;
    end;
	
	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.grassParticleSystems) do
		Utils.deleteParticleSystem(v.ps);
	end;
    for _,v in pairs(self.windrowerParticleSystems) do
        Utils.deleteParticleSystem(v.ps);
    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, "uvScrollSpeed", 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.speedRotatingParts1) 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 hasGroundContact, typedWorkAreas = self:getIsTypedWorkAreaActive(WorkArea.AREATYPE_TEDDER);
					self.hasGroundContact = hasGroundContact;
					
					if self.hasGroundContact then
						local foldAnimTime = self.foldAnimTime;
						self.isTedderSpeedLimitActive = true;
						if self.isServer then
							local workAreasSend = {};                    
							local typedWorkAreasDrop = self:getTypedWorkAreas(WorkArea.AREATYPE_TEDDERDROP);
							for k, workArea in pairs(typedWorkAreas) do
								if self:getIsWorkAreaActive(workArea) then
									local x,y,z = getWorldTranslation(workArea.start);
									local x1,y1,z1 = getWorldTranslation(workArea.width);
									local x2,y2,z2 = getWorldTranslation(workArea.height);
		
									local dropArea = typedWorkAreasDrop[workArea.dropAreaIndex];
									local dx,dy,dz = getWorldTranslation(dropArea.start);
									local dx1,dy1,dz1 = getWorldTranslation(dropArea.width);
									local dx2,dy2,dz2 = getWorldTranslation(dropArea.height);
			
									table.insert(workAreasSend, {x,z, x1,z1, x2,z2, dx,dz, dx1,dz1, dx2,dz2, 0, k});
								end;
							end;
		                    if (table.getn(workAreasSend) > 0) then
		                        local workAreasSend, bitType = TedderAreaEvent.runLocally(workAreasSend, self.accumulatedWorkAreaValues);
		                        if (table.getn(workAreasSend) > 0) then
		                            self.isWorking = true;
		                            if self:getLastSpeed(true) > 0.5 then
		                                for i=1, table.getn(workAreasSend) do
		                                    local workArea = typedWorkAreas[workAreasSend[i][14]];
		                                    if workArea.grassParticleSystemIndex ~= nil then
		                                        local ps = self.grassParticleSystems[workArea.grassParticleSystemIndex+1];
		                                        if ps ~= nil then
		                                            ps.disableTime = g_currentMission.time + 300;
		                                            if not ps.isEnabled then
		                                                ps.isEnabled = true;
		                                                self:raiseDirtyFlags(self.tedderParticleSystemFlag);
		                                                if self.isClient then
		                                                    Utils.setEmittingState(ps.ps, true);
		                                                end;
		                                            end;
		                                        end;
		                                    end;
		                                end;
		                            end;
		                            g_server:broadcastEvent(TedderAreaEvent:new(workAreasSend, bitType));
		                        end;
		                    end;
						end;
					end;
					if self.isServer then
						for k,v in pairs(self.grassParticleSystems) do
							if g_currentMission.time > v.disableTime then
								if v.isEnabled then
									v.isEnabled = false;
									self:raiseDirtyFlags(self.tedderParticleSystemFlag);
									if self.isClient then
										Utils.setEmittingState(v.ps, false);
									end;
								end;
							end;
						end;
					end;
				-- windrower mode function
				elseif self.currentMode == Agromet_Z211_2.WindrowerMode then
					local hasGroundContact, typedWorkAreas = self:getIsTypedWorkAreaActive(WorkArea.AREATYPE_WINDROWER);
					self.hasGroundContact = hasGroundContact;

					if hasGroundContact then
						self.isWindrowerSpeedLimitActive = true;
							if self.isServer then
					
							local workAreasSend = {};
							local typedWorkAreasDrop = self:getTypedWorkAreas(WorkArea.AREATYPE_WINDROWERDROP);
							for k, workArea in pairs(typedWorkAreas) do
								if self:getIsWorkAreaActive(workArea) then
									local x,y,z = getWorldTranslation(workArea.start);
									local x1,y1,z1 = getWorldTranslation(workArea.width);
									local x2,y2,z2 = getWorldTranslation(workArea.height);
					
									local dropArea = typedWorkAreasDrop[workArea.dropAreaIndex];
									local dx,dy,dz = getWorldTranslation(dropArea.start);
									local dx1,dy1,dz1 = getWorldTranslation(dropArea.width);
									local dx2,dy2,dz2 = getWorldTranslation(dropArea.height);
					
									table.insert(workAreasSend, {x,z, x1,z1, x2,z2, dx,dz, dx1,dz1, dx2,dz2, 0, k});
								end;
							end;
							
		                    if table.getn(typedWorkAreas) > 0 then
		                        local workAreasRet, fruitType, bitType = WindrowAreaEvent.runLocally(workAreasSend, self.accumulatedWorkAreaValues, self.accumulatedFruitType);
		
		                        if table.getn(workAreasRet) > 0 then
		                            self.accumulatedFruitType = fruitType;
		                            g_server:broadcastEvent(WindrowAreaEvent:new(workAreasRet, fruitType, bitType));
		
		                            if self:getLastSpeed(true) > 0.5 then
		                                for i=1, table.getn(workAreasRet) do
		                                    if workAreasRet[i][13] > 0 then
		                                        local workArea = typedWorkAreas[workAreasRet[i][14]];
		                                        for _,v in pairs(self.windrowerParticleSystems) do
		                                            if v.ps ~= nil and v.workAreaIndex == workAreasRet[i][14] and v.fruitType == self.accumulatedFruitType then
		                                                v.disableTime = g_currentMission.time + 300;
		                                                if not v.isEnabled then
		                                                    v.isEnabled = true;
		                                                    self:raiseDirtyFlags(self.windrowerGroundFlag);
		                                                    if self.isClient then
		                                                        Utils.setEmittingState(v.ps, true);
		                                                    end;
		                                                end;
		                                            end;
		                                        end;
		                                    end;
		                                end;
		                            end;
		
		                        end;
		                    end;
						end;
					end;
					if self.isServer then
		                for k,v in pairs(self.windrowerParticleSystems) do
		                    if g_currentMission.time > v.disableTime then
		                        if v.isEnabled then
		                            v.isEnabled = false;
		                            self:raiseDirtyFlags(self.windrowerGroundFlag);
		                            if self.isClient then
		                                Utils.setEmittingState(v.ps, false);
		                            end;
		                        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;
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)

	if self.isClient then
		for k,v in pairs(self.grassParticleSystems) do
			v.isEnabled = false;
			Utils.setEmittingState(v.ps, false);
		end;
	end;
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;

function Agromet_Z211_2:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key)
	local retValue = true;
		
	if superFunc ~= nil then
		retValue = superFunc(self, workArea, xmlFile, key)
	end

	if workArea.type == WorkArea.AREATYPE_DEFAULT then
		workArea.type = WorkArea.AREATYPE_WINDROWER;
	end;

	if workArea.type == WorkArea.AREATYPE_WINDROWER then
		workArea.windrowerParticleSystemIndex = getXMLInt(xmlFile, key .. "#particleSystemIndex");
		workArea.dropAreaIndex = Utils.getNoNil(getXMLInt(xmlFile, key .. "#dropAreaIndex"), 0) + 1;
		if self.accumulatedWorkAreaValues == nil then
			self.accumulatedWorkAreaValues = {};
		end;	
		self.accumulatedWorkAreaValues[table.getn(self.accumulatedWorkAreaValues)+1] = 0;
	end;

	if workArea.type == WorkArea.AREATYPE_TEDDER then
	    workArea.grassParticleSystemIndex = getXMLInt(xmlFile, key .. "#particleSystemIndex");
	    workArea.dropAreaIndex = Utils.getNoNil(getXMLInt(xmlFile, key .. "#dropAreaIndex"), 0) + 1;
	    if self.accumulatedWorkAreaValues == nil then
	        self.accumulatedWorkAreaValues = {};
	    end;
	    self.accumulatedWorkAreaValues[table.getn(self.accumulatedWorkAreaValues)+1] = 0;
	end;
		
	return retValue;
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;