--
-- Lexion600Cutter
-- 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.

Lexion600Cutter = {};

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

function Lexion600Cutter:load(xmlFile)

	self.setReelSpeed = SpecializationUtil.callSpecializationsFunction("setReelSpeed");
	self.onStartReel = SpecializationUtil.callSpecializationsFunction("onStartReel");
	self.onStopReel = SpecializationUtil.callSpecializationsFunction("onStopReel");
	self.isReelStarted = Lexion600Cutter.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)

	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.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 Lexion600Cutter:delete()
	Utils.deleteParticleSystem(self.threshingParticleSystems);
end;

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

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

function Lexion600Cutter: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 Lexion600Cutter.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 Lexion600Cutter.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
											Lexion600Cutter.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
				self.printRainWarning = true;
			end;
		end;
	else
		self.speedViolationTimer = self.speedViolationMaxTime;
	end;
	
	Utils.setEmittingState(self.threshingParticleSystems, (self.reelStarted and self.lastArea > 0.0));

	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 Lexion600Cutter:draw()

	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 Lexion600Cutter:onDetach()

	if self.deactivateOnDetach then
		Lexion600Cutter.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 Lexion600Cutter:onLeave()
	if self.deactivateOnLeave then
		Lexion600Cutter.onDeactivate(self);
	end;
end;

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

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

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

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

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

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

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

		Lexion600Cutter.updateExtraObjects(self)
	end;
end;

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

function Lexion600Cutter.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 Lexion600Cutter.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;
