--
-- Cargos
--

CargosChangeModeEvent = {};
CargosChangeModeEvent_mt = Class(CargosChangeModeEvent, Event);

InitEventClass(CargosChangeModeEvent, "CargosChangeModeEvent");

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

function CargosChangeModeEvent:new(object, mode)
    local self = CargosChangeModeEvent:emptyNew()
    self.object = object;
    self.mode = mode;
    return self;
end;

function CargosChangeModeEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
    self.mode = streamReadInt8(streamId);
    self.object = networkGetObject(id);
    self:run(connection);
end;

function CargosChangeModeEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.object));
    streamWriteInt8(streamId, self.mode);
end;

function CargosChangeModeEvent:run(connection)
    self.object:changeMode(self.mode, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(CargosChangeModeEvent:new(self.object, self.mode), nil, connection, self.object);
    end;
end;


CargosSetTurnedEvent = {};
CargosSetTurnedEvent_mt = Class(CargosSetTurnedEvent, Event);

InitEventClass(CargosSetTurnedEvent, "CargosSetTurnedEvent");

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

function CargosSetTurnedEvent:new(object, turnedOn)
    local self = CargosSetTurnedEvent:emptyNew()
    self.object = object;
    self.turnedOn = turnedOn;
    return self;
end;

function CargosSetTurnedEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
    self.turnedOn = streamReadBool(streamId);
    self.object = networkGetObject(id);
    self:run(connection);
end;

function CargosSetTurnedEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.object));
    streamWriteBool(streamId, self.turnedOn);
end;

function CargosSetTurnedEvent:run(connection)
    self.object:setTurned(self.turnedOn, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(CargosSetTurnedEvent:new(self.object, self.turnedOn), nil, connection, self.object);
    end;
end;


CargosDrawBarEvent = {};
CargosDrawBarEvent_mt = Class(CargosDrawBarEvent, Event);

InitEventClass(CargosDrawBarEvent, "CargosDrawBarEvent");

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

function CargosDrawBarEvent:new(object, min, max)
    local self = CargosDrawBarEvent:emptyNew()
    self.object = object;
    self.min = min;
    self.max = max;
    return self;
end;

function CargosDrawBarEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
    self.min = streamReadBool(streamId);
    self.max = streamReadBool(streamId);
    self.object = networkGetObject(id);
    self:run(connection);
end;

function CargosDrawBarEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.object));
    streamWriteBool(streamId, self.min);
    streamWriteBool(streamId, self.max);
end;

function CargosDrawBarEvent:run(connection)
    self.object.drawbarMin=self.min;
    self.object.drawbarMax=self.max;
    if not connection:getIsServer() then
        g_server:broadcastEvent(CargosDrawBarEvent:new(self.object, self.min, self.max), nil, connection, self.object);
    end;
end;


CargosBrakeLightEvent = {};
CargosBrakeLightEvent_mt = Class(CargosBrakeLightEvent, Event);

InitEventClass(CargosBrakeLightEvent, "CargosBrakeLightEvent");

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

function CargosBrakeLightEvent:new(object, active)
    local self = CargosBrakeLightEvent:emptyNew()
    self.object = object;
    self.active = active;
    return self;
end;

function CargosBrakeLightEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
    self.active = streamReadBool(streamId);
    self.object = networkGetObject(id);
    self:run(connection);
end;

function CargosBrakeLightEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.object));
    streamWriteBool(streamId, self.active);
end;

function CargosBrakeLightEvent:run(connection)
    self.object.brakeLightActive=self.active;
    if not connection:getIsServer() then
        g_server:broadcastEvent(CargosBrakeLightEvent:new(self.object, self.active), nil, connection, self.object);
    end;
end;


CargosAreaEvent = {};
CargosAreaEvent_mt = Class(CargosAreaEvent, Event);

InitEventClass(CargosAreaEvent, "CargosAreaEvent");

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

function CargosAreaEvent:new(cuttingAreas, fruitType)
    local self = CargosAreaEvent:emptyNew()
    self.cuttingAreas = cuttingAreas;
    self.fruitType = fruitType;
    return self;
end;

function CargosAreaEvent:readStream(streamId, connection)
    local fruitType = streamReadInt8(streamId);
    local _fruitType = FruitUtil.fillTypeToFruitType[fruitType];
    local numAreas = streamReadUIntN(streamId, 4);

    local refX = streamReadFloat32(streamId);
    local refY = streamReadFloat32(streamId);
    local values = Utils.readCompressed2DVectors(streamId, refX, refY, numAreas*3-1, 0.01, true);
    for i=1,numAreas do
        local vi = i-1;
        local x = values[vi*3+1].x;
        local z = values[vi*3+1].y;
        local x1 = values[vi*3+2].x;
        local z1 = values[vi*3+2].y;
        local x2 = values[vi*3+3].x;
        local z2 = values[vi*3+3].y;
--        Utils.updateCuttedMeadowArea(x, z, x1, z1, x2, z2);
        Utils.updateFruitWindrowArea(_fruitType, x, z, x1, z1, x2, z2, 0);
        Utils.updateFruitCutLongArea(_fruitType, x, z, x1, z1, x2, z2, 0);
    end;
end;

function CargosAreaEvent:writeStream(streamId, connection)
    streamWriteInt8(streamId,self.fruitType);
    local numAreas = table.getn(self.cuttingAreas);
    streamWriteUIntN(streamId, numAreas, 4);
    local refX, refY;
    local values = {};
    for i=1, numAreas do
        local d = self.cuttingAreas[i];
        if i==1 then
            refX = d[1];
            refY = d[2];
            streamWriteFloat32(streamId, d[1]);
            streamWriteFloat32(streamId, d[2]);
        else
            table.insert(values, {x=d[1], y=d[2]});
        end;
        table.insert(values, {x=d[3], y=d[4]});
        table.insert(values, {x=d[5], y=d[6]});
    end;
    assert(table.getn(values) == numAreas*3 - 1);
    Utils.writeCompressed2DVectors(streamId, refX, refY, values, 0.01);
end;

function CargosAreaEvent:run(connection)
    print("Error: Do not run CargosAreaEvent locally");
end;

function CargosAreaEvent.runLocally(cuttingAreas, fillTypes, currentFruitType)

    local numAreas = table.getn(cuttingAreas);
    

    local refX, refY;
    local values = {};
    for i=1, numAreas do
        local d = cuttingAreas[i];
        if i==1 then
            refX = d[1];
            refY = d[2];
        else
            table.insert(values, {x=d[1], y=d[2]});
        end;
        table.insert(values, {x=d[3], y=d[4]});
        table.insert(values, {x=d[5], y=d[6]});
    end;
    assert(table.getn(values) == numAreas*3 - 1);

    local values = Utils.simWriteCompressed2DVectors(refX, refY, values, 0.01, true);

    local area = 0;
    for i=1, numAreas do
      local vi = i-1;
      local x = values[vi*3+1].x;
      local z = values[vi*3+1].y;
      local x1 = values[vi*3+2].x;
      local z1 = values[vi*3+2].y;
      local x2 = values[vi*3+3].x;
      local z2 = values[vi*3+3].y;
      for fruitType,v in pairs(fillTypes) do
        local _fruitType = FruitUtil.fillTypeToFruitType[fruitType];
        if _fruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then
		      if currentFruitType == _fruitType or currentFruitType == FruitUtil.FRUITTYPE_UNKNOWN then
            local area = Utils.updateFruitWindrowArea(_fruitType, x, z, x1, z1, x2, z2, 0)*g_currentMission.windrowCutLongRatio;
            area = area + Utils.updateFruitCutLongArea(_fruitType, x, z, x1, z1, x2, z2, 0);
		  		  if area > 0 then
					    return area, fruitType;
            end;
          end;
        end;
      end;
    end;
    return area, fruitType;
end;


Cargos = {};
Cargos.FORAGE  = 0;
Cargos.SILAGE  = 1;

function Cargos.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Trailer, specializations);
end;

function Cargos:load(xmlFile)
    self.setFillLevel = Utils.overwrittenFunction(self.setFillLevel, Cargos.setFillLevel);
    self.updateForage = Cargos.updateForage;
    self.updateSilage = Cargos.updateSilage;
    self.changeMode = Cargos.changeMode;
    self.setTurned = Cargos.setTurned;
    self.telo = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.telo#index"));
    self.floorAnimSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.telo#speed"), 0.3);
    self.grainPlanes = {};
    local i = 0;
    while true do
        local key = string.format("vehicle.grainPlane.node(%d)", i);
        local t = getXMLString(xmlFile, key.."#type");
        local index = getXMLString(xmlFile, key.."#index");
        if t==nil or index==nil then
            break;
        end;

        local node = Utils.indexToObject(self.components, index);
        if node ~= nil then
            setVisibility(node, false);
            if self.defaultGrainPlane == nil then
                self.defaultGrainPlane = node;
            end;
            self.grainPlanes[t] = node;
        end;
        i = i +1;
    end;
    if self.defaultGrainPlane==nil then
        self.grainPlanes = nil;
    end;

    self.grainPlaneMinY, self.grainPlaneMaxY = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.grainPlane#minMaxY"));
    if self.grainPlaneMinY == nil or self.grainPlaneMaxY == nil then
        local grainAnimCurve = AnimCurve:new(linearInterpolator4);
        local keyI = 0;
        while true do
            local key = string.format("vehicle.grainPlane.key(%d)", keyI);
            local t = getXMLFloat(xmlFile, key.."#time");
            local yValue = getXMLFloat(xmlFile, key.."#y");
            local scaleX,scaleY,scaleZ = Utils.getVectorFromString(getXMLString(xmlFile, key.."#scale"));
            if yValue == nil or scaleX == nil or scaleY == nil or scaleZ == nil then
                break;
            end;
            grainAnimCurve:addKeyframe({x=scaleX, y=scaleY, z=scaleZ, w=yValue, time = t});
            keyI = keyI +1;
        end;
        if keyI > 0 then
            self.grainAnimCurve = grainAnimCurve;
        end;
        self.grainPlaneMinY = 0;
        self.grainPlaneMaxY = 0;
    end;

    self.jointSearch = false;
    self.lastTipTriggerInRange = false;
    self.timerRunning = false;
    self.posun = false;
    self.ForagefillTypes = {};
    self.ForagefillTypes[FruitUtil.FRUITTYPE_UNKNOWN] = true;

    local ForagefruitTypes = getXMLString(xmlFile, "vehicle.ForagefillTypes#fruitTypes");
    if ForagefruitTypes ~= nil then
        local Foragetypes = Utils.splitString(" ", ForagefruitTypes);
        for k,v in pairs(Foragetypes) do
            local desc = Fillable.fillTypeNameToInt[v];
            if desc ~= nil then
                self.ForagefillTypes[desc] = true;
            end;
        end;
    end;
    
    self.SilagefillTypes = {};
    self.SilagefillTypes[FruitUtil.FRUITTYPE_UNKNOWN] = true;

    local SilagefruitTypes = getXMLString(xmlFile, "vehicle.SilagefillTypes#fruitTypes");
    if SilagefruitTypes ~= nil then
        local Silagetypes = Utils.splitString(" ", SilagefruitTypes);
        for k,v in pairs(Silagetypes) do
            local desc = Fillable.fillTypeNameToInt[v];
            if desc ~= nil then
                self.SilagefillTypes[desc] = true;
            end;
        end;
    end;
    

    local forageWgnSound = getXMLString(xmlFile, "vehicle.forageWgnSound#file");
    if forageWgnSound ~= nil and forageWgnSound ~= "" then
        forageWgnSound = Utils.getFilename(forageWgnSound, self.baseDirectory);
        self.forageWgnSound = createSample("forageWgnSound");
        self.forageWgnSoundEnabled = false;
        loadSample(self.forageWgnSound, forageWgnSound, false);
        self.forageWgnSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.forageWgnSound#pitchOffset"), 1);
        self.forageWgnSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.forageWgnSound#volume"), 1.0);
    end;

    local convoyWgnSound = getXMLString(xmlFile, "vehicle.convoyWgnSound#file");
    if convoyWgnSound ~= nil and convoyWgnSound ~= "" then
        convoyWgnSound = Utils.getFilename(convoyWgnSound, self.baseDirectory);
        self.convoyWgnSound = createSample("convoyWgnSound");
        self.convoyWgnSoundEnabled = false;
        loadSample(self.convoyWgnSound, convoyWgnSound, false);
        self.convoyWgnSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.convoyWgnSound#pitchOffset"), 1);
        self.convoyWgnSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.convoyWgnSound#volume"), 1.0);
    end;

		local pickupNode = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.pickup#index"));
    if pickupNode ~= nil then
        self.pickup = {};
        self.pickup.node = pickupNode;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.pickup#minRot"));
        self.pickup.minRot = {};
        self.pickup.minRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.pickup.minRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.pickup.minRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.pickup#maxRot"));
        self.pickup.maxRot = {};
        self.pickup.maxRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.pickup.maxRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.pickup.maxRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        self.pickup.rotTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.pickup#rotTime"), 2)*1000;
        self.pickup.touchRotLimit = Utils.degToRad(Utils.getNoNil(getXMLString(xmlFile, "vehicle.pickup#touchRotLimit"), 10));
    end;
    
		local drawbarNode = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.drawbar#index"));
    if drawbarNode ~= nil then
        self.drawbar = {};
        self.drawbar.node = drawbarNode;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.drawbar#minRot"));
        self.drawbar.minRot = {};
        self.drawbar.minRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.drawbar.minRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.drawbar.minRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.drawbar#maxRot"));
        self.drawbar.maxRot = {};
        self.drawbar.maxRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.drawbar.maxRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.drawbar.maxRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        self.drawbar.rotTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.pickup#rotTime"), 2)*1000;
        self.drawbar.touchRotLimit = Utils.degToRad(Utils.getNoNil(getXMLString(xmlFile, "vehicle.pickup#touchRotLimit"), 10));
        
        self.drawbar.nahon = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.drawbar#nahon"));
        if self.drawbar.nahon ~= nil then
          x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.drawbar#maxRotNahon"));
          self.drawbar.maxRotNahon = {};
          self.drawbar.maxRotNahon[1] = Utils.degToRad(Utils.getNoNil(x, 0));
          self.drawbar.maxRotNahon[2] = Utils.degToRad(Utils.getNoNil(y, 0));
          self.drawbar.maxRotNahon[3] = Utils.degToRad(Utils.getNoNil(z, 0));

          local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.drawbar#minRotNahon"));
          self.drawbar.minRotNahon = {};
          self.drawbar.minRotNahon[1] = Utils.degToRad(Utils.getNoNil(x, 0));
          self.drawbar.minRotNahon[2] = Utils.degToRad(Utils.getNoNil(y, 0));
          self.drawbar.minRotNahon[3] = Utils.degToRad(Utils.getNoNil(z, 0));
        end;
        
    end;
    
	
    self.wholepickup= Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.wholepickup#index"));
    self.pickupcover= Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.wholepickup#cover"));
    
    self.drum1= Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.drum#index1"));
    self.drumRotationScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.drum#rotationScale"), 1);

    self.crusher= Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.crusher#index1"));
    self.crusherRotationScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.crusher#rotationScale"), 1);

    self.spreadersCount = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.spreaders#count"), 0);
    if self.spreadersCount > 0 then
      self.spreadersSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.spreaders#speed"), 0.01);
      self.spreaders = {};
      for i = 1, self.spreadersCount do
        local sid = string.format("vehicle.spreaders.spreader%d#index", i);
        local spread = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, sid));
        table.insert(self.spreaders,i,spread);
      end;
    end;

    local grainTipAnimCurve = AnimCurve:new(linearInterpolator4);
    local keyI = 0;
    while true do
      local key = string.format("vehicle.grainPlane.tipkey(%d)", keyI);
      local t = getXMLFloat(xmlFile, key.."#time");
      local yValue = getXMLFloat(xmlFile, key.."#y");
      local scaleX,scaleY,scaleZ = Utils.getVectorFromString(getXMLString(xmlFile, key.."#scale"));
      if yValue == nil or scaleX == nil or scaleY == nil or scaleZ == nil then
        break;
      end;
      grainTipAnimCurve:addKeyframe({x=scaleX, y=scaleY, z=scaleZ, w=yValue, time = t});
      keyI = keyI +1;
    end;
    if keyI > 1 then
      self.grainTipAnimCurve = grainTipAnimCurve;
    end;
    
    local silageAnimCurve = AnimCurve:new(linearInterpolator4);
    local keyI = 0;
    while true do
      local key = string.format("vehicle.grainPlane.silagekey(%d)", keyI);
      local t = getXMLFloat(xmlFile, key.."#time");
      local yValue = getXMLFloat(xmlFile, key.."#y");
      local scaleX,scaleY,scaleZ = Utils.getVectorFromString(getXMLString(xmlFile, key.."#scale"));
      if yValue == nil or scaleX == nil or scaleY == nil or scaleZ == nil then
        break;
      end;
      silageAnimCurve:addKeyframe({x=scaleX, y=scaleY, z=scaleZ, w=yValue, time = t});
      keyI = keyI +1;
    end;
    if keyI > 0 then
      self.silageAnimCurve = silageAnimCurve;
    end;
    
    local silageTipAnimCurve = AnimCurve:new(linearInterpolator4);
    local keyI = 0;
    while true do
      local key = string.format("vehicle.grainPlane.silagetipkey(%d)", keyI);
      local t = getXMLFloat(xmlFile, key.."#time");
      local yValue = getXMLFloat(xmlFile, key.."#y");
      local scaleX,scaleY,scaleZ = Utils.getVectorFromString(getXMLString(xmlFile, key.."#scale"));
      
      if yValue == nil or scaleX == nil or scaleY == nil or scaleZ == nil then
        break;
      end;
      silageTipAnimCurve:addKeyframe({x=scaleX, y=scaleY, z=scaleZ, w=yValue, time = t});
      keyI = keyI +1;
    end;
    if keyI > 0 then
      self.silageTipAnimCurve = silageTipAnimCurve;
    end;    
    
    if self.isClient then
      self.reverseLightObject = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.reverselights#index"));
      setVisibility(self.reverseLightObject, false);
      self.reverseLightActive = false;

      self.brakeLightObject = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.brakelights#index"));
      setVisibility(self.brakeLightObject, false);
      self.brakeLightActive = 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);
        self.hydraulicSoundEnabled = false;
      end;
    end;     

    self.fillScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fillScale#value"), 1);
    self.fillNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.fillNode#index"));
    if self.fillNode ~= nil then
      self.fillNodeMinZ = getXMLFloat(xmlFile, "vehicle.fillNode#minZ");
      self.fillNodeMaxZ = getXMLFloat(xmlFile, "vehicle.fillNode#maxZ");
    end;
    self.mode = Cargos.FORAGE;
    self.fillTypes = self.ForagefillTypes;
    self.wasToFast = false;
    self.isTurnedOn = false;
	  self.currentFruitType = FruitUtil.FRUITTYPE_UNKNOWN;
	  self.lastFruitType = FruitUtil.FRUITTYPE_UNKNOWN;
	  self.pickupMax = false;
	  self.allowFillFromAir = false;
	  self.TipTriggerInRange = false;
	  self.drawbarMin = false;
	  self.drawbarMax = false;
	  
    self.currentFillType = FruitUtil.FRUITTYPE_UNKNOWN;
    self:setFillLevel(0, FruitUtil.FRUITTYPE_UNKNOWN);	  
end;

function Cargos:delete()
  if self.isClient then
    if self.forageWgnSound ~= nil then
        delete(self.forageWgnSound);
        self.forageWgnSound=nil;
    end;
    if self.hydraulicSound ~= nil then
        delete(self.hydraulicSound);
        self.hydraulicSound=nil;
    end;
  end;           
end;

function Cargos:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
    local rot1 = getXMLFloat(xmlFile, key.."#drawbarRot");
    if rot1~=nil then
      local x,y,z = getRotation(self.drawbar.node);
      setRotation(self.drawbar.node, Utils.degToRad(rot1), y, z); 
    end; 
    local rot2 = getXMLFloat(xmlFile, key.."#nahonRot");
    if rot2~=nil then
      local a,b,c = getRotation(self.drawbar.nahon);
      setRotation(self.drawbar.nahon, Utils.degToRad(rot2), b, c); 
    end; 
    
    local cargosMode = getXMLString(xmlFile, key.."#cargosMode");
    if cargosMode ~= nil then
      if cargosMode == "forage" then
        self:changeMode(Cargos.FORAGE);
      end;
      if cargosMode == "silage" then
        self:changeMode(Cargos.SILAGE);
      end;      
    end;
    local fillLevel = getXMLFloat(xmlFile, key.."#fillLevel");
    local fillType = getXMLString(xmlFile, key.."#fillType");
    if fillLevel ~= nil and fillType ~= nil then
        local fillTypeDesc = FruitUtil.fruitTypes[fillType];
        if fillTypeDesc ~= nil then
            self:setFillLevel(fillLevel, FruitUtil.fruitTypeToFillType[fillTypeDesc.index]);
        end;
    end;
    return BaseMission.VEHICLE_LOAD_OK;
end;

function Cargos:getSaveAttributesAndNodes(nodeIdent)
    local cargosMode = "forage";
    if self.mode == Cargos.SILAGE then
      cargosMode = "silage";
    end;
    local rot1,y,z = getRotation(self.drawbar.node);
    local rot2,a,b = getRotation(self.drawbar.nahon);  
    local attributes = 'cargosMode="'..cargosMode..'" drawbarRot="'..math.deg(rot1)..'" nahonRot="'..math.deg(rot2)..'"';
    return attributes, nil;
end;

function Cargos:readStream(streamId, timestamp, connection)
  local mode = streamReadInt8(streamId);
  local turnedOn = streamReadBool(streamId);
  self:changeMode(mode, true);
  self:setTurned(turnedOn, true);
  local x,y,z = getRotation(self.drawbar.node);
  x = streamReadFloat32(streamId);
  setRotation(self.drawbar.node, x, y, z);
  local a,b,c = getRotation(self.drawbar.nahon);
  a = streamReadFloat32(streamId);
  setRotation(self.drawbar.nahon, a, b, c);
end;

function Cargos:writeStream(streamId, connection, dirtyMask)
  streamWriteInt8(streamId, self.mode);
  streamWriteBool(streamId, self.isTurnedOn);
  local x,y,z = getRotation(self.drawbar.node);
  streamWriteFloat32(streamId, x);
  local a,b,c = getRotation(self.drawbar.nahon);
  streamWriteFloat32(streamId, a);
end;

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

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

function Cargos:changeMode(mode, noEventSend)
  if self.mode ~= mode then
    if mode == Cargos.FORAGE then
      self.isTurnedOn = false;
      self.pickupMax = false;
      self.mode = Cargos.FORAGE;
      self.fillTypes = self.ForagefillTypes;
      setVisibility(self.wholepickup, true); 
      setVisibility(self.pickupcover, false);
      self.allowFillFromAir = false;
    else
      self.isTurnedOn = false;
      self.pickupMax = false;
      self.mode = Cargos.SILAGE;
      self.fillTypes = self.SilagefillTypes;
      setVisibility(self.wholepickup, false); 
      setVisibility(self.pickupcover, true);
      self.allowFillFromAir = true;
    end;
    if noEventSend == nil or noEventSend == false then
      if g_server ~= nil then
        g_server:broadcastEvent(CargosChangeModeEvent:new(self, mode), nil, nil, self);
      else
        g_client:getServerConnection():sendEvent(CargosChangeModeEvent:new(self, mode));
      end;
    end;    
  end;
end;

function Cargos:setTurned(turnedOn, noEventSend)
  if self.isTurnedOn ~= turnedOn then
    self.isTurnedOn = turnedOn;
    self.pickupMax = turnedOn; 
    
    if noEventSend == nil or noEventSend == false then
      if g_server ~= nil then
        g_server:broadcastEvent(CargosSetTurnedEvent:new(self, turnedOn), nil, nil, self);
      else
        g_client:getServerConnection():sendEvent(CargosSetTurnedEvent:new(self, turnedOn));
      end;
    end;                
  end;
end;

function Cargos:update(dt)
  if self.isClient then
    if self:getIsActiveForInput() then
      if (InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2)) and (self.fillLevel == 0) and (not self.isTurnedOn) then
        local mode = Cargos.FORAGE;
        if self.mode == Cargos.FORAGE then
          mode = Cargos.SILAGE;
        end;
        self:changeMode(mode);
      end;  

      if self.vehicleJoint ~= nil then
        local prevMin = self.drawbarMin;
        local prevMax = self.drawbarMax;
        self.drawbarMin = InputBinding.isPressed(InputBinding.LOWER_CARGOS);
        self.drawbarMax = InputBinding.isPressed(InputBinding.LIFT_CARGOS);
        if (prevMin~=self.drawbarMin) or (prevMax~=self.drawbarMax) then
          if g_server ~= nil then
            g_server:broadcastEvent(CargosDrawBarEvent:new(self, self.drawbarMin, self.drawbarMax), nil, nil, self);
          else
            g_client:getServerConnection():sendEvent(CargosDrawBarEvent:new(self, self.drawbarMin, self.drawbarMax));
          end;          
        end; 
      end;
    end;  
    if self.spreadersCount > 0 then
      local v = true;
      if ((FruitUtil.fillTypeToFruitType[self.currentFillType] == FruitUtil.FRUITTYPE_WHEAT) or (FruitUtil.fillTypeToFruitType[self.currentFillType] == FruitUtil.FRUITTYPE_BARLEY)) then
        v = false;
      end;
      if (self.tipState == Trailer.TIPSTATE_CLOSING) or (((self.tipState == Trailer.TIPSTATE_OPENING) or (self.tipState == Trailer.TIPSTATE_OPEN)) and (self.fillLevel == 0)) then
        if ((FruitUtil.fillTypeToFruitType[self.lastFruitType] == FruitUtil.FRUITTYPE_WHEAT) or (FruitUtil.fillTypeToFruitType[self.lastFruitType] == FruitUtil.FRUITTYPE_BARLEY)) then
          v = false;
        end;
      end; 
      for i=1, self.spreadersCount do
        if self.spreaders[i] ~= nil then
          setVisibility(self.spreaders[i], v);	      
        end;
      end;
    end; 

    if self.jointSearch then
      for k,v in pairs(self.attacherVehicle.attachedImplements) do
        if v.object == self then
          local joint = self.attacherVehicle.attacherJoints[v.jointDescIndex];
          self.vehicleJoint = joint;					
          setJointFrame(joint.jointIndex, 0, self.attacherPoint);
        end;
      end;
      self.jointSearch = false;
    end;	
  
    local doRotate = self.drawbarMax or self.drawbarMin
  
    if (not doRotate) and ((self.tipState == Trailer.TIPSTATE_OPEN) or (self.tipState == Trailer.TIPSTATE_CLOSED)) and (self.hydraulicSoundEnabled) then
      stopSample(self.hydraulicSound);
      self.hydraulicSoundEnabled = false;   
    end;
  
    if (self.drawbar ~= nil) and doRotate then
      local x, y, z = getRotation(self.drawbar.node);
      local rot = {x,y,z};
      local newRot = Utils.getMovedLimitedValues(rot, self.drawbar.maxRot, self.drawbar.minRot, 3, self.drawbar.rotTime, dt, self.drawbarMax);   
      setRotation(self.drawbar.node, unpack(newRot));
      if math.abs(x-newRot[1]) > 0.001 then
        if not self.hydraulicSoundEnabled and self.hydraulicSound ~= nil and self:getIsActiveForSound() then
          playSample(self.hydraulicSound, 0, self.hydraulicSoundVolume, 0);
          setSamplePitch(self.hydraulicSound, self.hydraulicSoundPitchOffset-0.4);
          self.hydraulicSoundEnabled = true;
        end;   
      end;
    
      if (self.drawbar.nahon ~= nil) then
        x, y, z = getRotation(self.drawbar.nahon);
        rot = {x,y,z};
        newRot = Utils.getMovedLimitedValues(rot, self.drawbar.maxRotNahon, self.drawbar.minRotNahon, 3, self.drawbar.rotTime, dt, self.drawbarMax);      
        setRotation(self.drawbar.nahon, unpack(newRot));
      end;    
      setJointFrame(self.vehicleJoint.jointIndex, 1, self.attacherJoint.node);      
    end;
  end;
  if self.mode == Cargos.FORAGE then
    self:updateForage(dt);
  else
    self:updateSilage(dt);
  end;
  if self.isClient then
    if self.tipState == Trailer.TIPSTATE_OPENING or self.tipState == Trailer.TIPSTATE_OPEN then
      if (self.fillLevel ~= 0) and (self.currentFillType ~= FruitUtil.FRUITTYPE_UNKNOWN) then
        self.lastFruitType = self.currentFillType;
      end; 
      if self.spreadersCount > 0 then
        for i=1, self.spreadersCount do
          if self.spreaders[i] ~= nil then
            rotate(self.spreaders[i],self.spreadersSpeed * 100,0,0);
          end;
        end;
      end;
    end;
    if self.tipState == Trailer.TIPSTATE_CLOSED and self.fillLevel==0 then
      self.lastFruitType = self.currentFillType;
    end;
	
    if (self.tipState == Trailer.TIPSTATE_CLOSED) and (self.fillLevel>0) and (FruitUtil.fillTypeToFruitType[self.currentFillType] == FruitUtil.FRUITTYPE_CHAFF) then
      self.lastTipTriggerInRange = self.TipTriggerInRange;
      self.TipTriggerInRange = (TipTriggerInRange(self)~=nil);

      if (self.lastTipTriggerInRange ~= self.TipTriggerInRange) then
        if self.timerRunning then
          self.timer=4000-self.timer;
        else
          self.timer=4000;
        end;
        self.timerRunning = true;
      end;   
      
      if self.timerRunning then
        self.timer=self.timer-dt;

        local fillTypeName = Fillable.fillTypeIntToName[self.currentFillType];
        local grainPlane = self.grainPlanes[fillTypeName];

        local x, y, z = getTranslation(grainPlane);
        local trans = {x,y,z}; 
        local tX, tY, tZ , tTrans = self.silageTipAnimCurve:get(self.fillLevel/self.capacity);
        local sX, sY, sZ , sTrans = self.silageAnimCurve:get(self.fillLevel/self.capacity);
        local tmpAnimCurve = AnimCurve:new(linearInterpolator4);
        tmpAnimCurve:addKeyframe({x=sX, y=sY, z=sZ, w=sTrans, time = 0});
        tmpAnimCurve:addKeyframe({x=tX, y=tY, z=tZ, w=tTrans, time = 1});
        local tim = 0;
        if self.TipTriggerInRange then
         tim=1-(self.timer/4000);
        else
          tim=(self.timer/4000);
        end;
        local scaleX, scaleY, scaleZ , yTrans = tmpAnimCurve:get(tim);
        setScale(grainPlane, scaleX, scaleY, scaleZ);    
        local xPos, yPos, zPos = getTranslation(grainPlane);
        setTranslation(grainPlane, xPos, yTrans, zPos); 

        if self.timer<=0 then
          self.timerRunning = false;
        end;
      end;
    end;

    if (self.tipState == Trailer.TIPSTATE_CLOSED) and (self.fillLevel>0) and (FruitUtil.fillTypeToFruitType[self.currentFillType] ~= FruitUtil.FRUITTYPE_CHAFF) then      
      self.TipTriggerInRange = (TipTriggerInRange(self)~=nil);    
      local fillTypeName = Fillable.fillTypeIntToName[self.currentFillType];
      local grainPlane = self.grainPlanes[fillTypeName];
      local x, y, z = getTranslation(grainPlane);
      local trans = {x,y,z}; 
      local scaleX, scaleY, scaleZ , yTrans = self.grainTipAnimCurve:get(self.fillLevel/self.capacity);
      local sX, sY, sZ , yMax = self.grainAnimCurve:get(self.fillLevel/self.capacity);
      local newtrans = Utils.getMovedLimitedValues(trans,{x,yMax,z}, {x,yTrans,z}, 3, 4000, dt, self.TipTriggerInRange); 
      setTranslation(grainPlane, unpack(newtrans));
      if math.abs(y-newtrans[2])>0.001 then    
        self.posun = true;
      else
        self.posun = false;
      end;
    else
      self.posun = false; 
    end;
  

    if self.tipState == Trailer.TIPSTATE_OPENING or self.tipState == Trailer.TIPSTATE_OPEN or self.posun then
      local o = self.floorAnimSpeed;
      if self.posun then 
        o = o * 2.45;
        if not self.TipTriggerInRange then
          o = o * -1;
        end;
      end;    
      setShaderParameter(self.telo, "UVPlaySpeed", 0, o, 0, 0, false);
    else
      setShaderParameter(self.telo, "UVPlaySpeed", 0, 0, 0, 0, false);
    end;

    -- Reverse lights
    if self.movingDirection < 0 then
      self.reverseLightActive = true;
    else
      self.reverseLightActive = false;
    end;
    setVisibility(self.reverseLightObject, self.reverseLightActive);
  
    -- Brake lights
    local input = 0;
    if self:getIsActiveForInput() then
      input = InputBinding.getAnalogInputAxis(InputBinding.AXIS_MOVE_FORWARD_VEHICLE);
      if InputBinding.isAxisZero(input) then
        input = InputBinding.getDigitalInputAxis(InputBinding.AXIS_MOVE_FORWARD_VEHICLE);
      end;
      local prevBLA = self.brakeLightActive;
      if (self.movingDirection*self.lastSpeed*(-input)) < -0.001 then
        self.brakeLightActive = true;
      else
        self.brakeLightActive = false;
      end;
      if prevBLA~=self.brakeLightActive then
        if g_server ~= nil then
          g_server:broadcastEvent(CargosBrakeLightEvent:new(self, self.brakeLightActive), nil, nil, self);
        else
          g_client:getServerConnection():sendEvent(CargosBrakeLightEvent:new(self, self.brakeLightActive));
        end;
      end;
    end;
  
    setVisibility(self.brakeLightObject, self.brakeLightActive);
  end;
end;

function Cargos:updateSilage(dt)
 -- zatim nic :)
end;

function Cargos:updateForage(dt)
  if self.isClient then
    if self:getIsActiveForInput() then
      if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA) then
        self:setTurned(not self.isTurnedOn);
      end;      
    end;
    if self.pickup ~= nil then
      local x, y, z = getRotation(self.pickup.node);
      local rot = {x,y,z};
      local newRot = Utils.getMovedLimitedValues(rot, self.pickup.maxRot, self.pickup.minRot, 3, self.pickup.rotTime, dt, not self.pickupMax);
      setRotation(self.pickup.node, unpack(newRot));
    end;
	
    if self.drum1 ~= nil and self.isTurnedOn then
      rotate(self.drum1, self.drumRotationScale * 100, 0, 0); 
    end;

    if self.crusher ~= nil and self.isTurnedOn then
      rotate(self.crusher, self.crusherRotationScale * 100, 0, 0); 
    end;
  end;
  self.wasToFast = false;
  if self:getIsActive() then
    if self.isTurnedOn then
      local toFast = self:doCheckSpeedLimit() and self.attacherVehicle.lastSpeed*3600 > 29;
      if self.isServer then
        if not toFast then
				  local cuttingAreasSend = {};
          for k, cuttingArea in pairs(self.cuttingAreas) do
            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);

              table.insert(cuttingAreasSend, {x,z,x1,z1,x2,z2});
            end;
          end;
          if (table.getn(cuttingAreasSend) > 0) then
            local area, fillType = CargosAreaEvent.runLocally(cuttingAreasSend, self.fillTypes, self.currentFruitType);
            if area > 0 then
              self.lastForageWagonArea = area;

              local pixelToSqm = g_currentMission:getFruitPixelsToSqm(); -- 4096px are mapped to 2048m
              local literPerSqm = g_strawLitersPerSqm * 2;
              local sqm = area*pixelToSqm;

              local deltaLevel = sqm*literPerSqm * self.fillScale;
              
              self:setFillLevel(self.fillLevel+deltaLevel, fillType);
              g_server:broadcastEvent(CargosAreaEvent:new(cuttingAreasSend, fillType));
            end;
          end;

				  if self.fillLevel == 0 then
					  self:setFillLevel(0, Fillable.FILLTYPE_UNKNOWN)
				  end;
        end;
      end;
      self.wasToFast = toFast;
			if self.isClient then
        if not self.forageWgnSoundEnabled and self:getIsActiveForSound() then
          playSample(self.forageWgnSound, 0, self.forageWgnSoundVolume, 0);
          setSamplePitch(self.forageWgnSound, self.forageWgnSoundPitchOffset);
          self.forageWgnSoundEnabled = true;
        end;
      end;
      if self.fillLevel == self.capacity then
        self:setTurned(false);
      end;
    end;
    if self.isClient and self.forageWgnSoundEnabled and not self.isTurnedOn then
      stopSample(self.forageWgnSound);
      self.forageWgnSoundEnabled = false;
    end;
  end;
end; 

function Cargos:draw()
  if self.mode == Cargos.FORAGE then
    if self.wasToFast then
        g_currentMission:addWarning(g_i18n:getText("Dont_drive_to_fast") .. "\n" .. string.format(g_i18n:getText("Cruise_control_levelN"), "2", InputBinding.getKeyNamesOfDigitalAction(InputBinding.SPEED_LEVEL2)), 0.07+0.022, 0.019+0.029);
    end;
    if self.isTurnedOn then
        g_currentMission:addHelpButtonText(string.format(g_i18n:getText("turn_off_OBJECT"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA);
    else
        g_currentMission:addHelpButtonText(string.format(g_i18n:getText("turn_on_OBJECT"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA);
        if (self.fillLevel == 0) then 
          g_currentMission:addHelpButtonText(g_i18n:getText("cargos_switch_silage"), InputBinding.IMPLEMENT_EXTRA2);
        end;
    end;
  else
    if (self.fillLevel == 0) then
      g_currentMission:addHelpButtonText(g_i18n:getText("cargos_switch_forage"), InputBinding.IMPLEMENT_EXTRA2);
    end;
  end;
  g_currentMission:addExtraPrintText(InputBinding.getKeyNamesOfDigitalAction(InputBinding.LOWER_CARGOS).."/"..InputBinding.getKeyNamesOfDigitalAction(InputBinding.LIFT_CARGOS)..":            "..g_i18n:getText("cargos_drawbar")); 
end;

function Cargos:onAttach(attacherVehicle)
	self.jointSearch = true;
end;

function Cargos:onDetach()	
	self.vehicleJoint = nil;
end;

function Cargos:setFillLevel(superFunc, fillLevel, fillType, force)
    if not self:allowFillType(fillType, false) then
        return;
    end;
    local oldFillType = self.currentFillType;
    self.currentFillType = fillType;
    self.fillLevel = fillLevel;
    if self.fillLevel > self.capacity then
        self.fillLevel = self.capacity;
    end;
    if self.fillLevel <= 0 then
      self.fillLevel = 0;
      if self.isClient then
        Utils.setEmittingState(self.dischargeParticleSystems[oldFillType], false);
      end;
      -- reset fill type as the trailer is empty
      self.currentFillType = FruitUtil.FRUITTYPE_UNKNOWN;
    end;
    if self.isClient then
      if self.currentGrainPlane ~= nil then
        setVisibility(self.currentGrainPlane, false);
      end;
      if self.grainPlanes ~= nil and self.defaultGrainPlane ~= nil and fillType ~= FruitUtil.FRUITTYPE_UNKNOWN then
        local fillTypeName = FruitUtil.fruitIndexToDesc[FruitUtil.fillTypeToFruitType[fillType]].name;
        local grainPlane = self.grainPlanes[fillTypeName];
        if grainPlane == nil then
            grainPlane = self.defaultGrainPlane;
        end;
        local yTranslation;
        if FruitUtil.fillTypeToFruitType[self.currentFillType] == FruitUtil.FRUITTYPE_CHAFF then
          local fnm = (self.fillNodeMaxZ - self.fillNodeMinZ) / self.capacity;
          local fnX, fnY, fnZ = getTranslation(self.fillNode);
          fnZ = self.fillNodeMinZ + (fnm * self.fillLevel);
          setTranslation(self.fillNode, fnX, fnY, fnZ);       
          if self.tipState == Trailer.TIPSTATE_OPENING or self.tipState == Trailer.TIPSTATE_OPEN or self.tipState == Trailer.TIPSTATE_CLOSING then
            if self.silageTipAnimCurve then
              local scaleX, scaleY, scaleZ , yTrans = self.silageTipAnimCurve:get(self.fillLevel/self.capacity);
              yTranslation = yTrans;
              setScale(grainPlane, scaleX, scaleY, scaleZ);
            else
              local m = (self.grainPlaneMaxY - self.grainPlaneMinY) / self.capacity;
              yTranslation = m*self.fillLevel + self.grainPlaneMinY;
            end;
          else
            if self.silageAnimCurve then
              local scaleX, scaleY, scaleZ , yTrans = self.silageAnimCurve:get(self.fillLevel/self.capacity);
              yTranslation = yTrans;
              setScale(grainPlane, scaleX, scaleY, scaleZ);
            else
              local m = (self.grainPlaneMaxY - self.grainPlaneMinY) / self.capacity;
              yTranslation = m*self.fillLevel + self.grainPlaneMinY;
            end;          
          end;        
        else
          if self.tipState == Trailer.TIPSTATE_OPENING or self.tipState == Trailer.TIPSTATE_OPEN or self.tipState == Trailer.TIPSTATE_CLOSING then
            if self.grainTipAnimCurve then
              local scaleX, scaleY, scaleZ , yTrans = self.grainTipAnimCurve:get(self.fillLevel/self.capacity);
              yTranslation = yTrans;
              setScale(grainPlane, scaleX, scaleY, scaleZ);
            else
              local m = (self.grainPlaneMaxY - self.grainPlaneMinY) / self.capacity;
              yTranslation = m*self.fillLevel + self.grainPlaneMinY;
            end;
          else 
            if self.grainAnimCurve then
              local scaleX, scaleY, scaleZ , yTrans = self.grainAnimCurve:get(self.fillLevel/self.capacity);
              yTranslation = yTrans;
              setScale(grainPlane, scaleX, scaleY, scaleZ);
            else
              local m = (self.grainPlaneMaxY - self.grainPlaneMinY) / self.capacity;
              yTranslation = m*self.fillLevel + self.grainPlaneMinY;
            end;
          end;
        end;
        local xPos, yPos, zPos = getTranslation(grainPlane);
        setTranslation(grainPlane, xPos, yTranslation, zPos);
        setVisibility(grainPlane, self.fillLevel > 0);
        self.currentGrainPlane = grainPlane;
      end;
    end;
end;

function Cargos:onStartTip(currentTipTrigger)
    self.currentTipTrigger = currentTipTrigger;
    if self.tipAnimCharSet ~= 0 then
        if getAnimTrackTime(self.tipAnimCharSet, 0) < 0.0 then
            setAnimTrackTime(self.tipAnimCharSet, 0, 0.0);
        end;
        setAnimTrackSpeedScale(self.tipAnimCharSet, 0, self.tipAnimSpeedScale);
        enableAnimTrack(self.tipAnimCharSet, 0);
    end;
    if not self.forageWgnSoundEnabled and self:getIsActiveForSound() then
      playSample(self.forageWgnSound, 0, self.forageWgnSoundVolume, 0);
      setSamplePitch(self.forageWgnSound, self.forageWgnSoundPitchOffset);
      self.forageWgnSoundEnabled = true;
    end;
    self.tipState = Trailer.TIPSTATE_OPENING;
    g_currentMission.allowSteerableMoving = false;
    g_currentMission.fixedCamera = false;
end;

function Cargos:onEndTip()
    self.currentTipTrigger = nil;
    if self.tipAnimCharSet ~= 0 then
        if getAnimTrackTime(self.tipAnimCharSet, 0) > self.tipAnimDuration then
            setAnimTrackTime(self.tipAnimCharSet, 0, self.tipAnimDuration);
        end;
        setAnimTrackSpeedScale(self.tipAnimCharSet, 0, -self.tipAnimSpeedScale);
        enableAnimTrack(self.tipAnimCharSet, 0);
    end;
    if self.forageWgnSoundEnabled then
        stopSample(self.forageWgnSound);
        self.forageWgnSoundEnabled = false;
    end;    
    self.tipState = Trailer.TIPSTATE_CLOSING;
end;

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

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

function Cargos:onDeactivate()
  self:setTurned(false);
  Cargos.onDeactivateSounds(self);
end;

function Cargos:onDeactivateSounds()
    if self.forageWgnSoundEnabled then
        stopSample(self.forageWgnSound);
        self.forageWgnSoundEnabled = false;
    end;
    if self.hydraulicSoundEnabled then
        stopSample(self.hydraulicSound);
        self.hydraulicSoundEnabled = false;   
    end;    
end;

function TipTriggerInRange(self)	
  local nearestObject
	local itemNode
	local index 
	local nearestDistance = 5;
	local objectCopy = self.tipReferencePoint;	
	local px, py, pz = getWorldTranslation(objectCopy);
	for i,v in pairs(g_currentMission.tipTriggers) do
	  itemNode = i.triggerId;
 	  local vx, vy, vz = getWorldTranslation(itemNode);
  	local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
    if distance < nearestDistance then
 	  	nearestObject = itemNode
  	  nearestDistance = distance
		end;		
	end;
  return nearestObject;
end;
