--
-- Lexion580Cutter
-- This is the specialization for cutters
-- It reacts both to steerable and attachable events
--
-- @author  Stefan Geiger
-- @date  04/12/08
--
-- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.

Lexion580Cutter = {};

function Lexion580Cutter.prerequisitesPresent(specializations)
    return true;
end;

function Lexion580Cutter:load(xmlFile)

    self.setReelSpeed = SpecializationUtil.callSpecializationsFunction("setReelSpeed");
    self.onStartReel = SpecializationUtil.callSpecializationsFunction("onStartReel");
    self.onStopReel = SpecializationUtil.callSpecializationsFunction("onStopReel");
    self.isReelStarted = Lexion580Cutter.isReelStarted;
    self.resetFruitType = SpecializationUtil.callSpecializationsFunction("resetFruitType");
    self.setFruitType = SpecializationUtil.callSpecializationsFunction("setFruitType");

    self.reelNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.reel#index"));
    self.rollNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.roll#index"));
	self.rollNodeLeft = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.rollLeft#index"));
	self.rollNodeRight = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.rollRight#index"));

    local indexSpikesStr = getXMLString(xmlFile, "vehicle.reelspikes#index");
    self.spikesCount = getXMLInt(xmlFile, "vehicle.reelspikes#count");
    self.spikesRootNode = Utils.indexToObject(self.components, indexSpikesStr);

	self.sidearms = {};
    self.sidearms.rot = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.sidearms#rot"));
	self.sidearms.trans = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.sidearms#trans"));
    self.sidearms.movable = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.sidearms#movable"), false);

    self.threshingParticleSystems = {};
    local psName = "vehicle.threshingParticleSystem";
    Utils.loadParticleSystem(xmlFile, self.threshingParticleSystems, psName, self.components, false, nil, self.baseDirectory)
	
    local rotationPartNodeLeft = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.rotationPartLeft#index"));
    if rotationPartNodeLeft ~= nil then
        self.rotationPartLeft = {};
        self.rotationPartLeft.node = rotationPartNodeLeft;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.rotationPartLeft#minRot"));
        self.rotationPartLeft.minRot = {};
        self.rotationPartLeft.minRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.rotationPartLeft.minRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.rotationPartLeft.minRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));
        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.rotationPartLeft#maxRot"));
        self.rotationPartLeft.maxRot = {};
        self.rotationPartLeft.maxRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.rotationPartLeft.maxRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.rotationPartLeft.maxRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));
        self.rotationPartLeft.rotTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.rotationPartLeft#rotTime"), 2)*1000;
        self.rotationPartLeft.touchRotLimit = Utils.degToRad(Utils.getNoNil(getXMLString(xmlFile, "vehicle.rotationPartLeft#touchRotLimit"), 10));
    end;

    self.fruitExtraObjects = {};
    local i = 0;
    while true do
        local key = string.format("vehicle.fruitExtraObjects.fruitExtraObject(%d)", i);
        local t = getXMLString(xmlFile, key.."#fruitType");
        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
            if self.currentExtraObject == nil then
                self.currentExtraObject = node;
                setVisibility(node, true);
            else
                setVisibility(node, false);
            end;
            self.fruitExtraObjects[t] = node;
        end;
        i = i +1;
    end;
	self.rapeTable = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.rapeTable#index"));

    self.preferedCombineSize = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.preferedCombineSize"), 1);

    self.fruitTypes = {};
    self.fruitTypes[FruitUtil.FRUITTYPE_UNKNOWN] = true;
    local fruitTypes = getXMLString(xmlFile, "vehicle.fruitTypes#fruitTypes");
    if fruitTypes ~= nil then
        local types = Utils.splitString(" ", fruitTypes);
        for k,v in pairs(types) do
            local desc = FruitUtil.fruitTypes[v];
            if desc ~= nil then
                self.fruitTypes[desc.index] = true;
            end;
        end;
    end;
	
	self.controlpath = Utils.getFilename("textures/580Cutter/V900HUD.png", self.baseDirectory);
    self.hudV900Width = 0.16;
    self.hudV900Height = 0.9775;
	self.hudV900PoxX = 0.8325;
    self.hudV900PoxY = 0.01;
    self.hudV900Overlay = Overlay:new("hudV900Control", self.controlpath, self.hudV900PoxX, self.hudV900PoxY, self.hudV900Width, self.hudV900Height);
	
	self.hydraulic = {};
	self.hydraulic.node = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.zylinder#rotIndex"));
	self.hydraulic.punch = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.zylinder#transIndex"));
	self.hydraulic.translationPunch = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.zylinder#translationPunch"));
	self.hydraulic.rotationPunch = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.zylinder#rotationPunch"));
	if self.hydraulic.punch and self.hydraulic.translationPunch ~= nil then
		local ax, ay, az = getWorldTranslation(self.hydraulic.punch);
		local bx, by, bz = getWorldTranslation(self.hydraulic.translationPunch);
		self.hydraulic.punchDistance = Utils.vector3Length(ax-bx, ay-by, az-bz);
	end;
	
	self.earLifter = {};
	self.earLifter.left = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.earLifter#left"));
	self.earLifter.right = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.earLifter#right"));
	
	self.pto = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.pto#index"));
	
    self.currentFruitType = FruitUtil.FRUITTYPE_UNKNOWN;
    self.reelStarted = false;
    self.forceLowSpeed = false;
    self.speedLimitLow = 20.2;
    self.speedLimit = 20.2; --old 17.5
    self.speedViolationMaxTime = 50;
    self.speedViolationTimer = self.speedViolationMaxTime;
    self.printRainWarning = false;
    self.lastArea = 0;
	self.percentArea = 0;

end;

function Lexion580Cutter:delete()
    Utils.deleteParticleSystem(self.threshingParticleSystems);
end;

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

function Lexion580Cutter:keyEvent(unicode, sym, modifier, isDown)

	if sym == Input.KEY_KP_1 then
		self.rotationMaxLeft = isDown;
	end;
	if sym == Input.KEY_KP_3 then
		self.rotationMinLeft = isDown;
	end;

    if isDown and sym == Input.KEY_KP_5 then
		self.helpPanel = not self.helpPanel;
	end;

end;

function Lexion580Cutter:update(dt)

	if self.attacherVehicle ~= nil then
		setRotation(self.pto, 0, 0, 0-0.05);
		setRotation(self.earLifter.right, 0, 0, 0);
		setRotation(self.earLifter.left, 0, 0, 0);
	end;
	
    self.lastArea = 0;
	self.percentArea = 0;
    if self.reelStarted and self.movingDirection < 0 then
        local speedLimit = self.speedLimit;
        if Lexion580Cutter.getUseLowSpeedLimit(self) then
            speedLimit = self.speedLimitLow;
        end;
        if self:doCheckSpeedLimit() and self.lastSpeed*3600 > speedLimit then
            self.speedViolationTimer = self.speedViolationTimer - dt;
        else
            self.speedViolationTimer = self.speedViolationMaxTime;
        end;

        if self.speedViolationTimer > 0 then
            if Lexion580Cutter.allowThreshing(false) then
                self.printRainWarning = false;

                -- during low fill level new fruit types are allowed to "take over"
                local lowFillLevel = false;
                if self.attacherVehicle ~= nil then
                    if self.attacherVehicle.grainTankFillLevel > 0 and self.attacherVehicle.grainTankFillLevel / self.attacherVehicle.grainTankCapacity <= self.attacherVehicle.minThreshold then
                        lowFillLevel = true;
                    end;
                end;

                local foundFruitType = false;
                local oldFruitType = self.currentFruitType;
                
                local allowsThreshing = true;
                if self.attacherVehicle ~= nil then
                    allowsThreshing = self.attacherVehicle.allowsThreshing;
                end;

                if allowsThreshing and self:isLowered(false) then
                    if self.currentFruitType == FruitUtil.FRUITTYPE_UNKNOWN or lowFillLevel then
                        for fruitType,v in pairs(self.fruitTypes) do
                            local isOk = true;
                            if self.attacherVehicle ~= nil then
                                if self.attacherVehicle.allowGrainTankFruitType ~= nil then
                                    isOk = self.attacherVehicle:allowGrainTankFruitType(fruitType);
                                end;
                            end;
                            if isOk then
                                for k,area in pairs(self.cuttingAreas) do
                                    local x,y,z = getWorldTranslation(area.start);
                                    local x1,y1,z1 = getWorldTranslation(area.width);
                                    local x2,y2,z2 = getWorldTranslation(area.height);
                                    local area = Utils.getFruitArea(fruitType, x, z, x1, z1, x2, z2);
                                    if area > 0 then
                                        self.currentFruitType = fruitType;
                                        if self.currentFruitType ~= oldFruitType then
                                            Lexion580Cutter.updateExtraObjects(self)
                                            if self.attacherVehicle ~= nil then
                                                self.attacherVehicle:emptyGrainTankIfLowFillLevel();
                                            end;
                                        end;
                                        foundFruitType = true;
                                        break;
                                    end;
                                end;

                                if foundFruitType then
                                    break;
                                end;
                            end;
                        end;
                    end;
                    if self.currentFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then
                        local realArea = 0;
                        for k,area in pairs(self.cuttingAreas) do
                            local x,y,z = getWorldTranslation(area.start);
                            local x1,y1,z1 = getWorldTranslation(area.width);
                            local x2,y2,z2 = getWorldTranslation(area.height);
                            Utils.updateFruitCutShortArea(self.currentFruitType, x, z, x1, z1, x2, z2, 1);
                            local area = Utils.cutFruitArea(self.currentFruitType, x, z, x1, z1, x2, z2);
                            if area > 0 then
                                local spray = Utils.getDensity(g_currentMission.terrainDetailId, g_currentMission.sprayChannel, x, z, x1, z1, x2, z2);
                                local multi = 1;
                                if spray > 0 then
                                    multi = 2;
                                end;
                                self.lastArea = self.lastArea + area*multi;
                                realArea = realArea + area/g_currentMission.maxFruitValue;
								self.percentArea = realArea;
                            end;
                        end;
                        local pixelToQm = 2048 / 4096 * 2048 / 4096; -- 4096px are mapped to 2048m
                        local qm = realArea*pixelToQm;
                        local ha = qm/10000;

                        g_currentMission.missionStats.hectaresThreshedTotal = g_currentMission.missionStats.hectaresThreshedTotal + ha;
                        g_currentMission.missionStats.hectaresThreshedSession = g_currentMission.missionStats.hectaresThreshedSession + ha;

                        g_currentMission.missionStats.threshingDurationTotal = g_currentMission.missionStats.threshingDurationTotal + dt/(1000*60);
                        g_currentMission.missionStats.threshingDurationSession= g_currentMission.missionStats.threshingDurationSession + dt/(1000*60);
                    end;
                end;
            else
				if not self.isAIThreshing then
					self.printRainWarning = true;
				end;
            end;
        end;
    else
        self.speedViolationTimer = self.speedViolationMaxTime;
    end;
	
    Utils.setEmittingState(self.threshingParticleSystems, (self.reelStarted and self.lastArea > 0.0));
	
		if self.rotationPartLeft ~= nil and (self.rotationMaxLeft or self.rotationMinLeft) then
			local x, y, z = getRotation(self.rotationPartLeft.node);
			local rot = {x,y,z};
			local newRot = Utils.getMovedLimitedValues(rot, self.rotationPartLeft.maxRot, self.rotationPartLeft.minRot, 3, self.rotationPartLeft.rotTime, dt, not self.rotationMaxLeft);
			setRotation(self.rotationPartLeft.node, unpack(newRot));
		end;	

    if self.reelStarted then

        rotate(self.rollNode, -dt*self.reelSpeed*10, 0, 0);
		if self.rollNodeLeft and self.rollNodeRight ~= nil then
			rotate(self.rollNodeLeft, -dt*self.reelSpeed*10, 0, 0);
			rotate(self.rollNodeRight, -dt*self.reelSpeed*10, 0, 0);
		end;

        if self.reelNode ~= nil then
            rotate(self.reelNode, -dt*self.reelSpeed*0.6, 0, 0);

            --correct spikes, so that they always look down
            atx, aty, atz = getRotation(self.reelNode);

            for i=1, self.spikesCount do
                local spike    =    getChildAt(self.spikesRootNode, i-1);
                tx, ty, tz = getRotation(spike);
                setRotation(spike, -atx, aty, atz);
            end;
        end;
    end;
		
	if self.hydraulic.node and self.hydraulic.rotationPunch and self.hydraulic.punch ~= nil then
		local ax, ay, az = getWorldTranslation(self.hydraulic.node);
		local bx, by, bz = getWorldTranslation(self.hydraulic.rotationPunch);
		local x, y, z = worldDirectionToLocal(getParent(self.hydraulic.node), bx-ax, by-ay, bz-az);
		setDirection(self.hydraulic.node, x, y, z, 0, 0, 1);
		if self.hydraulic.punch ~= nil then
			local distance = Utils.vector3Length(ax-bx, ay-by, az-bz);
			setTranslation(self.hydraulic.punch, 0, 0, (distance-self.hydraulic.punchDistance));
		end;
	end;
	
	if self.rapeTable ~= nil then
		local xTrans, yTrans, zTrans = getTranslation(self.rapeTable);
		local moveSpeed = 0.0025;
		if self.currentFruitType == FruitUtil.FRUITTYPE_RAPE then
			if zTrans >= -1.0 then
				zTrans = zTrans - moveSpeed;
			else
				zTrans = zTrans;
			end;
		else
			if zTrans <= -0.5 then
				zTrans = zTrans + moveSpeed;
			else
				zTrans = zTrans;
			end;
		end;
		setTranslation(self.rapeTable, xTrans, yTrans, zTrans);
	end;
	
	if self.attacherVehicle ~= nil then
		if self.attacherVehicle.isEntered then
			if self.sidearms.movable then
				local xRotHaspel, yRotHaspel, zRotHaspel = getRotation(self.sidearms.rot);
				local xTransHaspel, yTransHaspel, zTransHaspel = getTranslation(self.sidearms.trans);
				local move = 0.0065;

				if InputBinding.isPressed(InputBinding.HASPEL_UP) then
					if xRotHaspel <= Utils.degToRad(12) then
						xRotHaspel = xRotHaspel + move;
					else
						xRotHaspel = xRotHaspel;
					end;
				end;
				if InputBinding.isPressed(InputBinding.HASPEL_DOWN) then
					if xRotHaspel >= Utils.degToRad(-20) then
						xRotHaspel = xRotHaspel - move;
					else
						xRotHaspel = xRotHaspel;
					end;
				end;
				if InputBinding.isPressed(InputBinding.HASPEL_BACK) then
					if zTransHaspel <= -1.2 then
						zTransHaspel = zTransHaspel + move;
					else
						zTransHaspel = zTransHaspel;
					end;
				end;
				if InputBinding.isPressed(InputBinding.HASPEL_FORWARD) then
					if zTransHaspel >= -1.65 then
						zTransHaspel = zTransHaspel - move;
					else
						zTransHaspel = zTransHaspel;
					end;
				end;
				setRotation(self.sidearms.rot, xRotHaspel, yRotHaspel, zRotHaspel);
				setTranslation(self.sidearms.trans, xTransHaspel, yTransHaspel, zTransHaspel);
				end;
		end;
	end;
	
end;

function Lexion580Cutter:draw()

		if self.attacherVehicle ~= nil then
			if not self.helpPanel then
				renderText(0.845, 0.40, 0.018, "NUM: 5: Cutterinfo Ein");
			else
			end;		
			if self.helpPanel then
				renderText(0.845, 0.46, 0.018, g_i18n:getText("Lexion580Cutter-1"));
				renderText(0.845, 0.445, 0.018, g_i18n:getText("Lexion580Cutter-2"));
				renderText(0.845, 0.43, 0.017, g_i18n:getText("Lexion580Cutter-3"));
				if self.hudV900Overlay ~= nil then
					self.hudV900Overlay:render();
				end;
			end;	
		end;
		
    if math.abs(self.speedViolationTimer - self.speedViolationMaxTime) > 2 then
        local str = "2";
        local keyStr = InputBinding.getButtonKeyName(InputBinding.SPEED_LEVEL2)
        if Cutter.getUseLowSpeedLimit(self) then
            str = "1";
            keyStr = InputBinding.getButtonKeyName(InputBinding.SPEED_LEVEL1)
        end;
        g_currentMission:addWarning(g_i18n:getText("Dont_drive_to_fast") .. "\n" .. string.format(g_i18n:getText("Cruise_control_levelN"), str, keyStr), 0.07+0.022, 0.019+0.029);
    end;

    if self.printRainWarning then
        g_currentMission:addWarning(g_i18n:getText("Dont_do_threshing_during_rain_or_hail"), 0.018, 0.033);
    end;		

--[[    if math.abs(self.speedViolationTimer - self.speedViolationMaxTime) > 2 then
		if self.attacherVehicle.percentMaschine > 90 then
			g_currentMission:addWarning(g_i18n:getText("Dont_drive_to_fast") .. "\n" .. string.format(g_i18n:getText("warning3")), 0.07+0.022, 0.019+0.029);
		end;
		if self.attacherVehicle.percentMaschine < 90 then
			g_currentMission:addWarning(g_i18n:getText("Dont_drive_to_fast") .. "\n" .. string.format(g_i18n:getText("warning4")), 0.07+0.022, 0.019+0.029);
		end;	
	end;
		
    if self.printRainWarning then
        g_currentMission:addWarning(g_i18n:getText("Dont_do_threshing_during_rain_or_hail"), 0.018, 0.033);
    end;]]

end;

function Lexion580Cutter:onDetach()

    if self.deactivateOnDetach then
        Lexion580Cutter.onDeactivate(self);
    end;
	local y = 8.2*3.1456/180.0;
	local z = 19*3.1456/180.0;
	setRotation(self.pto, 0, y, z);
	
	local yMaxLeft = 80;
	local yMaxRight = -80;
	setRotation(self.earLifter.right, 0, yMaxRight, 0);
	setRotation(self.earLifter.left, 0, yMaxLeft, 0);
	
end;

function Lexion580Cutter:onLeave()
    if self.deactivateOnLeave then
        Lexion580Cutter.onDeactivate(self);
    end;
end;

function Lexion580Cutter:onDeactivate()
    self:onStopReel();
    Utils.setEmittingState(self.threshingParticleSystems, false);
    self.speedViolationTimer = self.speedViolationMaxTime;
end;

function Lexion580Cutter:setReelSpeed(speed)
    self.reelSpeed = speed;
end;

function Lexion580Cutter:onStartReel()
    self.reelStarted = true;
end;

function Lexion580Cutter:onStopReel()
    self.reelStarted = false;
    Utils.setEmittingState(self.threshingParticleSystems, false);
    self.speedViolationTimer = self.speedViolationMaxTime;
end;

function Lexion580Cutter:isReelStarted()
    return self.reelStarted;
end;

function Lexion580Cutter:resetFruitType()
    self.currentFruitType = FruitUtil.FRUITTYPE_UNKNOWN;
    self.lastArea = 0;
end;

function Lexion580Cutter:setFruitType(fruitType)
    if self.currentFruitType ~= fruitType then
        self.currentFruitType = fruitType;
        self.lastArea = 0;

        Lexion580Cutter.updateExtraObjects(self)
    end;
end;

function Lexion580Cutter.getUseLowSpeedLimit(self)
    if self.forceLowSpeed or (self.attacherVehicle ~= nil and self.preferedCombineSize > self.attacherVehicle.combineSize) then
        return true;
    end;
    return false;
end;

function Lexion580Cutter.updateExtraObjects(self)
    if self.currentExtraObject ~= nil then
        setVisibility(self.currentExtraObject, false);
        self.currentExtraObject = nil;
    end;
    if self.currentFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then
        local name = FruitUtil.fruitIndexToDesc[self.currentFruitType].name;
        local extraObject = self.fruitExtraObjects[name];
        if extraObject ~= nil then
            setVisibility(extraObject, true);
            self.currentExtraObject = extraObject;
        end;
    end;
end;

function Lexion580Cutter.allowThreshing(earlyWarning)
    if early ~= nil and early == true then
        if g_currentMission.environment.lastRainScale <= 0.02 and g_currentMission.environment.timeSinceLastRain > 20 then
            return true;
        end;
    else
        if g_currentMission.environment.lastRainScale <= 0.1 and g_currentMission.environment.timeSinceLastRain > 20 then
            return true;
        end;
    end;
    return false;
end;
