--
-- FruitParticleSystem
-- Specialization for FruitParticleSystem
--
-- @author  	Manuel Leithner (SFM-Modding)
-- @version 	v1.0
-- @date  		02/09/11
-- @history:	v1.0 - Initial version
--
-- free for noncommerical-usage
--

FruitParticleSystem = {};

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

function FruitParticleSystem:load(xmlFile)
	
	self.canPlaceParticle = FruitParticleSystem.canPlaceParticle;
	self.getIsPSActive = FruitParticleSystem.getIsPSActive;
	self.resetFruitParticleSystem = FruitParticleSystem.resetFruitParticleSystem;
	
	self.fruitParticle = {};
	self.fruitParticle.leftFreePart = {};
	self.fruitParticle.rightFreePart = {};
	
	self.fruitParticle.cloneFactor = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.fruitParticleSystem.fruits#cloneFactor"), 5);
	i = 0;
	while true do		
		local key = string.format("vehicle.fruitParticleSystem.fruits.fruit(%d)", i);
		if not hasXMLProperty(xmlFile, key) then
			break;
		end;
		local fruitType = getXMLString(xmlFile, key .. "#type");
		self.fruitParticle.leftFreePart[fruitType] = {};
		self.fruitParticle.rightFreePart[fruitType] = {};
		
		local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#node"));
		local rightNode = clone(node, true);
		setVisibility(rightNode, false);
		setVisibility(node, false);
		table.insert(self.fruitParticle.leftFreePart[fruitType], node);
		table.insert(self.fruitParticle.rightFreePart[fruitType], rightNode);
		
		for j=1, self.fruitParticle.cloneFactor*2 do
			local fruitLeftClone = clone(node, true);
			local fruitRightClone = clone(node, true);
			setVisibility(fruitLeftClone, false);
			setVisibility(fruitRightClone, false);
			table.insert(self.fruitParticle.leftFreePart[fruitType], fruitLeftClone);
			table.insert(self.fruitParticle.rightFreePart[fruitType], fruitRightClone);
		end;			
		i = i + 1;
	end;
	
	local leftAreas = {};
	i = 0;
	while true do
		local key = string.format("vehicle.fruitParticleSystem.left.area(%d)", i);
		if not hasXMLProperty(xmlFile, key) then
			break;
		end;		
		local area = {};
		area.start = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#start"));
		area.width = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#width"));
		area.height = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#height"));
		table.insert(leftAreas, area);
		i = i + 1;
	end;
	self.fruitParticle.leftAreas = leftAreas;
	
	
	local rightAreas = {};
	i = 0;
	while true do
		local key = string.format("vehicle.fruitParticleSystem.right.area(%d)", i);
		if not hasXMLProperty(xmlFile, key) then
			break;
		end;		
		local area = {};
		area.start = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#start"));
		area.width = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#width"));
		area.height = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#height"));
		table.insert(rightAreas, area);
		i = i + 1;
	end;
	self.fruitParticle.rightAreas = rightAreas;
	
	local leftAnimation = AnimCurve:new(linearInterpolatorTransRotScale);
	i = 0;
	while true do 
		local key = string.format("vehicle.fruitParticleSystem.animations.left.key(%d)", i);
		local t = getXMLFloat(xmlFile, key.."#time");
		local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#translation"));
		if x == nil or y == nil or z == nil then
			break;
		end;
		local rx, ry, rz = Utils.getVectorFromString(getXMLString(xmlFile, key.."#rotation"));
		rx = math.rad(Utils.getNoNil(rx, 0));
		ry = math.rad(Utils.getNoNil(ry, 0));
		rz = math.rad(Utils.getNoNil(rz, 0));
		local sx, sy, sz= Utils.getVectorFromString(getXMLString(xmlFile, key.."#scale"));
		sx = Utils.getNoNil(sx, 1);
		sy = Utils.getNoNil(sy, 1);
		sz = Utils.getNoNil(sz, 1);
		leftAnimation:addKeyframe({x=x, y=y, z=z, rx=rx, ry=ry, rz=rz, sx=sx, sy=sy, sz=sz, time = t});
		i = i +1;
	end;
	self.fruitParticle.leftAnimation = leftAnimation;
	
	local rightAnimation = AnimCurve:new(linearInterpolatorTransRotScale);
	i = 0;
	while true do 
		local key = string.format("vehicle.fruitParticleSystem.animations.right.key(%d)", i);
		local t = getXMLFloat(xmlFile, key.."#time");
		local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#translation"));
		if x == nil or y == nil or z == nil then
			break;
		end;
		local rx, ry, rz = Utils.getVectorFromString(getXMLString(xmlFile, key.."#rotation"));
		rx = math.rad(Utils.getNoNil(rx, 0));
		ry = math.rad(Utils.getNoNil(ry, 0));
		rz = math.rad(Utils.getNoNil(rz, 0));
		local sx, sy, sz= Utils.getVectorFromString(getXMLString(xmlFile, key.."#scale"));
		sx = Utils.getNoNil(sx, 1);
		sy = Utils.getNoNil(sy, 1);
		sz = Utils.getNoNil(sz, 1);
		rightAnimation:addKeyframe({x=x, y=y, z=z, rx=rx, ry=ry, rz=rz, sx=sx, sy=sy, sz=sz, time = t});
		i = i +1;
	end;
	self.fruitParticle.rightAnimation = rightAnimation;	
	self.fruitParticle.speed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fruitParticleSystem.animations#speed"), 11);
	self.fruitParticle.animTime = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fruitParticleSystem.animations#time"), 3) * 1000;
	local fruitTime = getXMLFloat(xmlFile, "vehicle.fruitParticleSystem.fruits#fruitOffset");
	if fruitTime ~= nil then
		self.fruitParticle.partCount = fruitTime*1000;
	end;	
	
	self.fruitParticle.leftPartInAnim = {};
	self.fruitParticle.rightPartInAnim = {};
	
	self.lastActiveFruitType = FruitUtil.FRUITTYPE_UNKNOWN;
	self.isFruitReset = false;
	
	local mapObj = g_currentMission.fruits[FruitUtil.FRUITTYPE_WHEAT];
	self.wheatViewDistance = getFoliageViewDistance(mapObj.id);
	
	self.onStopDoReset = false;
end;

function FruitParticleSystem:delete()
end;

function FruitParticleSystem:readStream(streamId, connection)
end;

function FruitParticleSystem:writeStream(streamId, connection)
end;

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

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

function FruitParticleSystem:update(dt)
end;

function FruitParticleSystem:updateTick(dt)	
	
	if self.rollNodes[1].speed ~= 0 then
		-- play particle animation		
		local animTime = self.fruitParticle.animTime;
		for k, particle in pairs(self.fruitParticle.leftPartInAnim) do
			if particle.time > animTime then
				table.remove(self.fruitParticle.leftPartInAnim, k);
				table.insert(self.fruitParticle.leftFreePart[particle.type], particle.node);
				setVisibility(particle.node, false);
			else
				particle.time = particle.time + dt * math.max(0.85, math.min((self.lastSpeed*3600) / self.fruitParticle.speed, 1.5));
				local x,y,z, rx,ry,rz, sx,sy,sz = self.fruitParticle.leftAnimation:get(particle.time / animTime);
				setTranslation(particle.node, x,y,z);
				setRotation(particle.node, rx,ry,rz);
				setScale(particle.node, sx,sy,sz);
			end;
		end;
		for k, particle in pairs(self.fruitParticle.rightPartInAnim) do
			if particle.time > animTime then
				table.remove(self.fruitParticle.rightPartInAnim, k);
				table.insert(self.fruitParticle.rightFreePart[particle.type], particle.node);
				setVisibility(particle.node, false);
			else
				particle.time = particle.time + dt * math.max(0.85, math.min((self.lastSpeed*3600) / self.fruitParticle.speed, 1.5));
				local x,y,z, rx,ry,rz, sx,sy,sz = self.fruitParticle.rightAnimation:get(particle.time / animTime);
				setTranslation(particle.node, x,y,z);
				setRotation(particle.node, rx,ry,rz);
				setScale(particle.node, sx,sy,sz);
			end;
		end;
		self.onStopDoReset = true;
	else
		if self.onStopDoReset then
			self:resetFruitParticleSystem();
			self.onStopDoReset = false;
		end;
	end;

	if self:getIsActive() then			
		local camera = getCamera();
		local distance = 0;
		if camera ~= 0 then
			local x,y,z = getWorldTranslation(camera);
			local x1,y1,z1 = getWorldTranslation(self.rootNode);
			distance = Utils.vector3Length(x-x1,y-y1,z-z1);
		end;
		
		local allowsThreshing = true;
		if self.attacherVehicle ~= nil then
			allowsThreshing = self.attacherVehicle.allowsThreshing and self.attacherVehicle:getIsThreshingAllowed(false);
		end;		
		
		
		if self.reelStarted and self:getIsPSActive() and self.lastSpeed*3600 > 0.5 and self.speedViolationTimer > 0 and allowsThreshing and distance < self.wheatViewDistance then
			if self.attacherVehicle ~= nil and self.attacherVehicle.allowsThreshing then
				if self.attacherVehicle.lastValidGrainTankFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then
					self.lastActiveFruitType = self.attacherVehicle.lastValidGrainTankFruitType;
				end;
				
				for k, area in pairs(self.fruitParticle.leftAreas) do
					local x,_,z = getWorldTranslation(area.start);
					local x1,_,z1 = getWorldTranslation(area.width);
					local x2,_,z2 = getWorldTranslation(area.height);  		
					local fruitValue = Utils.getFruitArea(self.lastActiveFruitType, x, z, x1, z1, x2, z2);
					if fruitValue > 0 then
						local fruitTypeName = FruitUtil.fruitIndexToDesc[self.lastActiveFruitType].name;
						if table.getn(self.fruitParticle.leftFreePart[fruitTypeName]) > 0 then
							local startTime = self.fruitParticle.animTime * ((table.getn(self.fruitParticle.leftAreas) - k) / table.getn(self.fruitParticle.leftAreas));
							if self:canPlaceParticle(self.fruitParticle.leftPartInAnim, startTime) then
								local newParticle = {};
								newParticle.time = startTime;
								newParticle.node = self.fruitParticle.leftFreePart[fruitTypeName][1];	
								newParticle.type = fruitTypeName;						
								table.remove(self.fruitParticle.leftFreePart[fruitTypeName], 1);
								-- randomize particle rotation
								setRotation(getChildAt(newParticle.node, 0), math.rad(math.random(-10, 10)), math.rad(math.random(0, 45)), math.rad(math.random(-10, 10)));
								-- set correct particle position
								local x,y,z, rx,ry,rz, sx,sy,sz = self.fruitParticle.leftAnimation:get(newParticle.time / self.fruitParticle.animTime);
								setTranslation(newParticle.node, x,y,z);
								setRotation(newParticle.node, rx,ry,rz);
								setScale(newParticle.node, sx,sy,sz);
								setVisibility(newParticle.node, true);				
								table.insert(self.fruitParticle.leftPartInAnim, newParticle);
							end;
						else
							break;
						end;
					end;
				end;
				
				for k, area in pairs(self.fruitParticle.rightAreas) do
					local x,y,z = getWorldTranslation(area.start);
					local x1,y1,z1 = getWorldTranslation(area.width);
					local x2,y2,z2 = getWorldTranslation(area.height);  		
					local fruitValue = Utils.getFruitArea(self.lastActiveFruitType, x, z, x1, z1, x2, z2);
					
					if fruitValue > 0 then
						local fruitTypeName = FruitUtil.fruitIndexToDesc[self.lastActiveFruitType].name;
						if table.getn(self.fruitParticle.rightFreePart[fruitTypeName]) > 0 then
							local startTime = self.fruitParticle.animTime * ((table.getn(self.fruitParticle.rightAreas) - k) / table.getn(self.fruitParticle.rightAreas));
							if self:canPlaceParticle(self.fruitParticle.rightPartInAnim, startTime) then
								local newParticle = {};
								newParticle.time = startTime;
								newParticle.node = self.fruitParticle.rightFreePart[fruitTypeName][1];	
								newParticle.type = fruitTypeName;
								table.remove(self.fruitParticle.rightFreePart[fruitTypeName], 1);
								-- randomize particle rotation
								setRotation(getChildAt(newParticle.node, 0), math.rad(math.random(-10, 10)), math.rad(math.random(0, 45)), math.rad(math.random(-10, 10)));
								-- set correct particle position
								local x,y,z, rx,ry,rz, sx,sy,sz = self.fruitParticle.rightAnimation:get(newParticle.time / self.fruitParticle.animTime);
								setTranslation(newParticle.node, x,y,z);
								setRotation(newParticle.node, rx,ry,rz);
								setScale(newParticle.node, sx,sy,sz);
								setVisibility(newParticle.node, true);				
								table.insert(self.fruitParticle.rightPartInAnim, newParticle);
							end;
						else
							break;
						end;
					end;
				end;
			end;
		end;
	end;
end;

function FruitParticleSystem:draw()	
end;

function FruitParticleSystem:resetFruitType()
	self.isFruitReset = true;
end;

function FruitParticleSystem:getIsPSActive()
	local isActive = self.lastCutterAreaBiggerZero or self.isFruitReset;
	self.isFruitReset = false;	
	return isActive;
end;

function FruitParticleSystem:canPlaceParticle(animatedParticle, time)	
	local percent = math.max(0.85, math.min((self.lastSpeed*3600) / self.fruitParticle.speed, 1.5));
	local halfTime = (self.fruitParticle.partCount / percent) / 2;
	
	for _, particle in pairs(animatedParticle) do
		if particle.time + halfTime > time and  particle.time - halfTime < time then
			return false;
		end;
	end;
	
	return true;
end;

function FruitParticleSystem:onLeave()
    if self.deactivateOnLeave then
        self:resetFruitParticleSystem();
    end;
end;

function FruitParticleSystem:onDetach()
	self:resetFruitParticleSystem();
end;

function FruitParticleSystem:resetFruitParticleSystem()
	for k, particle in pairs(self.fruitParticle.leftPartInAnim) do
		table.insert(self.fruitParticle.leftFreePart[particle.type], particle.node);
		setVisibility(particle.node, false);
	end;
	self.fruitParticle.leftPartInAnim = {};
	for k, particle in pairs(self.fruitParticle.rightPartInAnim) do
		table.insert(self.fruitParticle.rightFreePart[particle.type], particle.node);
		setVisibility(particle.node, false);
	end;
	self.fruitParticle.rightPartInAnim = {};
end;