ChaffMission = {};
ChaffMission.NAME = "chaffMission";
ChaffMission.UI_SETTINGS = true;
ChaffMission.MAX_NUM_INSTANCE = 2;
ChaffMission.DEFAULT_NUM_INSTANCE = 2;
ChaffMission.MAX_NUM_SEASON = {3,0,1}; --0=off or max,is,nextDay
ChaffMission.BALANCE = {false,0};
ChaffMission.RANDOM = false;

source(AdditionalContracts.modDir.. "missions/chaffMission/ChaffChangeSettingsEvent.lua");
source(AdditionalContracts.modDir.. "missions/chaffMission/ChaffLoadSettingsEvent.lua");

ChaffMission.uiData = {
	settings = {
		chaffMission_minMax = ChaffMission.DEFAULT_NUM_INSTANCE;		
	};
	controls = {
		{ typName="chaffMission", name="chaffMission_minMax", autoBind=true, min=0, max=ChaffMission.MAX_NUM_INSTANCE, step=1, unit="/ ".. tostring(ChaffMission.MAX_NUM_INSTANCE), nillable=false };
	};
};

ChaffMission.data = {	
	ownTable = {FIELD_SIZE_BIGLARGE=35, SUCCESS_FACTOR=0.90, CONVERT_FACTOR=2, VEHICLE_USE_COST=130, classOverlay="harvester_chaff", typOverlay="chop"}; --big large speciale vehicles, 4x Mod Maps... / success factor for pf dlc / make it cheaper vehicle cost (many expensive vehicles)
	reward = {dismiss=0, min=2500, PER_HA=5000};
	jobTypName = g_i18n:getText("contract_field_chaff_title");	
};

ChaffMission.metadata = {
	interface = "FS25 ...", --new
	title = "Chaff\Forage Contracts",
	notes = "Dieser Mod generiert Häcksel Aufträge.",
	author = "(by HappyLooser)",		
	build = 7,
	datum = "06.07.2025",
	update = "01.11.2025",
	debugPrint = false, 
	discord = "HappyLooser Modding",
	info = " Link Freigabe,Änderungen,Kopien oder Code Benutzung ist ohne meine Zustimmung nicht erlaubt",
	"##Orginal Link Freigabe: https://www.farming-simulator.com/mods.php"
};

function debugPrint(text, ...)
	if ChaffMission.metadata.debugPrint then
		Logging.info(text,...);
	end;
end;	

local ChaffMission_mt = Class(ChaffMission, AbstractFieldMission);
InitObjectClass(ChaffMission, "ChaffMission");

function ChaffMission.registerXMLPaths(schema, key)
	ChaffMission:superClass().registerXMLPaths(schema, key);
	schema:register(XMLValueType.INT, key .. "#rewardPerHa", "Reward per ha");
	schema:register(XMLValueType.STRING, key .. ".fruitType#name", "Fruit type");
	schema:register(XMLValueType.INT, key .. ".fruitType#value", "Reward per ha");
	schema:register(XMLValueType.FLOAT, key .. "#failureCostFactor", "Failure cost factor");
	schema:register(XMLValueType.FLOAT, key .. "#failureCostOfTotal", "Failure cost of total");
end;

function ChaffMission.registerSavegameXMLPaths(schema, key)
	ChaffMission:superClass().registerSavegameXMLPaths(schema, key);
	local harvestKey = string.format("%s.harvest", key);
	schema:register(XMLValueType.STRING, harvestKey .. "#fruitType", "Name of the fruit type");
	schema:register(XMLValueType.FLOAT, harvestKey .. "#expectedLiters", "Expected liters");
	schema:register(XMLValueType.FLOAT, harvestKey .. "#depositedLiters", "Deposited liters");
	schema:register(XMLValueType.STRING, harvestKey .. "#sellingStationPlaceableUniqueId", "Unique id of the selling point");
	schema:register(XMLValueType.INT, harvestKey .. "#unloadingStationIndex", "Index of the unloading station");
end;

function ChaffMission.registerMetaXMLPaths(schema, key)
	ChaffMission:superClass().registerMetaXMLPaths(schema, key);
	schema:register(XMLValueType.INT, key .. "#nextDay", "Earliest day a new mission can spawn");	
end;

function ChaffMission.new(isServer, isClient, customMt)	
	local title = g_i18n:getText("contract_field_chaff_title");
	local description = g_i18n:getText("contract_field_chaff_description");
	local self = AbstractFieldMission.new(isServer, isClient, title, description, customMt or ChaffMission_mt);
	self.workAreaTypes = {
		[WorkAreaType.CUTTER] = true;		
	};
	self.pendingSellingStationId = nil;
	self.sellingStation = nil;
	self.fillTypeIndex = nil;
	self.depositedLiters = 0;
	self.expectedLiters = 0;
	self.reimbursementPerHa = 0;
	self.lastSellChange = -1;
	self.highestPrice = 0;
	return self;
end;

function ChaffMission:init(field, fruitTypeIndex, sellingStation)
	self.fruitTypeIndex = fruitTypeIndex;
	self.fillTypeIndex = FillType.CHAFF;
	local success = ChaffMission:superClass().init(self, field);
	self:setSellingStation(sellingStation);
	self:setMinReward();
	return success;
end;

function ChaffMission:onSavegameLoaded()
	if self.field == nil then
		Logging.error("Field is not set for chaff mission");
		g_missionManager:markMissionForDeletion(self);
		return;
	elseif self.field:getFieldState().fruitTypeIndex == self.fruitTypeIndex then
		if not self:getIsFinished() then
			local sellingStation = g_currentMission.placeableSystem:getPlaceableByUniqueId(self.sellingStationPlaceableUniqueId);
			if sellingStation == nil then
				Logging.error("Selling station placeable with uniqueId \'%s\' not available for chaff mission", self.sellingStationPlaceableUniqueId);
				g_missionManager:markMissionForDeletion(self);
				return;
			end;
			local unloadingStation = g_currentMission.storageSystem:getPlaceableUnloadingStation(sellingStation, self.unloadingStationIndex);
			if unloadingStation == nil then
				Logging.error("Unable to retrieve unloadingStation %d for placeable %s for chaff mission", self.unloadingStationIndex, sellingStation.configFileName);
				g_missionManager:markMissionForDeletion(self);
				return;
			end;
			self:setSellingStation(unloadingStation);
			if self:getWasStarted() then
				unloadingStation.missions[self] = self;
			end;
		end;
		ChaffMission:superClass().onSavegameLoaded(self);
	else
		local fruitTypeName = g_fruitTypeManager:getFruitTypeNameByIndex(self.fruitTypeIndex); --g_fruitTypeManager:getFruitTypeByIndex(self.fruitTypeIndex); --patch 1.14 ?
		Logging.error("FruitType \'%s\' is not present on field \'%s\' for chaff mission", fruitTypeName, self.field:getName());
		g_missionManager:markMissionForDeletion(self);
	end;
end;

function ChaffMission:delete()
	if self.sellingStation ~= nil then
		self.sellingStation.missions[self] = nil;
		self.sellingStation = nil;
	end;
	if self.sellingStationMapHotspot ~= nil then
		table.removeElement(self.mapHotspots, self.sellingStationMapHotspot);
		g_currentMission:removeMapHotspot(self.sellingStationMapHotspot);
		self.sellingStationMapHotspot:delete();
		self.sellingStationMapHotspot = nil;
	end;
	ChaffMission:superClass().delete(self);
end;

function ChaffMission:writeStream(streamId, connection)
	NetworkUtil.writeNodeObject(streamId, self.sellingStation);
	streamWriteUIntN(streamId, self.fillTypeIndex, FillTypeManager.SEND_NUM_BITS);
	ChaffMission:superClass().writeStream(self, streamId, connection);
end;

function ChaffMission:readStream(streamId, connection)
	self.pendingSellingStationId = NetworkUtil.readNodeObjectId(streamId);
	self.fillTypeIndex = streamReadUIntN(streamId, FillTypeManager.SEND_NUM_BITS);
	ChaffMission:superClass().readStream(self, streamId, connection);
end;

function ChaffMission:saveToXMLFile(xmlFile, key)
	local harvestKey = string.format("%s.harvest", key);
	xmlFile:setValue(harvestKey .. "#fruitType", g_fruitTypeManager:getFruitTypeNameByIndex(self.fruitTypeIndex));
	xmlFile:setValue(harvestKey .. "#expectedLiters", self.expectedLiters);
	xmlFile:setValue(harvestKey .. "#depositedLiters", self.depositedLiters);
	if self.sellingStation ~= nil then
		local sellingStationPlaceable = self.sellingStation.owningPlaceable;
		if sellingStationPlaceable == nil then
			local sellingStationName = self.sellingStation.getName and self.sellingStation:getName() or "unknown";
			Logging.xmlWarning(xmlFile, "Unable to retrieve placeable of sellingStation \'%s\' for saving chaff mission \'%s\' ", sellingStationName, key);
			return;
		end;
		local unloadingStationIndex = g_currentMission.storageSystem:getPlaceableUnloadingStationIndex(sellingStationPlaceable, self.sellingStation);
		if unloadingStationIndex == nil then
			local sellingStationName = self.sellingStation.getName and self.sellingStation:getName() or (sellingStationPlaceable.getName and sellingStationPlaceable:getName() or "unknown");
			Logging.xmlWarning(xmlFile, "Unable to retrieve unloading station index of sellingStation \'%s\' for saving chaff mission \'%s\' ", sellingStationName, key);
			return;
		end;
		xmlFile:setValue(harvestKey .. "#sellingStationPlaceableUniqueId", sellingStationPlaceable:getUniqueId());
		xmlFile:setValue(harvestKey .. "#unloadingStationIndex", unloadingStationIndex);
	end;
	ChaffMission:superClass().saveToXMLFile(self, xmlFile, key);
end;

function ChaffMission:loadFromXMLFile(xmlFile, key)
	local harvestKey = string.format("%s.harvest", key);
	local fruitTypeName = xmlFile:getValue(harvestKey .. "#fruitType");
	local fruitType = g_fruitTypeManager:getFruitTypeByName(fruitTypeName);
	if fruitType == nil then
		Logging.xmlError(xmlFile, "FruitType \'%s\' not defined", fruitTypeName);
		return false;
	end;
	self.fruitTypeIndex = fruitType.index;
	self.fillTypeIndex = FillType.CHAFF;
	self.expectedLiters = xmlFile:getValue(harvestKey .. "#expectedLiters", self.expectedLiters);
	self.depositedLiters = xmlFile:getValue(harvestKey .. "#depositedLiters", self.depositedLiters);
	if not ChaffMission:superClass().loadFromXMLFile(self, xmlFile, key) then
		return false;
	end;
	if not self:getIsFinished() then
		local sellingStationPlaceableUniqueId = xmlFile:getValue(harvestKey .. "#sellingStationPlaceableUniqueId");
		if sellingStationPlaceableUniqueId == nil then
			Logging.xmlError(xmlFile, "No sellingStationPlaceable uniqueId given for chaff mission at \'%s\'", harvestKey);
			return false;
		end;
		local unloadingStationIndex = xmlFile:getValue(harvestKey .. "#unloadingStationIndex");
		if unloadingStationIndex == nil then
			Logging.xmlError(xmlFile, "No unloadting station index given for chaff mission at \'%s\'", harvestKey);
			return false;
		end;
		self.sellingStationPlaceableUniqueId = sellingStationPlaceableUniqueId;
		self.unloadingStationIndex = unloadingStationIndex;
	end;
	if ChaffMission:canMaxNumSeason() then self:setMaxNumSeason();end;
	return true;
end;

function ChaffMission:update(dt)
	ChaffMission:superClass().update(self, dt);
	if self.pendingSellingStationId ~= nil then
		self:tryToResolveSellingStation();
	end;
	if self.lastSellChange > 0 then
		self.lastSellChange = self.lastSellChange - 1;
		if self.lastSellChange == 0 then
			local expected = self.expectedLiters * AbstractMission.SUCCESS_FACTOR;
			local depositedLiters = self.depositedLiters / expected * 100;
			local percentage = math.floor(depositedLiters);
			g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_OK, string.format(g_i18n:getText("contract_field_harvest_progress_transporting_forField"), percentage, self.field.farmland:getId()));
		end;
	end;
end;

function ChaffMission:createModifier()
	local fruitType = g_fruitTypeManager:getFruitTypeByIndex(self.fruitTypeIndex);
	if fruitType ~= nil and fruitType.terrainDataPlaneId ~= nil then
		local modifier = DensityMapModifier.new(fruitType.terrainDataPlaneId, fruitType.startStateChannel, fruitType.numStateChannels, g_terrainNode);
		local filter = DensityMapFilter.new(modifier);
		self.completionModifier = DensityMapMultiModifier.new();
		for cutState, _ in pairs(fruitType.cutStates) do
			filter:setValueCompareParams(DensityValueCompareType.EQUAL, cutState);
			self.completionModifier:addExecuteGet("cutState", modifier, filter);
		end;
		filter:setValueCompareParams(DensityValueCompareType.GREATER, 0);
		self.completionModifier:addExecuteGet("totalArea", modifier, filter);
		self.matchingPixels = {};
	end;
end;

function ChaffMission:tryToResolveSellingStation()
	if self.pendingSellingStationId ~= nil and self.sellingStation == nil then
		local sellingStation = NetworkUtil.getObject(self.pendingSellingStationId);
		if sellingStation ~= nil then
			self:setSellingStation(sellingStation);
		end;
	end;
end;

function ChaffMission:setSellingStation(sellingStation)
	if sellingStation ~= nil then
		self.pendingSellingStationId = nil;
		self.sellingStation = sellingStation;
		local placeable = sellingStation.owningPlaceable;
		if placeable ~= nil and placeable.getHotspot ~= nil then
			local mapHotspot = placeable:getHotspot();
			if mapHotspot ~= nil then
				self.sellingStationMapHotspot = HarvestMissionHotspot.new();
				self.sellingStationMapHotspot:setWorldPosition(mapHotspot:getWorldPosition());
				table.addElement(self.mapHotspots, self.sellingStationMapHotspot);
				if self.addSellingStationHotSpot then
					g_currentMission:addMapHotspot(self.sellingStationMapHotspot);
				end;
			end;
		end;
	end;
end;

function ChaffMission:addHotspots()
	ChaffMission:superClass().addHotspots(self);
	self.addSellingStationHotSpot = true;
	if self.sellingStationMapHotspot ~= nil then
		g_currentMission:addMapHotspot(self.sellingStationMapHotspot);
	end;
end;

function ChaffMission:removeHotspot()
	ChaffMission:superClass().removeHotspot(self);
	if self.sellingStationMapHotspot ~= nil then
		g_currentMission:removeMapHotspot(self.sellingStationMapHotspot);
	end;
	self.addSellingStationHotSpot = false;
end;

function ChaffMission:start(spawnVehicles)
	if self.pendingSellingStationId ~= nil then
		self:tryToResolveSellingStation();
	end;
	if self.sellingStation == nil then
		return false;
	end;
	self.sellingStation.missions[self] = self;
	return ChaffMission:superClass().start(self, spawnVehicles);
end;

function ChaffMission:finishedPreparing()
	ChaffMission:superClass().finishedPreparing(self);
	local fruitType = g_fruitTypeManager:getFruitTypeByIndex(self.fruitTypeIndex);
	local fieldAreaHa;
	if fruitType == nil or fruitType.terrainDataPlaneId == nil then
		fieldAreaHa = nil;
	else
		local modifier = DensityMapModifier.new(fruitType.terrainDataPlaneId, fruitType.startStateChannel, fruitType.numStateChannels, g_terrainNode);
		local filter = DensityMapFilter.new(modifier);
		filter:setValueCompareParams(DensityValueCompareType.GREATER, 0);
		self.field:getDensityMapPolygon():applyToModifier(modifier);
		local _, fieldArea, _ = modifier:executeGet(filter);
		fieldAreaHa = MathUtil.areaToHa(fieldArea, g_currentMission:getFruitPixelsToSqm());
	end;	
	self.expectedLiters = self:getMaxCutLiters(fieldAreaHa);
	if self.expectedLiters <= 0 then
		self:finish(MissionFinishState.FAILED);
	end;
end;

function ChaffMission:finish(success)
	ChaffMission:superClass().finish(self, success);
	if self.sellingStation ~= nil then
		self.sellingStation.missions[self] = nil;
		self.sellingStation = nil;
	end;
end;

function ChaffMission:getFieldFinishTask()
	local fruitType = g_fruitTypeManager:getFruitTypeByIndex(self.fruitTypeIndex);
	local fieldState = self.field:getFieldState();
	fieldState.fruitTypeIndex = self.fruitTypeIndex;
	fieldState.growthState = fruitType.cutState;
	return ChaffMission:superClass().getFieldFinishTask(self);
end;

function ChaffMission:getPartitionCompletion(partitionIndex)
	self:setPartitionRegion(partitionIndex);
	if self.completionModifier == nil then
		return 0, 0, 0;
	end;
	self.completionModifier:resetStats();
	self.completionModifier:execute(nil, self.matchingPixels, nil);
	return 0, self.matchingPixels.cutState, self.matchingPixels.totalArea;
end;

function ChaffMission:getCompletion()
	local completion;
	if self.expectedLiters > 0 then
		local sellCompletion = self.depositedLiters / self.expectedLiters / ChaffMission.data.ownTable.SUCCESS_FACTOR;
		completion = math.min(sellCompletion, 1);
	else
		completion = 1;
	end;
	local fieldCompletion = self:getFieldCompletion() / AbstractMission.SUCCESS_FACTOR;
	local harvestCompletion = 0.8 * math.min(fieldCompletion, 1) + 0.2 * completion;
	return math.min(1, harvestCompletion);
end;

function ChaffMission:getVehicleVariant()
	local fruitTypeIndex = self.fruitTypeIndex;
	if self.field:getAreaHa() >= ChaffMission.data.ownTable.FIELD_SIZE_BIGLARGE then --big large speciale vehicles, 4x Mod Maps
		if g_currentMission.missionDynamicInfo.isMultiplayer then return "BIGLARGE_MP";end;
		return "BIGLARGE_SP";
	end; 
	return (fruitTypeIndex == FruitType.SUNFLOWER or fruitTypeIndex == FruitType.MAIZE) and "MAIZE" or "GRAIN";	
end;

function ChaffMission:getVehicleCosts()
	if self.vehiclesToLoad == nil then
		return 0;
	end;
	local numVehicles = #self.vehiclesToLoad;
	local difficultyMultiplier = 0.7 + 0.3 * g_currentMission.missionInfo.economicDifficulty;
	return numVehicles * ChaffMission.data.ownTable.VEHICLE_USE_COST * difficultyMultiplier;
end;

function ChaffMission:getDetails()
	local details = ChaffMission:superClass().getDetails(self);
	local stationName = nil;
	if self.pendingSellingStationId ~= nil then
		self:tryToResolveSellingStation();
	end;
	if self.sellingStation ~= nil then
		stationName = self.sellingStation:getName();
	end;
	if stationName ~= nil then
		local sellPoint = {
			["title"] = g_i18n:getText("contract_details_harvesting_sellingStation");
			["value"] = stationName;
		};
		table.insert(details, sellPoint);
	end
	local harvesting = {
		["title"] = g_i18n:getText("contract_details_harvesting_crop");
		["value"] = g_fillTypeManager:getFillTypeTitleByIndex(self.fillTypeIndex);
	};
	table.insert(details, harvesting);
	return details;
end;

function ChaffMission:getExtraProgressText()
	if self.completion < 0.1 then
		return "";
	end;
	local stationName = "Unknown";
	if self.pendingSellingStationId ~= nil then
		self:tryToResolveSellingStation();
	end;
	if self.sellingStation ~= nil then
		stationName = self.sellingStation:getName();
	end;
	return string.format(g_i18n:getText("contract_field_harvest_nextUnloadDesc"), g_fillTypeManager:getFillTypeTitleByIndex(self.fillTypeIndex), stationName);
end;

function ChaffMission:fillSold(fillDelta)
	local depositedLiters = self.depositedLiters + fillDelta;
	local expectedLiters = self.expectedLiters;
	self.depositedLiters = math.min(depositedLiters, expectedLiters);
	local expected = self.expectedLiters * AbstractMission.SUCCESS_FACTOR;
	if self.sellingStation ~= nil and expected <= self.depositedLiters then
		self.sellingStation.missions[self] = nil;
	end;
	self.lastSellChange = 30;
end;

function ChaffMission:getRewardPerHa()
	local data = g_missionManager:getMissionTypeDataByName(ChaffMission.NAME);
	return data.rewardPerFruitHa[self.fruitTypeIndex] or data.rewardPerHa;
end;

function ChaffMission:setMinReward()
	if ChaffMission.data.reward.min == nil or ChaffMission.data.reward.min <= 0 then return;end;	
	if self.reward < ChaffMission.data.reward.min then self.reward = ChaffMission.data.reward.min;end;	
end;

function ChaffMission:getStealingCosts()
	if self.finishState ~= MissionFinishState.SUCCESS and self.isServer then
		local data = g_missionManager:getMissionTypeDataByName(ChaffMission.NAME);
		local fillType = FillType.CHAFF;
		local litersHarvested = self.expectedLiters * self:getFieldCompletion();
		for _, vehicle in pairs(self.vehicles) do
			if vehicle.spec_fillUnit ~= nil then
				for fillTypeIndex, _ in pairs(vehicle:getFillUnits()) do
					if vehicle:getFillUnitFillType(fillTypeIndex) == self.fillType then
						litersHarvested = litersHarvested - vehicle:getFillUnitFillLevel(fillTypeIndex);
					end;
				end;
			end;
		end;
		local diff = litersHarvested - self.depositedLiters;
		if litersHarvested * data.failureCostFactor < diff then
			local _, pricePerLiter = g_additionalContractMapData:getSellingStationWithHighestPrice(fillType);
			return diff * data.failureCostOfTotal * pricePerLiter;
		end;
	end;
	return 0;
end;

function ChaffMission:getMaxCutLiters(fieldAreaHa)
	local fieldState = self.field:getFieldState();
	local fruitTypeIndex = fieldState.fruitTypeIndex;
	local multiplier = fieldState:getHarvestScaleMultiplier();
	local areaHa = (fieldAreaHa or self.field:getAreaHa()) * multiplier;
	local areaPixel = MathUtil.haToSqm(areaHa) / g_currentMission:getFruitPixelsToSqm();
	--convert factor--
	local factor = ChaffMission.data.ownTable.CONVERT_FACTOR;
	--local converter = g_fruitTypeManager:getConverterDataByName("forageHarvester");	
	--local factor = converter[fruitTypeIndex].conversionFactor/ChaffMission.data.ownTable.CONVERT_FACTOR;
	--if factor >= ChaffMission.data.ownTable.CONVERT_FACTOR*2 then factor = factor/ChaffMission.data.ownTable.CONVERT_FACTOR;end; 
	--if self.highestPrice <= 300 then factor = 1;end;
	--convert factor--
	return factor * g_fruitTypeManager:getFruitTypeAreaLiters(fruitTypeIndex, areaPixel, false);
end;

function ChaffMission:getMissionTypeName()
	return ChaffMission.NAME;
end;

function ChaffMission:validate(event)
	if not ChaffMission:superClass().validate(self, event) then
		return false;
	end;
	if not self:getIsFinished() then
		if not ChaffMission.isAvailableForField(self.field, self) then
			return false;
		end;
		if self.sellingStation ~= nil and not self.sellingStation.isRegistered then
			return false;
		end;
	end;
	return true;
end;

function ChaffMission:onDeleteSellingStation(sellingStation)
	if sellingStation == self.sellingStation and (self.isServer and (self.status == MissionStatus.RUNNING and not g_currentMission.isExitingGame)) then
		Logging.warning("Finish chaff mission because selling station was removed");
		self:finish(MissionFinishState.FAILED);
	end;
end;

function ChaffMission.loadMapData(xmlFile, key, baseDirectory)
	local data = g_missionManager:getMissionTypeDataByName(ChaffMission.NAME);
	data.rewardPerHa = xmlFile:getFloat(key .. "#rewardPerHa", ChaffMission.data.reward.PER_HA);
	data.rewardPerFruitHa = {};
	xmlFile:iterate(key .. ".fruitType", function(_, valueKey)		
		local fruitType = xmlFile:getString(valueKey .. "#name");
		local rewardPerHa = xmlFile:getFloat(valueKey .. "#value", data.rewardPerHa);
		local fruitTypeIndex = g_fruitTypeManager:getFruitTypeIndexByName(fruitType);
		if fruitTypeIndex == nil then
			Logging.xmlWarning(xmlFile, "Chaffmission rewardPerHa fruitType \'%s\' is not defined for \'%s\'", fruitType, valueKey);
		else
			data.rewardPerFruitHa[fruitTypeIndex] = rewardPerHa;
		end;
	end)
	data.failureCostFactor = xmlFile:getFloat(key .. "#failureCostFactor", 0.1);
	data.failureCostOfTotal = xmlFile:getFloat(key .. "#failureCostOfTotal", 0.95);	
	return true;
end;

function ChaffMission.loadMetaDataFromXMLFile(xmlFile, key)
	if ChaffMission:canMaxNumSeason() then
		g_missionManager:getMissionTypeDataByName(ChaffMission.NAME).nextMissionDay = xmlFile:getValue(key .. "#nextDay");		
	end;
end;

function ChaffMission.saveMetaDataToXMLFile(xmlFile, key)
	local data = g_missionManager:getMissionTypeDataByName(ChaffMission.NAME);	
	if data.nextMissionDay ~= nil then
		xmlFile:setValue(key .. "#nextDay", data.nextMissionDay);
	end;	
end;

function ChaffMission.tryGenerateMission(addConsole, setMaxNumSeason)
	if ChaffMission.canRun(addConsole) then
		local field = g_fieldManager:getFieldForMission();
		if field == nil then
			if addConsole then printError("Error: No found mission field");end;
			return;
		end;
		if field.currentMission ~= nil then
			if addConsole then printError("Error: Field currentMission already");end;
			return;
		end;
		if not ChaffMission.isAvailableForField(field, nil) then
			if addConsole then printError("Error: No found isAvailableForField");end;
			return;
		end;
		local fruitTypeIndex = field:getFieldState().fruitTypeIndex;
		local fillTypeIndex = FillType.CHAFF;
		local sellingStation, highestPrice = g_additionalContractMapData:getSellingStationWithHighestPrice(fillTypeIndex);
		if not g_additionalContractMapData:isAvailableForSellingStation(sellingStation) then
			if addConsole then printError("Error: No found selling station");end;
			return;
		end;		
		local data = g_missionManager:getMissionTypeDataByName(ChaffMission.NAME);
		local mission = ChaffMission.new(true, g_client ~= nil);
		mission.highestPrice = highestPrice;		
		if mission:init(field, fruitTypeIndex, sellingStation) then
			mission:setDefaultEndDate();
			if (addConsole == nil or addConsole and setMaxNumSeason ~= nil) and mission:canMaxNumSeason() then 
				mission:setMaxNumSeason();
				if mission:isMaxNumSeason() then
					data.nextMissionDay = g_currentMission.environment.currentMonotonicDay + mission:getNextMissionDay();
					mission:setMaxNumSeason(0);
				end;
			end;
			return mission;
		end;
		if addConsole then printError("Error: Mission init not true");end;
		mission:delete();
	end;
	if addConsole then printError("Error: Mission type not active or disabled");end;
	return nil;
end;

function ChaffMission.isAvailableForField(field, mission)
	if mission == nil then
		local fieldState = field:getFieldState();
		if not fieldState.isValid then
			return false;
		end;
		local fruitTypeIndex = fieldState.fruitTypeIndex;
		if fruitTypeIndex == FruitType.UNKNOWN then
			return false;
		end;
		local fruitType = g_fruitTypeManager:getFruitTypeByIndex(fruitTypeIndex);
		if fruitType:getIsCatchCrop() then
			return false;
		end;
		if fruitType.minForageGrowthState == 0 or fruitType.minForageGrowthState > fieldState.growthState or fieldState.growthState > fruitType.maxForageGrowthState then --or not fruitType:getIsHarvestReady(fieldState.growthState) then
			return false;
		end;
	end;
	return true;
end;

function ChaffMission.canRun(addConsole)
	if not ChaffMission:getOnOff() then return false;end;
	if addConsole then return true;end;
	local data = g_missionManager:getMissionTypeDataByName(ChaffMission.NAME);
	if data.numInstances >= data.maxNumInstances or data.numInstances >= g_additionalContractTypes.settings[ChaffMission.NAME.. "_minMax"] then
		return false;
	else
		return not ChaffMission:canMaxNumSeason() or data.nextMissionDay == nil or g_currentMission.environment.currentMonotonicDay >= data.nextMissionDay;	
		--return not g_currentMission.growthSystem:getIsGrowingInProgress();
	end;
end;

function ChaffMission:setMaxNumInstance(maxNumInstance)
	self.uiData.settings[ChaffMission.NAME.. "_minMax"] = maxNumInstance;
	g_additionalContractTypes:replaceUISettings(ChaffMission.NAME.. "_minMax", maxNumInstance);
	local data = g_missionManager:getMissionTypeDataByName(ChaffMission.NAME);
	if data ~= nil then data.maxNumInstances = maxNumInstance;end;	
end;

function ChaffMission:getMaxNumInstance()
	local data = g_missionManager:getMissionTypeDataByName(ChaffMission.NAME);
	if data == nil then 
		return g_additionalContractTypes.settings[ChaffMission.NAME.. "_minMax"];
	end;
	return data.maxNumInstances;
end;

function ChaffMission:getOnOff()
	return g_additionalContractTypes.settings[ChaffMission.NAME.. "_minMax"] > 0;
end;

function ChaffMission:setOnOff(state)
	
end;

function ChaffMission:canMaxNumSeason()
	return ChaffMission.MAX_NUM_SEASON[1] > 0;
end;

function ChaffMission:isMaxNumSeason(canMaxNumSeason)
	if canMaxNumSeason ~= nil and canMaxNumSeason then return ChaffMission:canMaxNumSeason() and ChaffMission.MAX_NUM_SEASON[2] >= ChaffMission.MAX_NUM_SEASON[1];end;
	return ChaffMission.MAX_NUM_SEASON[2] >= ChaffMission.MAX_NUM_SEASON[1];
end;

function ChaffMission:setMaxNumSeason(state)
	ChaffMission.MAX_NUM_SEASON[2] = state or ChaffMission.MAX_NUM_SEASON[2] + 1;	
end;

function ChaffMission:getNextMissionDay()
	return ChaffMission.MAX_NUM_SEASON[3];
end;

function ChaffMission:onStartMap(args)
	if not args.isDetiServer and FS25_MissionsExpanded ~= nil and FS25_MissionsExpanded.MissionsExpanded ~= nil and FS25_MissionsExpanded.MissionsExpanded.missionsMultiplier["chaffMission"] ~= nil then --replace MissionsExpanded value
		FS25_MissionsExpanded.MissionsExpanded.missionsMultiplier["chaffMission"][1] = g_additionalContractTypes.settings[ChaffMission.NAME.. "_minMax"];
		local data = g_missionManager:getMissionTypeDataByName(ChaffMission.NAME);
		if data ~= nil and data.maxNumInstances ~= g_additionalContractTypes.settings[ChaffMission.NAME.. "_minMax"] then data.maxNumInstances = g_additionalContractTypes.settings[ChaffMission.NAME.. "_minMax"];end; 
	end;
end;

function ChaffMission:loadInit()	
	if ChaffMission.UI_SETTINGS then		
		local isReady = false;
		for key, value in pairs(ChaffMission.uiData.settings) do			
			isReady = g_additionalContractTypes:setUISettings(key, value);
			if not isReady then break;end; 
		end;
		if isReady then
			for _, control in ipairs(ChaffMission.uiData.controls) do
				g_additionalContractTypes:setUIControls(control);			
			end;
		else
			for key, value in pairs(ChaffMission.uiData.settings) do
				g_additionalContractTypes:delUISettings(key);				 
			end;
		end;		
	end;
	local xmlFile = Utils.getFilename("missionVehicles/chaffMissionVehicles.xml", AdditionalContracts.modDir)
	g_missionManager:addPendingMissionVehiclesFile(xmlFile, AdditionalContracts.modDir)
end;

function ChaffMission:loadSettingsEvent(mission, connection, x, y, z, viewDistanceCoeff)
	if g_currentMission ~= nil and g_currentMission.missionDynamicInfo ~= nil and g_currentMission.missionDynamicInfo.isMultiplayer then
		g_client:getServerConnection():sendEvent(ChaffLoadSettingsEvent.new());
	end;
end;

function ChaffMission:changeSettingsEvent(settingsId, state)
	if g_currentMission ~= nil and g_currentMission.missionDynamicInfo ~= nil and g_currentMission.missionDynamicInfo.isMultiplayer then
		g_client:getServerConnection():sendEvent(ChaffChangeSettingsEvent.new(settingsId, state));
	else
		self:onChangeSettings(settingsId, state);
	end;
end;

function ChaffMission:onChangeSettings(settingsId, state)
	if settingsId == "chaffMission_minMax" then		
		self:setMaxNumInstance(state);		
	end;	
end;

function ChaffMission:loadSettingsXML(xmlFile, prefix)	
	if not xmlFile:hasProperty(prefix.. ".".. ChaffMission.NAME.. ".minMax") then return;end;	
	local minMax = xmlFile:getInt(prefix.. ".".. ChaffMission.NAME.. ".minMax");
	local control = g_additionalContractTypes:getUIControls(ChaffMission.NAME.. "_minMax");
	if minMax > control.max then minMax = control.max;elseif minMax < control.min then minMax = control.min;end;	
	self:setMaxNumInstance(minMax);	
end;

function ChaffMission:saveSettingsXML(xmlFile, prefix)	
	xmlFile:setInt(prefix.. ".".. ChaffMission.NAME.. ".minMax", g_additionalContractTypes.settings[ChaffMission.NAME.. "_minMax"]);	
end;

function ChaffMission:getJobTypName()
	return self.data.jobTypName;
end;

function ChaffMission:getClassTypOverlay(args)
	local classOverlay = "harvester_chaff";
	local typOverlay = "chop";
	if self.data.ownTable.classOverlay ~= nil then classOverlay = self.data.ownTable.classOverlay;end;
	if self.data.ownTable.typOverlay ~= nil then typOverlay = self.data.ownTable.typOverlay;end;	
	return classOverlay, typOverlay;
end;

function ChaffMission:getFillTypeIndexOverlay(args)
	return FillType.CHAFF;
end;

g_additionalContractTypes:registerTyp(ChaffMission, ChaffMission.NAME, true);
