local metadata = {
"## Interface:FS15 1.1.0.0 RC12",
"## Title: MilchTransport",
"## Notes: Zum Transport und Verkauf von Milch",
"## Author: Marhu",
"## Version: 4.8.0-16",
"## Date: 26.06.2015",
"## Web: http://marhu.net"
} 

 
source(g_currentModDirectory.."Scripte/MilchTrailerSetIsFillingEvent.lua");
source(g_currentModDirectory.."Scripte/MilchTrailerToggleEmptyStateEvent.lua");

MilchTransport = {};
MilchTransport.MilktruckFillTrigger = {}
MilchTransport.MilktruckStartTrigger = {}
MilchTransport.MilktruckClientTrigger = {}

MilchTransport.Dir = g_currentModDirectory;

if MilktruckFillTrigger.onCreate ~= nil then
	local orgFillTriggerOnCreate = MilktruckFillTrigger.onCreate;
	MilktruckFillTrigger.onCreate = function(a,id)
		orgFillTriggerOnCreate(a,id);
		table.insert(MilchTransport.MilktruckFillTrigger,id);
		if not g_currentMission:getIsServer() then
			addTrigger(id, "FillTriggerCallbackClient", MilchTransport)
			local org_FSBaseMission_delete = FSBaseMission.delete
			FSBaseMission.delete = function(...)
				removeTrigger(id)
				org_FSBaseMission_delete(...)
			end;
		end;
	end;
end;
if MilktruckFillTrigger.delete ~= nil then
	local orgFillTriggerdelete = MilktruckFillTrigger.delete;
	MilktruckFillTrigger.delete = function(a)
		for i = 1, table.getn(MilchTransport.MilktruckFillTrigger) do
			if MilchTransport.MilktruckFillTrigger[i] == a.triggerId then
				table.remove(MilchTransport.MilktruckFillTrigger,i);
				break;
			end;
		end;	
		orgFillTriggerdelete(a);
	end;
end;
if MilktruckStartTrigger.onCreate ~= nil then
	local orgStartTriggerOnCreate = MilktruckStartTrigger.onCreate;
	MilktruckStartTrigger.onCreate = function(a,id)
		orgStartTriggerOnCreate(a,id);
		table.insert(MilchTransport.MilktruckStartTrigger,id);
		if not g_currentMission:getIsServer() then
			addTrigger(id, "StartTriggerCallbackClient", MilchTransport)
			local org_FSBaseMission_delete = FSBaseMission.delete
			FSBaseMission.delete = function(...)
				removeTrigger(id)
				org_FSBaseMission_delete(...)
			end;
		end
	end;
end;
if MilktruckStartTrigger.delete ~= nil then
	local orgStartTriggerdelete = MilktruckStartTrigger.delete;
	MilktruckStartTrigger.delete = function(a)
		for i = 1, table.getn(MilchTransport.MilktruckStartTrigger) do
			if MilchTransport.MilktruckStartTrigger[i] == a.triggerId then
				table.remove(MilchTransport.MilktruckStartTrigger,i);
				break;
			end;
		end;
		orgStartTriggerdelete(a);
	end;
end;
local function HandleMilktruckTriggerCallback(otherShapeId, onEnter, trigger)
	local MilkTrailer = g_currentMission.objectToTrailer[otherShapeId];
	if MilkTrailer ~= nil and MilkTrailer.addMilchTrailerFillTrigger ~= nil and MilkTrailer.removeMilchTrailerFillTrigger ~= nil then
		if onEnter then
			MilkTrailer:addMilchTrailerFillTrigger(trigger);
		 else -- onLeave
			MilkTrailer:removeMilchTrailerFillTrigger(trigger);
		 end;
	end;
end
if MilktruckFillTrigger.triggerCallback ~= nil then
	local orgtriggerCallback = MilktruckFillTrigger.triggerCallback;
	MilktruckFillTrigger.triggerCallback = function(a, triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
		orgtriggerCallback(a, triggerId, otherId, onEnter, onLeave, onStay, otherShapeId);
		HandleMilktruckTriggerCallback(otherShapeId, onEnter, {id = triggerId, fillMilk = true})
	end;
end;
if MilktruckStartTrigger.triggerCallback ~= nil then
	local orgtriggerCallback = MilktruckStartTrigger.triggerCallback;
	MilktruckStartTrigger.triggerCallback = function(a, triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
		orgtriggerCallback(a, triggerId, otherId, onEnter, onLeave, onStay, otherShapeId);
		HandleMilktruckTriggerCallback(otherShapeId, onEnter, {id = triggerId, buyMilk = true})
	end;
end;

function MilchTransport:FillTriggerCallbackClient(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
	HandleMilktruckTriggerCallback(otherShapeId, onEnter, {id = triggerId, fillMilk = true})
end;

function MilchTransport:StartTriggerCallbackClient(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
	HandleMilktruckTriggerCallback(otherShapeId, onEnter, {id = triggerId, buyMilk = true})
end;
		
function MilchTransport.prerequisitesPresent(specializations)
    return true
end;

function MilchTransport:load(xmlFile)
			
	self.setIsMilchTrailerFilling = SpecializationUtil.callSpecializationsFunction("setIsMilchTrailerFilling");
	self.setIsMilchTrailerBuyMilk = SpecializationUtil.callSpecializationsFunction("setIsMilchTrailerBuyMilk");
    self.setIsZuchtFilling = SpecializationUtil.callSpecializationsFunction("setIsZuchtFilling");
	self.removeMilchTrailerFillTrigger = SpecializationUtil.callSpecializationsFunction("removeMilchTrailerFillTrigger");
    self.addMilchTrailerFillTrigger = SpecializationUtil.callSpecializationsFunction("addMilchTrailerFillTrigger");
	self.updatePowerTakeoff = SpecializationUtil.callSpecializationsFunction("updatePowerTakeoff");
	self.UpdateOverloadPipe = SpecializationUtil.callSpecializationsFunction("UpdateOverloadPipe");
	self.setOverloadPipe = SpecializationUtil.callSpecializationsFunction("setOverloadPipe");
	self.toggleEmptyState = SpecializationUtil.callSpecializationsFunction("toggleEmptyState");
	self.MilkTriggerCallback = MilchTransport.MilkTriggerCallback;
	
    self.isMilchTrailerFilling = false;
	self.isMilchTrailerBuyMilk = false;
    self.isZuchtFilling = false;
	
	self.milchTrailerActivatableAdded = false;
    self.milchTrailerActivatable = MilchTrailerActivatable:new(self);
  
    self.MilchTrailerFillTriggers = {};
 
    self.fillLitersPerSecond = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fillLitersPerSecond"), 500);
  
    local TrailerFillTriggerNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.milkTrailerFillTrigger#index"));
	if TrailerFillTriggerNode ~= nil then
		self.TrailerFillTrigger = TrailerFillTriggerNode;
		addTrigger(self.TrailerFillTrigger, "MilkTriggerCallback", self);
    end;
	
	self.fillSoundEnabled = false;
    local fillSound = getXMLString(xmlFile, "vehicle.fillSound#file");
	if fillSound ~= nil and fillSound ~= "" then
		fillSound  = Utils.getFilename(fillSound, MilchTransport.Dir);
		self.fillSound = createSample("fillSound");
		loadSample(self.fillSound, fillSound, false);
		self.fillSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fillSound#pitchOffset"), 1.0);
		self.fillSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fillSound#volume"), 1.0);
		setSamplePitch(self.fillSound, self.fillSoundPitchOffset);
	end;
	
	self.AddMarkierung = not Utils.getNoNil(getXMLBool(xmlFile, "vehicle.MilktruckTrigger#AddMarkierung"), false);
	
	local i = 0;
    while true do
        local key = string.format("vehicle.addMaterials.addMaterial(%d)", i);
        if not hasXMLProperty(xmlFile, key) then
            break;
        end;
		local filename = Utils.getFilename(getXMLString(xmlFile, key .. "#filename"),MilchTransport.Dir);
		local materialFile = Utils.loadSharedI3DFile(filename)
		local material = Utils.indexToObject(materialFile,getXMLString(xmlFile, key .. "#index"))
		Fillable:onCreateFillMaterial(material)
		i = i + 1
	end;	
	
	local OverloadPipe = getXMLString(xmlFile, "vehicle.OverloadPipe#index");
	if OverloadPipe ~= nil then
		self.OverloadPipe = {}
		self.OverloadPipe.node0 = Utils.indexToObject(self.components,OverloadPipe)
		self.OverloadPipe.node1 = getChildAt(self.OverloadPipe.node0,0)
		self.OverloadPipe.node2 = getChildAt(self.OverloadPipe.node1,0)
		local _,_,baseDistance = getTranslation(self.OverloadPipe.node2);
		self.OverloadPipe.pose = {getTranslation(self.OverloadPipe.node0)};
		self.OverloadPipe.rot = {getRotation(self.OverloadPipe.node0)};
		self.OverloadPipe.baseDistance = baseDistance;
		self.OverloadPipe.attacher = {}
		local i = 0;
		while true do
			local key = string.format("vehicle.OverloadPipe.attacher(%d)", i);
			if not hasXMLProperty(xmlFile, key) then
				break;
			end;
			local attacher = Utils.indexToObject(self.components,getXMLString(xmlFile, key .. "#index"))
			table.insert(self.OverloadPipe.attacher,attacher)
			i = i + 1
		end;	
	end;	

end;

function MilchTransport:delete()
	if self.TrailerFillTrigger then
		removeTrigger(self.TrailerFillTrigger);
		self.TrailerFillTrigger = nil;
	end
	if self.milchTrailerActivatableAdded then
		g_currentMission:removeActivatableObject(self.milchTrailerActivatable);
		self.milchTrailerActivatableAdded = false;
	end;
	if self.fillSound ~= nil then
        delete(self.fillSound);
    end;
end;

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

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

function MilchTransport:update(dt)
	if self:getIsActiveForInput() then
		if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA3) then
			if g_currentMission.MilktruckTriggerMarkierung and table.getn(g_currentMission.MilktruckTriggerMarkierung) > 0 then
				local vis = not getVisibility(g_currentMission.MilktruckTriggerMarkierung[1])
				for i = 1, table.getn(g_currentMission.MilktruckTriggerMarkierung) do
					 setVisibility(g_currentMission.MilktruckTriggerMarkierung[i],vis)
				end;
			end;
		elseif InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) then
			self:toggleEmptyState()
		end;
	end;
end;

function MilchTransport:updateTick(dt)
	
	if not self.AddMarkierung and not g_currentMission.MilktruckTriggerMarkierung then
		self.AddMarkierung = true
		
		g_currentMission.MilktruckTriggerMarkierung = {}
		if MilchTransport.MilktruckFillTrigger then
			for i = 1, table.getn(MilchTransport.MilktruckFillTrigger) do
				local MarkierungRoot = getChildAt(Utils.loadSharedI3DFile(MilchTransport.Dir.."Markierung.i3d"), 0);
				if MarkierungRoot then
					link(getRootNode(), MarkierungRoot);			
					local x, y, z = getWorldTranslation(MilchTransport.MilktruckFillTrigger[i]);
					y = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, y, z);
					setTranslation(MarkierungRoot, x, y, z);
					setVisibility(MarkierungRoot,false)
					table.insert(g_currentMission.MilktruckTriggerMarkierung,MarkierungRoot)
				end;
			end;
			MilchTransport.MilktruckFillTrigger = {};
		end
		if MilchTransport.MilktruckStartTrigger then
			for i = 1, table.getn(MilchTransport.MilktruckStartTrigger) do
				local MarkierungRoot = getChildAt(Utils.loadSharedI3DFile(MilchTransport.Dir.."Markierung.i3d"), 0);
				if MarkierungRoot then
					link(getRootNode(), MarkierungRoot);						
					local x, y, z = getWorldTranslation(MilchTransport.MilktruckStartTrigger[i]);
					y = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, y, z);
					setTranslation(MarkierungRoot, x, y, z);
					setVisibility(MarkierungRoot,false)
					table.insert(g_currentMission.MilktruckTriggerMarkierung,MarkierungRoot)
				end;
			end;
			MilchTransport.MilktruckStartTrigger = {};
		end;
	end;

	if self:getIsActive() or self.isMilchTrailerFilling or self.isMilchTrailerBuyMilk or self.isZuchtFilling then
        
		self.isNearMilktruckFillTrigger = nil
		self.isNearBuyMilkTrigger = nil
		self.isNearZuchtTrigger = nil
        for i=1, table.getn(self.MilchTrailerFillTriggers) do
			local trigger = self.MilchTrailerFillTriggers[i];
			if trigger.fillMilk then
				self.isNearMilktruckFillTrigger = trigger;
			elseif trigger.buyMilk then 
				self.isNearBuyMilkTrigger = trigger;
			elseif trigger.Zucht then 
				self.isNearZuchtTrigger = trigger.Zucht;
			end
			break;
		end

		if self.isNearMilktruckFillTrigger or self.isNearBuyMilkTrigger or self.isNearZuchtTrigger then
			if not self.milchTrailerActivatableAdded then
				g_currentMission:addActivatableObject(self.milchTrailerActivatable);
				self.milchTrailerActivatableAdded = true;
			end;
		else
			if self.milchTrailerActivatableAdded then
				g_currentMission:removeActivatableObject(self.milchTrailerActivatable);
				self.milchTrailerActivatableAdded = false;
			end;
		end;
		  
		if self.isServer then
            if self.isMilchTrailerFilling then
                if not self.isNearMilktruckFillTrigger then
                    self:setIsMilchTrailerFilling(false);
                end
            end
			if self.isMilchTrailerBuyMilk then
                if not self.isNearBuyMilkTrigger then
                    self:setIsMilchTrailerBuyMilk(false);
                end
            end
			if self.isZuchtFilling then
                if not self.isNearZuchtTrigger then
                    self:setIsZuchtFilling(false);
                end
            end
 
            if self.isMilchTrailerFilling then
                local delta = self.fillLitersPerSecond*dt*0.001;
 
                if self:allowFillType(Fillable.FILLTYPE_MILK, false) then
					local milk = 0
					milk = g_currentMission.husbandries.cow.fillLevelMilk or 0
					delta = math.min(milk,delta)
					local oldFillLevel = self:getFillLevel(Fillable.FILLTYPE_MILK);
					self:setFillLevel(oldFillLevel + delta, Fillable.FILLTYPE_MILK, true);
					delta = self:getFillLevel(Fillable.FILLTYPE_MILK) - oldFillLevel;
					g_currentMission.husbandries.cow.fillLevelMilk = milk - delta
				else
					delta = 0;
				end
                
                 if delta <= 0 then
                     self:setIsMilchTrailerFilling(false);
                 end;
			elseif self.isMilchTrailerBuyMilk then
				local delta = self.fillLitersPerSecond*dt*0.001;
				 
				local oldFillLevel = self:getFillLevel(Fillable.FILLTYPE_MILK);
				delta = math.min(oldFillLevel,delta)
				self:setFillLevel(oldFillLevel - delta, Fillable.FILLTYPE_MILK, true);
				delta = self:getFillLevel(Fillable.FILLTYPE_MILK) - oldFillLevel;
				local difficultyMultiplier = math.max(2 * (3 - g_currentMission.missionStats.difficulty), 1); -- 1  2  4
				local price = Fillable.fillTypeIndexToDesc[Fillable.FILLTYPE_MILK].pricePerLiter * difficultyMultiplier * delta;
				g_currentMission:addSharedMoney(-price);
				if delta >= 0 then
                     self:setIsMilchTrailerBuyMilk(false);
                end; 
			elseif self.isZuchtFilling then
				local delta = self.fillLitersPerSecond*dt*0.001;
				 
				delta = math.min(self:getFillLevel(self.currentFillType),delta)
				
				local oldFillLevel = self.isNearZuchtTrigger:getFillLevel(self.currentFillType);
				self.isNearZuchtTrigger:setFillLevel(oldFillLevel + delta, self.currentFillType);
				delta = self.isNearZuchtTrigger:getFillLevel(self.currentFillType) - oldFillLevel;
								
				self:setFillLevel(self:getFillLevel(self.currentFillType) - delta, self.currentFillType, true);
				
				if delta <= 0 then
                    self:setIsZuchtFilling(false);
                end; 
            end;
         end;
	end
	if self.isClient then
		if self.isMilchTrailerFilling or self.isMilchTrailerBuyMilk or self.isZuchtFilling or self.isWaterTrailerFilling then
			if not self.fillSoundEnabled and not self.isWaterTrailerFilling and self.fillSound ~= nil and self:getIsActiveForSound() then
				playSample(self.fillSound, 0, self.fillSoundVolume, 0);
				self.fillSoundEnabled = true;
			end;
			self:UpdateOverloadPipe(true)
		elseif self.WaterFillingMast == nil or self.WaterFillingMast > 1000 then
			if self.fillSoundEnabled then
				stopSample(self.fillSound);
				self.fillSoundEnabled = false;
			end;
			self:UpdateOverloadPipe(false)
		elseif self.WaterFillingMast ~= nil then
			self.WaterFillingMast = self.WaterFillingMast + dt;
		end;
	end;
end

function MilchTransport:readStream(streamId, connection)
    if connection:getIsServer() then
    end;
end;

function MilchTransport:writeStream(streamId, connection)
    if not connection:getIsServer() then
    end;
end;

function MilchTransport:readUpdateStream(streamId, timestamp, connection)
	if connection:getIsServer() then
		if self.isMilchTrailerFilling then
			fillLevel = streamReadFloat32(streamId);
			if fillLevel and fillLevel > 0 then
				g_currentMission.husbandries.cow.fillLevelMilk = fillLevel
			end
		end
	end
		 
end;

function MilchTransport:writeUpdateStream(streamId, connection, dirtyMask)
	if not connection:getIsServer() then
        if self.isMilchTrailerFilling then
			local milk = 0
			milk = g_currentMission.husbandries.cow.fillLevelMilk
			streamWriteFloat32(streamId, milk);
		end
	end
end;

function MilchTransport:draw()
	if self.isClient and self:getIsActiveForInput() then
		if g_currentMission.MilktruckTriggerMarkierung and table.getn(g_currentMission.MilktruckTriggerMarkierung) > 0 then
			if getVisibility(g_currentMission.MilktruckTriggerMarkierung[1]) then
				g_currentMission:addHelpButtonText(g_i18n:getText("Hidde_Marker"), InputBinding.IMPLEMENT_EXTRA3);
			else
				g_currentMission:addHelpButtonText(g_i18n:getText("Show_Marker"), InputBinding.IMPLEMENT_EXTRA3);
			end
		end;
		if self:getFillLevel(self.currentFillType) > 0 then
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("Milktrailer_empty"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA2);
		end
     end;
end;

function MilchTransport:onAttach()
end; 

function MilchTransport:onDetach()
	if self.milchTrailerActivatableAdded then
		g_currentMission:removeActivatableObject(self.milchTrailerActivatable);
		self.milchTrailerActivatableAdded = false;
	end;
	if self.fillSoundEnabled then
        stopSample(self.fillSound);
        self.fillSoundEnabled = false;
    end;
end;

function MilchTransport:onLeave()
	if self.milchTrailerActivatableAdded then
		g_currentMission:removeActivatableObject(self.milchTrailerActivatable);
		self.milchTrailerActivatableAdded = false;
	end;
	if self.fillSoundEnabled then
        stopSample(self.fillSound);
        self.fillSoundEnabled = false;
    end;
end

function MilchTransport:getSaveAttributesAndNodes(nodeIdent)

	local attributes = "";
    local nodes = "";
  	
	return attributes,nodes;
end

function MilchTransport:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	return BaseMission.VEHICLE_LOAD_OK;
end

function MilchTransport:setIsMilchTrailerFilling(isFilling, noEventSend)
    MilchTrailerSetIsFillingEvent.sendEvent(self, isFilling, self.isMilchTrailerBuyMilk, self.isZuchtFilling, noEventSend)
    self.isMilchTrailerFilling = isFilling;
end;
 
function MilchTransport:setIsMilchTrailerBuyMilk(isBy, noEventSend)
    MilchTrailerSetIsFillingEvent.sendEvent(self, self.isMilchTrailerFilling, isBy, self.isZuchtFilling, noEventSend)
    self.isMilchTrailerBuyMilk = isBy;
end;

function MilchTransport:setIsZuchtFilling(isFilling, noEventSend)
	MilchTrailerSetIsFillingEvent.sendEvent(self, self.isMilchTrailerFilling, self.isMilchTrailerBuyMilk, isFilling, noEventSend)
    self.isZuchtFilling = isFilling;
end;

function MilchTransport:updatePowerTakeoff(implement, dt)
	local jointDesc = self.attacherJoints[implement.jointDescIndex];
	if jointDesc.ptoActive then
        local object = implement.object;

        local ptoRootNode = jointDesc.ptoOutput.rootNode;
        local ptoAttachNode = jointDesc.ptoOutput.attachNode;
        local ptoDirAndScaleNode = jointDesc.ptoOutput.dirAndScaleNode;
        local ptoBaseDistance = jointDesc.ptoOutput.baseDistance;
        if object.ptoInput.rootNode ~= nil then
            ptoRootNode = object.ptoInput.rootNode;
            ptoAttachNode = object.ptoInput.attachNode
	        ptoDirAndScaleNode = object.ptoInput.dirAndScaleNode
	        ptoBaseDistance = object.ptoInput.baseDistance
        end
	
		if object.ptoInput.rotSpeed ~= 0 and object:getIsPowerTakeoffActive() then
			jointDesc.ptoOutput.rotation = (jointDesc.ptoOutput.rotation + dt*object.ptoInput.rotSpeed) % (2*math.pi);
			setRotation(ptoRootNode, 0, 0, jointDesc.ptoOutput.rotation);
			setRotation(ptoAttachNode, 0, 0, jointDesc.ptoOutput.rotation);
		end

		local x,y,z = getWorldTranslation(ptoAttachNode);
		local dx,dy,dz = worldToLocal(ptoRootNode, x,y,z);
		setDirection(ptoDirAndScaleNode, dx, dy, dz, 0, 1, 0);

		local _,_,dist = worldToLocal(ptoDirAndScaleNode, x,y,z);
		setScale(ptoDirAndScaleNode, 1, 1, dist/ptoBaseDistance);
	end
end

function MilchTransport:UpdateOverloadPipe(vis)
	if self.OverloadPipe then
		if vis then
			local parent
			if self.isNearMilktruckFillTrigger then
				parent = getParent(self.isNearMilktruckFillTrigger.id)
			elseif self.isNearBuyMilkTrigger then 
				parent = getParent(self.isNearBuyMilkTrigger.id)
			elseif self.isNearZuchtTrigger then
				parent = self.isNearZuchtTrigger.nodeId
			elseif self.isWaterTrailerFilling then
				for i=1, table.getn(self.waterTrailerFillTriggers) do
					local trigger = self.waterTrailerFillTriggers[i];
					if trigger:getIsActivatable(self) then
						parent = getParent(trigger.triggerId)
						break;
					end;
				end;
			end;
			local attacher = parent ~= nil and getChild(parent,"OverloadPipe") or 0;
			if attacher ~= 0 then
				local minDist = math.huge;
				local site
				local xa,ya,za = getWorldTranslation(attacher);
				for i = 1, table.getn(self.OverloadPipe.attacher) do
					local x1, y1, z1 = getWorldTranslation(self.OverloadPipe.attacher[i])
					dist = Utils.vector3Length(xa-x1, ya-y1, za-z1);
					if dist < minDist then
						minDist = dist
						site = self.OverloadPipe.attacher[i]
					end
				end
				local x,y,z = getTranslation(site)
				local rx,ry,rz = getRotation(site)
				setTranslation(self.OverloadPipe.node0,x,y,z)
				setRotation(self.OverloadPipe.node0,rx,ry,rz)
				local dx,dy,dz = worldToLocal(self.OverloadPipe.node0, xa,ya,za);
				setDirection(self.OverloadPipe.node1, dx, dy, dz, 0, 1, 0);
				if not self.OverloadPipe.attach then
					link(attacher,self.OverloadPipe.node2)
					setTranslation(self.OverloadPipe.node2, 0,0,0);
				end
				self.OverloadPipe.attach = true
			end;
		elseif self.OverloadPipe.attach then
			setTranslation(self.OverloadPipe.node0,unpack(self.OverloadPipe.pose))
			setRotation(self.OverloadPipe.node0,unpack(self.OverloadPipe.rot))
			setRotation(self.OverloadPipe.node1,0,0,0)
			link(self.OverloadPipe.node1,self.OverloadPipe.node2)
			setTranslation(self.OverloadPipe.node2, 0,0,self.OverloadPipe.baseDistance);
			setRotation(self.OverloadPipe.node2,0,0,0)
			self.OverloadPipe.attach = nil;
		end;
	end;
end;

function MilchTransport:setOverloadPipe(triggerId) -- SchweineMast
	self.WaterFillingMast = 0;
	if not self.fillSoundEnabled then
		playSample(self.fillSound, 0, self.fillSoundVolume, 0);
		self.fillSoundEnabled = true;
	end;
	local parent = getParent(triggerId)
	local attacher = parent ~= nil and getChild(parent,"OverloadPipe") or 0;
	if attacher ~= 0 then
		local minDist = math.huge;
		local site
		local xa,ya,za = getWorldTranslation(attacher);
		for i = 1, table.getn(self.OverloadPipe.attacher) do
			local x1, y1, z1 = getWorldTranslation(self.OverloadPipe.attacher[i])
			dist = Utils.vector3Length(xa-x1, ya-y1, za-z1);
			if dist < minDist then
				minDist = dist
				site = self.OverloadPipe.attacher[i]
			end
		end
		local x,y,z = getTranslation(site)
		local rx,ry,rz = getRotation(site)
		setTranslation(self.OverloadPipe.node0,x,y,z)
		setRotation(self.OverloadPipe.node0,rx,ry,rz)
		local dx,dy,dz = worldToLocal(self.OverloadPipe.node0, xa,ya,za);
		setDirection(self.OverloadPipe.node1, dx, dy, dz, 0, 1, 0);
		if not self.OverloadPipe.attach then
			link(attacher,self.OverloadPipe.node2)
			setTranslation(self.OverloadPipe.node2, 0,0,0);
		end
		self.OverloadPipe.attach = true
	end;
end;

function MilchTransport:toggleEmptyState(noEventSend)
	if g_server ~= nil then
		self:toggleTipState(tipTriggerDummy, 1);
	else
		MilchTrailerToggleEmptyStateEvent.sendEvent(self, noEventSend)
	end
end

function MilchTransport:addMilchTrailerFillTrigger(trigger, send, noEventSend)
	table.insert(self.MilchTrailerFillTriggers, trigger);
end;
 
function MilchTransport:removeMilchTrailerFillTrigger(trigger, send, noEventSend)
	 for i=1, table.getn(self.MilchTrailerFillTriggers) do
        if self.MilchTrailerFillTriggers[i].id == trigger.id then
            table.remove(self.MilchTrailerFillTriggers, i);
            break;
        end;
    end;
end;

function MilchTransport:MilkTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
	local vehicle = g_currentMission.nodeToVehicle[otherId];
	if vehicle ~= nil then
		if vehicle.milktruckStopNode then
			if onEnter then
				self:addMilchTrailerFillTrigger({id = otherId, buyMilk = true});
			else -- onLeave
				self:removeMilchTrailerFillTrigger({id = otherId, buyMilk = true});
			end;
		elseif vehicle ~= self and vehicle.addMilchTrailerFillTrigger ~= nil and vehicle.removeMilchTrailerFillTrigger ~= nil then
			if onEnter then
				vehicle:addMilchTrailerFillTrigger({id = triggerId, Zucht = self});
			else -- onLeave
				vehicle:removeMilchTrailerFillTrigger({id = triggerId, Zucht = self});
			end;
		end;
	end;
 end;
 
MilchTrailerActivatable = {}
local MilchTrailerActivatable_mt = Class(MilchTrailerActivatable);
 
function MilchTrailerActivatable:new(trailer)
    local self = {};
    setmetatable(self, MilchTrailerActivatable_mt);
 
    self.trailer = trailer;
    self.activateText = "unknown";
	local overlay = Utils.getFilename("Texturen/overlay.png", MilchTransport.Dir);
    self.Overlay = Overlay:new("OverloadOverlay", overlay, g_currentMission.hudTipperOverlay.x, g_currentMission.hudTipperOverlay.y, g_currentMission.hudTipperOverlay.width, g_currentMission.hudTipperOverlay.height); 
    return self;
end;
 
function MilchTrailerActivatable:getIsActivatable()
	if self.trailer:getIsActive() then --self.trailer:getIsActiveForInput() then
		if self.trailer.isNearMilktruckFillTrigger and self.trailer:getFillLevel(Fillable.FILLTYPE_MILK) < self.trailer.capacity and self.trailer:allowFillType(Fillable.FILLTYPE_MILK, false) then
			self:updateActivateText();
			return true;
		elseif (self.trailer.isNearBuyMilkTrigger or self.trailer.isNearZuchtTrigger) and self.trailer:getFillLevel(self.trailer.currentFillType) > 0 then
			self:updateActivateText();
			return true;
		end
    end
    return false;
end
 
function MilchTrailerActivatable:onActivateObject()
	if self.trailer.isNearMilktruckFillTrigger then
		self.trailer:setIsMilchTrailerFilling(not self.trailer.isMilchTrailerFilling);
	elseif self.trailer.isNearBuyMilkTrigger then
		self.trailer:setIsMilchTrailerBuyMilk(not self.trailer.isMilchTrailerBuyMilk);
	elseif self.trailer.isNearZuchtTrigger then
		self.trailer:setIsZuchtFilling(not self.trailer.isZuchtFilling);
	end
    self:updateActivateText();
    g_currentMission:addActivatableObject(self);
end;
 
function MilchTrailerActivatable:drawActivate()
   self.Overlay:render();
end;
 
function MilchTrailerActivatable:updateActivateText()
	if self.trailer.isNearMilktruckFillTrigger then
		if self.trailer.isMilchTrailerFilling then
			self.activateText = string.format(g_i18n:getText("stop_refill_OBJECT"), self.trailer.typeDesc);
		else
			self.activateText = string.format(g_i18n:getText("refill_OBJECT"), self.trailer.typeDesc);
		end;
	elseif self.trailer.isNearBuyMilkTrigger then
		if self.trailer.isMilchTrailerBuyMilk then
			self.activateText = g_i18n:getText("stop_selling");
		else
			self.activateText = g_i18n:getText("sell_milk");
		end;
	elseif self.trailer.isNearZuchtTrigger then
		if self.trailer.isZuchtFilling then
			self.activateText = string.format(g_i18n:getText("stop_refill_OBJECT"), g_i18n:getText("Milk_storage"));
		else
			self.activateText = string.format(g_i18n:getText("refill_OBJECT"), g_i18n:getText("Milk_storage"));
		end;
	end;
end;

tipTriggerDummy = {}
function tipTriggerDummy:getTipInfoForTrailer(trailer, tipReferencePointIndex)
	if trailer.tipReferencePoints and trailer.tipReferencePoints[tipReferencePointIndex] then
		return true, 0, tipReferencePointIndex
	elseif trailer.tipReferencePoints and trailer.tipReferencePoints[1] then
		return true, 0, 1
	end
	return math.huge, nil, -1
end
function tipTriggerDummy:updateTrailerTipping(trailer, fillDelta, fillType)
end