AbstractFunctionAC = {};

function AbstractFunctionAC:addFillLevelFromTool(superFunc, farmId, deltaFillLevel, fillTypeIndex, fillInfo, toolType, extraAttributes)
	-- Preserve all normal GIANTS sales, storage and base-game contract routing.
	-- Only mission classes explicitly marked by the TFU delivery-safety layer
	-- are intercepted so goods are credited before they may be removed.
	if type(deltaFillLevel) ~= "number" or deltaFillLevel <= 0 or self.missions == nil then
		return superFunc(self, farmId, deltaFillLevel, fillTypeIndex, fillInfo, toolType, extraAttributes);
	end;

	local usedMission = nil;
	local highestCompletion = -math.huge;
	for _, mission in pairs(self.missions) do
		local isTFUDeliveryMission = mission ~= nil and mission.tfuIsDeliveryMission == true;
		local isRunning = mission ~= nil and MissionStatus ~= nil and mission.status == MissionStatus.RUNNING;
		local sameFarm = mission ~= nil and mission.farmId == farmId;
		local sameStation = mission ~= nil and mission.sellingStation == self;
		local acceptsFillType = mission ~= nil and mission.acceptsMissionFillType ~= nil and mission:acceptsMissionFillType(fillTypeIndex);
		if isTFUDeliveryMission and isRunning and sameFarm and sameStation and acceptsFillType and mission.fillSold ~= nil then
			local completion = tonumber(mission.completion);
			if completion == nil and mission.getCompletion ~= nil then
				local success, value = pcall(mission.getCompletion, mission);
				if success then completion = tonumber(value);end;
			end;
			completion = completion or 0;
			if usedMission == nil or completion > highestCompletion then
				usedMission = mission;
				highestCompletion = completion;
			end;
		end;
	end;

	if usedMission == nil then
		return superFunc(self, farmId, deltaFillLevel, fillTypeIndex, fillInfo, toolType, extraAttributes);
	end;

	local destinationSafe = usedMission.tfuDestinationBlocked ~= true;
	if destinationSafe and usedMission.isTFUDestinationSafe ~= nil then
		local success, value = pcall(usedMission.isTFUDestinationSafe, usedMission, self);
		destinationSafe = success and value == true;
	elseif destinationSafe and usedMission.isDeliveryDestinationSafe ~= nil then
		local success, value = pcall(usedMission.isDeliveryDestinationSafe, usedMission, self, fillTypeIndex);
		destinationSafe = success and value == true;
	end;

	if not destinationSafe then
		local now = type(g_time) == "number" and g_time or 0;
		if now >= (self.tfuNextUnsafeMissionDeliveryLogTime or 0) then
			self.tfuNextUnsafeMissionDeliveryLogTime = now + 30000;
			local ownerFarmId = g_additionalContractMapData ~= nil and g_additionalContractMapData.getSellingStationOwnerFarmId ~= nil
				and g_additionalContractMapData:getSellingStationOwnerFarmId(self) or nil;
			Logging.warning(
				"Additional Contracts | Blocked unsafe contract delivery: mission=%s missionFarm=%s unloadingFarm=%s stationOwner=%s fillType=%s",
				tostring(usedMission.uniqueId or "unknown"), tostring(usedMission.farmId), tostring(farmId), tostring(ownerFarmId), tostring(fillTypeIndex)
			);
		end;
		return 0;
	end;

	local success, credited = pcall(usedMission.fillSold, usedMission, deltaFillLevel, fillTypeIndex);
	if not success then
		Logging.error("Additional Contracts | Contract delivery credit failed: mission=%s error=%s", tostring(usedMission.uniqueId or "unknown"), tostring(credited));
		return 0;
	end;
	credited = tonumber(credited) or 0;
	if credited <= 0 then return 0;end;

	if self.startFx ~= nil then pcall(self.startFx, self, fillTypeIndex);end;
	if self.activateSimpleFillplanes ~= nil then pcall(self.activateSimpleFillplanes, self, fillTypeIndex);end;
	return math.min(credited, deltaFillLevel);
end;

SellingStation.addFillLevelFromTool = Utils.overwrittenFunction(SellingStation.addFillLevelFromTool, AbstractFunctionAC.addFillLevelFromTool);

function AbstractFunctionAC:addSellingStationAcceptedFillTypes(sellingStation, fillTypes)
	if sellingStation == nil or fillTypes == nil or type(fillTypes) ~= "table" then return false;end;
	
	function addFillType(fillType)
		local isAdd = 0;
		
		function addTriggerFillType(fillType)
			for _, trigger in ipairs(sellingStation.unloadTriggers) do
				if trigger.fillTypes == nil or next(trigger.fillTypes) == nil then
				
				else
					if trigger.fillTypes[fillType] == nil then trigger.fillTypes[fillType] = true;end;
				end;
			end;			
		end;
		
		if sellingStation.acceptedFillTypes[fillType] == nil then
			sellingStation.supportedFillTypes[fillType] = true;
			local pricePerLiter = priceUnscaled or g_fillTypeManager:getFillTypeByIndex(fillType).pricePerLiter;
			if pricePerLiter == nil or pricePerLiter <= 0 then return false, "fillType has no price defined";end;
			sellingStation:addAcceptedFillType(fillType, pricePerLiter, supportsGreatDemand or false, disablePriceDrop or false);
			addTriggerFillType(fillType);			
			isAdd = isAdd + 1;			
		end;
		return isAdd;
	end;
	
	local totalAdd = 0;
	for _, fillType in pairs(fillTypes) do
		if fillType.index ~= nil and fillType.index ~= 0 then
			local isAdd = addFillType(fillType.index, fillType.priceUnscaled, fillType.supportsGreatDemand, fillType.disablePriceDrop);
			fillType.add = isAdd;
			totalAdd = totalAdd + isAdd;			
		else
			fillType.error = "fillType index not found or 0";
			fillType.add = 0;
		end;
	end;
	if totalAdd > 0 then
		sellingStation:updateSupportedFillTypes();
		sellingStation.pricingDynamics = {};
		sellingStation:initPricingDynamics();
	end;
	return true, fillTypes;	
end;

function AbstractFunctionAC:removeSellingStationAcceptedFillTypes(sellingStation, fillTypes)
	if sellingStation == nil or fillTypes == nil or type(fillTypes) ~= "table" then return false;end;
	
	function removeFillType(fillType)
		local isRemove = 0;		
		
		function removeTriggerFillType(fillType)
			for _, trigger in ipairs(sellingStation.unloadTriggers) do
				if trigger.fillTypes == nil or next(trigger.fillTypes) == nil then
				
				else
					if trigger.fillTypes[fillType] ~= nil then trigger.fillTypes[fillType] = nil;end;
				end;
			end;
		end;
		
		sellingStation.supportedFillTypes[fillType] = nil;
		sellingStation.acceptedFillTypes[fillType] = nil;
		sellingStation.fillTypeSupportsGreatDemand[fillType] = nil;
		if supportsGreatDemand then
			sellingStation.supportsGreatDemand = true
		end
		sellingStation.priceDropDisabled[fillType] = nil;
		sellingStation.originalFillTypePricesUnscaled[fillType] = nil;
		if sellingStation.originalFillTypePrices[fillType] > 0 then
			if sellingStation.numFillTypesForSelling > 0 then sellingStation.numFillTypesForSelling = sellingStation.numFillTypesForSelling - 1;end;
		end
		sellingStation.originalFillTypePrices[fillType] = nil;
		sellingStation.fillTypePrices[fillType] = nil;
		sellingStation.fillTypePriceInfo[fillType] = nil;
		sellingStation.fillTypePriceRandomDelta[fillType] = nil;
		sellingStation.priceMultipliers[fillType] = nil;
		sellingStation.totalReceived[fillType] = nil;
		sellingStation.totalPaid[fillType] = nil;
		sellingStation.pendingPriceDrop[fillType] = nil;
		sellingStation.prevFillLevel[fillType] = nil;
		sellingStation.prevTotalReceived[fillType] = nil;
		sellingStation.prevTotalPaid[fillType] = nil;
		sellingStation.lastUpdateTime[fillType] = nil;
		removeTriggerFillType(fillType);
		isRemove = isRemove + 1;
		return isRemove;
	end;
	
	local totalRemove = 0;
	for _, fillType in pairs(fillTypes) do
		if fillType.index ~= nil and fillType.index ~= 0 then
			local fillTypeIndex = fillType.index;
		
			if sellingStation.supportedFillTypes[fillTypeIndex] ~= nil then
				if sellingStation.acceptedFillTypes[fillTypeIndex] ~= nil then					
					local isRemove = removeFillType(fillTypeIndex);					
					fillType.remove = isRemove;
					totalRemove = totalRemove + isRemove;
				else
					fillType.error = "fillType not accepted at SellingStation";
					fillType.remove = 0;
				end;
			else
				fillType.error = "fillType not supported at SellingStation";
				fillType.remove = 0;
			end;
		else
			fillType.error = "fillType index not found or 0";
			fillType.remove = 0;
		end;
	end;
	if totalRemove > 0 then
		sellingStation:updateSupportedFillTypes();
		sellingStation.pricingDynamics = {};
		sellingStation:initPricingDynamics();
	end;
	return true, fillTypes;	
end;

function AbstractFunctionAC:unloadTriggerLoadFillTypes(xmlFile, xmlNode)	
	if xmlFile ~= nil and xmlFile:hasProperty("placeable") and xmlFile:hasProperty("placeable.sellingStation") then
		if xmlFile:hasProperty("placeable.sellingStation.unloadTrigger") or xmlFile:hasProperty("placeable.sellingStation.palletTrigger") or xmlFile:hasProperty("placeable.sellingStation.baleTrigger") or xmlFile:hasProperty("placeable.sellingStation.woodTrigger") then
			local missionType = xmlFile:getValue(xmlNode.. "#missionType", nil);
			if missionType ~= nil then
				local mission = g_missionManager:getMissionType(missionType)
				if mission ~= nil and mission.classObject ~= nil then mission = mission.classObject;end;
				if mission ~= nil and mission.getTriggerAcceptsFillTypes ~= nil then				
					local fillTypes = nil;
					if xmlFile:hasProperty("placeable.sellingStation.unloadTrigger") then 
						fillTypes = mission:getTriggerAcceptsFillTypes("unloadTrigger");
						if fillTypes ~= nil then xmlFile:setValue("placeable.sellingStation.unloadTrigger(?)#fillTypes", fillTypes);end;
					elseif xmlFile:hasProperty("placeable.sellingStation.palletTrigger") then 
						fillTypes = mission:getTriggerAcceptsFillTypes("palletTrigger");
						if fillTypes ~= nil then xmlFile:setValue("placeable.sellingStation.palletTrigger(?)#fillTypes", fillTypes);end;
					elseif xmlFile:hasProperty("placeable.sellingStation.baleTrigger") then 
						fillTypes = mission:getTriggerAcceptsFillTypes("baleTrigger");
						if fillTypes ~= nil then xmlFile:setValue("placeable.sellingStation.baleTrigger(?)#fillTypes", fillTypes);end;
					end;
				end;
			end;
		end;
	end;	
end;

UnloadTrigger.loadFillTypes = Utils.prependedFunction(UnloadTrigger.loadFillTypes, AbstractFunctionAC.unloadTriggerLoadFillTypes)