--
-- Sowing
-- Specialization for F_35
-- Autor Templear, Stefan Geiger, Fendt413
-- 

Sowing = {}


source("dataS/scripts/vehicles/specializations/SowingMachineAreaEvent.lua");
source("dataS/scripts/vehicles/specializations/SowingMachineSetIsFillingEvent.lua");

function Sowing.prerequisitesPresent(specializations)
	return SpecializationUtil.hasSpecialization(Fillable, specializations);
end;

function Sowing:load(xmlFile)
	-- Register specializations --
	self.groundContactReport = SpecializationUtil.callSpecializationsFunction("groundContactReport");
        self.getDirectionSnapAngle = Utils.overwrittenFunction(self.getDirectionSnapAngle, Sowing.getDirectionSnapAngle);
	-- Contact report nodes --
	self.contactReportNodes = {};
	local contactReportNodeFound = false;
	local i = 0;
	while true do
		local baseName = string.format("vehicle.contactReportNodes.contactReportNode(%d)", i);
		if not hasXMLProperty(xmlFile, baseName) then
			break;
		end;
		
		local index = getXMLString(xmlFile, baseName .. "#index");
		if index == nil then
			break;
		end;
		
		local node = Utils.indexToObject(self.components, index);
		if node == nil then
			break;
		end;
		
		local entry = {};
		entry.node = node;
		entry.hasGroundContact = false;

		self.contactReportNodes[node] = entry;
		
		contactReportNodeFound = true;
		
		i = i + 1;
	end;	
	
	if not contactReportNodeFound then
		local entry = {};
		entry.node = self.components[1].node;
		entry.hasGroundContact = false;
		
		self.contactReportNodes[entry.node] = entry;
	end;
	
	self.contactReportsActive = false; 
    self.groundContactFlag = self:getNextDirtyFlag();
	self.hasGroundContact = false;
	
	-- Ground reference --
	self.groundReferenceThreshold = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.groundReferenceNode#threshold"), 0.2);
    self.groundReferenceNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.groundReferenceNode#index"));
	
	-- Cutting areas --
	local i = 1;
	while true do
		local baseName = string.format("vehicle.cuttingAreas.cuttingArea%d", i);
		if not hasXMLProperty(xmlFile, baseName) then
			break;
		end;
		
		self.cuttingAreas[i].foldMinLimit = Utils.getNoNil(getXMLFloat(xmlFile, baseName .. "#foldMinLimit"), 0);
		self.cuttingAreas[i].foldMaxLimit = Utils.getNoNil(getXMLFloat(xmlFile, baseName .. "#foldMaxLimit"), 1);
		
		i = i + 1;
	end;
	
	self.UsageScale = Utils.getNoNil(getXMLString(xmlFile, "vehicle.UsageScale#value"), 1);	
    self.startActivationTime = 0;
 if self.useDirectPlanting then
           self.aiTerrainDetailChannel3 = g_currentMission.sowingChannel;
 end

self.sowingDirectionNode = Utils.getNoNil(Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.sowingDirectionNode#index")), self.components[1].node);
end;

function Sowing:delete()
	-- Contact report nodes --
	Sowing.removeContactReports(self);
end;

function Sowing:readStream(streamId, connection)
end;

function Sowing:writeStream(streamId, connection)
end;

function Sowing:readUpdateStream(streamId, timestamp, connection)
    if connection:getIsServer() then
        self.hasGroundContact = streamReadBool(streamId);
    end;
end;

function Sowing:writeUpdateStream(streamId, connection, dirtyMask)
    if not connection:getIsServer() then
		streamWriteBool(streamId, self.sowingMachineHasGroundContact);
    end;
end;

function Sowing:mouseEvent(posX, posY, isDown, isUp, button)
end;
function Sowing:keyEvent(unicode, sym, modifier, isDown)
end;

function Sowing:update(dt)
end;

function Sowing:updateTick(dt)
	if self:getIsActive() then
		local hasGroundContact = false;
		if self.isServer then
			-- Ground contact --
			if not hasGroundContact then
				for k, v in pairs(self.contactReportNodes) do
					if v.hasGroundContact then
						hasGroundContact = true;
						break;
					end;
				end;
				
				for k,v in pairs(self.wheels) do
					if v.hasGroundContact then
						hasGroundContact = true;
						break;
					end;
				end;
				
				if not hasGroundContact then
					if self.groundReferenceNode ~= nil then
						local x,y,z = getWorldTranslation(self.groundReferenceNode);
						local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, 0, z);
						if terrainHeight+self.groundReferenceThreshold >= y then
							hasGroundContact = true;
						end;
					end;
				end;
				
				if self.hasGroundContact ~= hasGroundContact then
					self:raiseDirtyFlags(self.groundContactFlag);
				end;
			end;
			self.hasGroundContact = hasGroundContact;

			local attacher = self.attacherVehicle;
			while attacher.attacherVehicle~= nil do
				attacher=attacher.attacherVehicle;
			end;
			local fruittype = SeedConsomation(FruitUtil.FRUITTYPE_UNKNOWN,0,attacher.attachedImplements);	

			if hasGroundContact and self:isLowered(false) then
				local hasSeeds = self.attacherVehicle.fillLevel ~= 0;
				local useFillLevel = true;
				if self:getIsHired() then
					useFillLevel = false;
					hasSeeds = true;
				end;
				if hasSeeds then
					self.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(self.cuttingAreasSend, {x,z,x1,z1,x2,z2});
						end;
						if table.getn(self.cuttingAreasSend) > 0 and fruittype ~= FruitUtil.FRUITTYPE_UNKNOWN then
                                                                local dx,dy,dz = localDirectionToWorld(self.sowingDirectionNode, 0, 0, 1);
                                                                local angleRad = Utils.getYRotationFromDirection(dx, dz)
                                                                local desc = FruitUtil.fruitIndexToDesc[fruittype];
                                                                 if desc ~= nil and desc.directionSnapAngle ~= 0 then
 					                              angleRad = math.floor(angleRad / desc.directionSnapAngle + 0.5) * desc.directionSnapAngle;
 					                         end
                                                                local angle = Utils.convertToDensityMapAngle(angleRad, g_currentMission.terrainDetailAngleMaxValue);
								local area, detailArea = SowingMachineAreaEvent.runLocally(self.cuttingAreasSend, fruittype, angle, self.useDirectPlanting)
								if area > 0 or detailArea > 0 then
									local fruitDesc = FruitUtil.fruitIndexToDesc[fruittype];

									local pixelToSqm = g_currentMission:getTerrainDetailPixelsToSqm();
									local sqm = area*pixelToSqm;
									local ha = sqm/10000;
									self.lastSowingArea = sqm;
									 
									local usage = fruitDesc.seedUsagePerSqm*sqm*self.UsageScale;
									g_currentMission.missionStats.seedUsageTotal = g_currentMission.missionStats.seedUsageTotal + usage;
									g_currentMission.missionStats.seedUsageSession = g_currentMission.missionStats.seedUsageSession + usage;

									g_currentMission.missionStats.hectaresSeededTotal = g_currentMission.missionStats.hectaresSeededTotal + ha;
									g_currentMission.missionStats.hectaresSeededSession = g_currentMission.missionStats.hectaresSeededSession + ha;
									
									SeedConsomation(self.attacherVehicle,usage,attacher.attachedImplements);				
									
									g_server:broadcastEvent(SowingMachineAreaEvent:new(self.cuttingAreasSend, fruittype));
								end;
						end;
					end;
					g_currentMission.missionStats.seedingDurationTotal = g_currentMission.missionStats.seedingDurationTotal + dt/(1000*60);
					g_currentMission.missionStats.seedingDurationSession = g_currentMission.missionStats.seedingDurationSession + dt/(1000*60);
				end;
			end;
		end;
	end;
end;

function Sowing:draw()
end;

function SeedConsomation(fruittype,usage,objectAttachedImplements)
	for k, implement in pairs(objectAttachedImplements) do
		local object = implement.object;
		if object.fillLevel ~= nil and object.capacity ~= nil then
			if object.fillLevel > 0 then
				object.fillLevel = math.max(object.fillLevel-usage,0)
				object:setFillLevel(object.fillLevel, object.currentFillType);
				fruittype = FruitUtil.fillTypeToFruitType[object.currentFillType];
				break;
			end;
		end;	
	end;
	return fruittype;
end;

function Sowing:onAttach(attacherVehicle)
    Sowing.onActivate(self);
    Sowing.addContactReports(self);
end;

function Sowing:onDetach()
    if self.deactivateOnDetach then
        Sowing.onDeactivate(self);
        Sowing.removeContactReports(self);
    end;
end;

function Sowing:onEnter(isControlling)
    if isControlling then
		Sowing.onActivate(self);
        Sowing.addContactReports(self);
    end;
end;

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

function Sowing:onActivate()
end;

function Sowing:onDeactivate()
end;

function Sowing:addContactReports()
   if not self.contactReportsActive then
	   for k, v in pairs(self.contactReportNodes) do
		   addContactReport(v.node, 0.0001, "groundContactReport", self);
	   end;
	   self.contactReportsActive = true;
   end;
end;

function Sowing:removeContactReports()
	if self.contactReportsActive then
		for k, v in pairs(self.contactReportNodes) do
			removeContactReport(v.node);
			v.hasGroundContact = false;
		end;
		self.contactReportsActive = false;
	end;
end;

function Sowing:groundContactReport(objectId, otherObjectId, isStart, normalForce, tangentialForce)
	if otherObjectId == g_currentMission.terrainRootNode then
		local entry = self.contactReportNodes[objectId];
		if entry ~= nil then
			entry.hasGroundContact = isStart or normalForce > 0 or tangentialForce > 0;
		end;
	end;
end;

function Sowing:getDirectionSnapAngle(superFunc)   
     local desc = FruitUtil.fruitIndexToDesc[fruittype];
      local snapAngle = 0;
      if desc ~= nil then
          snapAngle = desc.directionSnapAngle;
      end
      return math.max(snapAngle, superFunc(self));
end