AdditionalContractTypes = {};
AdditionalContractTypes.addConsoleCommand = true;
AdditionalContractTypes.SUCCESS_FACTOR = {90,80,95}; --default is,min,max

source(AdditionalContracts.modDir.. "manager/AdditionalContractChangeSettingsEvent.lua");
source(AdditionalContracts.modDir.. "manager/AdditionalContractLoadSettingsEvent.lua");

AdditionalContractTypes.uiData = {
	settings = {
		additionalContract_successFactor = AdditionalContractTypes.SUCCESS_FACTOR[1];
	};
	controls = {
		{ typName="additionalContract", name="additionalContract_successFactor", autoBind=true, min=AdditionalContractTypes.SUCCESS_FACTOR[2], max=AdditionalContractTypes.SUCCESS_FACTOR[3], step=1, unit="%", nillable=false };
	};
};

local AdditionalContractTypes_mt = Class(AdditionalContractTypes);

function AdditionalContractTypes.new()	
	local self = {};
	setmetatable(self, AdditionalContractTypes_mt);	
	self.typ = {};	
	self.settings = {};
	self.controls = {};
	self.xmlPrefix = "additionalContracts";
	self.multiplier = 1;
	self.numElements = {};
	self.randomTyp = {};
	self.balanceTyp = {};
	self.seasonTyp = {};
	self.nextDayTyp = {};
	return self;
end;

function AdditionalContractTypes:registerSavegameXMLPaths(schema, key)
	for _, typ in pairs (self.typ) do
		if typ ~= nil and typ.REGISTER_XML_PATHS ~= nil and typ.REGISTER_XML_PATHS and typ.registerSavegameXMLPaths ~= nil then typ.registerSavegameXMLPaths(schema, key);end;
	end;
end;

function AdditionalContractTypes:registerTyp(class, typName, org, alreadyTyp)
	local canRegister = true;
	if class == nil or typName == nil or self.typ[typName] ~= nil then canRegister = false;end;
	if canRegister then		
		self.typ[typName] = class;
		if org ~= nil and org then			
			if self:isAlreadyAvailableTyp(typName, alreadyTyp) then --register cancel already available mission typ (regardless of whether loaded or not-better for conflicts)
				self.typ[typName] = nil;
				local alreadyTypFile = "";
				if alreadyTyp ~= nil then alreadyTypFile = " ".. alreadyTyp.. ".zip";end;
				Logging.info(tostring(AdditionalContracts.metadata.title).. " not register Mission-Types: ".. tostring(typName).. " (already available/mod directory)".. tostring(alreadyTypFile));
				return false;
			end; 
			self:registerOrginalMission(class, typName, self.typ[typName]:getMaxNumInstance());
			Logging.info(tostring(AdditionalContracts.metadata.title).. " register Mission-Types: ".. tostring(typName));
		end;
		if self.typ[typName].loadInit ~= nil then self.typ[typName]:loadInit();end;
		if g_server ~= nil and self.typ[typName].addConsoleCommand ~= nil then self.typ[typName]:addConsoleCommand("AC");end;		
		return true;
	else
		Logging.warning(tostring(AdditionalContracts.metadata.title).. " not register Mission-Types: TypName\Class missing ? = ".. tostring(typName));
		return false;
	end;	
end;

function AdditionalContractTypes:isAlreadyAvailableTyp(typName, alreadyTyp)
	local available = false;
	local data = g_missionManager:getMissionTypeDataByName(typName);
	if data ~= nil then available = true;end;
	if alreadyTyp == nil or available then return available;end;
	if getfenv(0)[alreadyTyp] ~= nil then
		available = true;		
	end;	
	return available;
end;

function AdditionalContractTypes:unregisterTyp(typName)
	if typName == nil or self.typ[typName] == nil then return;end;
	self.typ[typName] = nil;
	self:unregisterOrginalMission(typName);
	--Logging.info(tostring(AdditionalContracts.metadata.title).. " unregister Mission Types: ".. tostring(typName));
end;

function AdditionalContractTypes:registerTypNameByTyp(typName, class, registerTypName, ownTable)
	if typName == nil or class == nil or registerTypName == nil or self.typ[typName] == nil or self.typ[typName].registerTypNames == nil then return;end;
	self.typ[typName]:registerTypNames(class, registerTypName, ownTable);
end;

function AdditionalContractTypes:getTypClass(setGlobalValues)	
	local typClass = g_additionalContractTypes:getMissionTyp(false, false, self.numElements[1]);
	if setGlobalValues ~= nil and setGlobalValues then
		self:setNumNextDayTyp(tostring(self.numElements[1]));
		self:setBalanceTyp(tostring(self.numElements[1]));
	end;
	table.remove(self.numElements, 1);
	return typClass;
end;

function AdditionalContractTypes:getTyp(typName)
	if typName == nil or self.typ[typName] == nil then return nil;end;
	return self.typ[typName];
end;

function AdditionalContractTypes:getData(typName)
	local typ = self:getTyp(typName);
	if typ == nil or typ.getOwnData == nil then return {};end;
	return typ:getOwnData() or {};
end;

function AdditionalContractTypes:getSuccessFactor()
	return math.max(0, math.min(self.uiData.settings["additionalContract_successFactor"], 100)) / 100;
	--return AdditionalContractTypes.SUCCESS_FACTOR[1]/100;
end;

---balance system---
function AdditionalContractTypes:insertBalanceTyp(typName)
	self.balanceTyp[typName] = {self:getLowestBalanceTyp(), true};	
end;

function AdditionalContractTypes:removeBalanceTyp(typName)
	if self.balanceTyp[typName] ~= nil then self.balanceTyp[typName] = nil;end;
end;

function AdditionalContractTypes:enabledBalanceTyp(typName)	
	self.balanceTyp[typName][1] = self:getHighestBalanceTyp();
	self.balanceTyp[typName][2] = true;
end;

function AdditionalContractTypes:disabledBalanceTyp(typName)	
	self.balanceTyp[typName][2] = false;
end;

function AdditionalContractTypes:hasBalanceTyp(typName)
	return typName ~= nil and self.balanceTyp[typName] ~= nil;
end;

function AdditionalContractTypes:canBalanceTyp(typName)
	return typName ~= nil and self.balanceTyp[typName] ~= nil and self.balanceTyp[typName][2];
end;

function AdditionalContractTypes:getHighestBalanceTyp()
	local highest = nil;			
	for balanceTyp, values in pairs(self.balanceTyp) do
		if balanceTyp ~= nil and values[2] then
			if self:canRunAndNotIsMaxNextDayTyp(balanceTyp) and (highest == nil or values[1] > highest) then
				highest = values[1];
			end;			
		end;
	end;
	return highest or 0;
end;

function AdditionalContractTypes:getLowestBalanceTyp()
	local lowest = nil;			
	for balanceTyp, values in pairs(self.balanceTyp) do
		if balanceTyp ~= nil and values[2] then
			if self:canRunAndNotIsMaxNextDayTyp(balanceTyp) and (lowest == nil or values[1] < lowest) then
				lowest = values[1];
			end;			
		end;
	end;
	return lowest or 0;
end;

function AdditionalContractTypes:resetBalanceTyp(typName)
	if typName ~= nil then
		if self:hasBalanceTyp(typName) then self.balanceTyp[typName][1] = 0;end;
	else
		for balanceTyp, _ in pairs (self.balanceTyp) do
			if balanceTyp ~= nil then self.balanceTyp[balanceTyp][1] = 0;end;
		end;
	end;	
end;

function AdditionalContractTypes:setBalanceTyp(typName, negativ)
	if not self:hasBalanceTyp(typName) or not self:canBalanceTyp(typName) then return;end;
	if negativ ~= nil and negativ then
		if self.balanceTyp[typName][1] > 0 then self.balanceTyp[typName][1] = self.balanceTyp[typName][1] - 1;end;
	else
		self.balanceTyp[typName][1] = self.balanceTyp[typName][1] + 1;
	end;		
end;
---balance system---

---random system---
function AdditionalContractTypes:insertRandomTyp(typName)
	self.randomTyp[typName] = true;
end;

function AdditionalContractTypes:removeRandomTyp(typName)
	if self.randomTyp[typName] ~= nil then self.randomTyp[typName] = nil;end;
end;

function AdditionalContractTypes:hasRandomTyp(typName)
	return typName ~= nil and self.randomTyp[typName] ~= nil and self.randomTyp[typName];
end;
---random system---

---next day system---
function AdditionalContractTypes:insertNextDayTyp(typName, dayData)
	self.nextDayTyp[typName] = dayData;
	self.nextDayTyp[typName][4] = 0; --next day
end;

function AdditionalContractTypes:removeNextDayTyp(typName)
	if self.nextDayTyp[typName] ~= nil then self.nextDayTyp[typName] = nil;end;	
end;

function AdditionalContractTypes:hasNextDayTyp(typName)
	return typName ~= nil and self.nextDayTyp[typName] ~= nil;	
end;

function AdditionalContractTypes:setNumNextDayTyp(typName, negativ)
	if self.nextDayTyp[typName] ~= nil then
		if negativ ~= nil and negativ then
			if self.nextDayTyp[typName][2] > 0 then self.nextDayTyp[typName][2] = self.nextDayTyp[typName][2] - 1;end;
		else
			self.nextDayTyp[typName][2] = self.nextDayTyp[typName][2] + 1;
		end;
		if self:isMaxNextDayTyp(typName) then self:setNextDayTyp(typName);end;
	end;
end;

function AdditionalContractTypes:setNextDayTyp(typName)
	if self.nextDayTyp[typName] ~= nil then
		if self.nextDayTyp[typName][4] == 0 then --first start
			self.nextDayTyp[typName][4] = g_currentMission.environment.currentMonotonicDay;
		else
			self.nextDayTyp[typName][4] = self.nextDayTyp[typName][3] + g_currentMission.environment.currentMonotonicDay;
		end;		
		if self:hasBalanceTyp(typName) and self:isMaxNextDayTyp(typName) then self:disabledBalanceTyp(typName);end;
	end;
end;

function AdditionalContractTypes:canRunAndNotIsMaxNextDayTyp(typName)
	if self.nextDayTyp[typName] == nil then return true;end;
	return self:canRunNextDayTyp(typName) and not self:isMaxNextDayTyp(typName)
end;

function AdditionalContractTypes:canRunNextDayTyp(typName)
	return g_currentMission ~= nil and g_currentMission.environment ~= nil and g_currentMission.environment.currentMonotonicDay ~= nil and g_currentMission.environment.currentMonotonicDay >= self.nextDayTyp[typName][4];
end;

function AdditionalContractTypes:isMaxNextDayTyp(typName)
	if self.nextDayTyp[typName] == nil then return false;end;
	return self.nextDayTyp[typName][2] >= self.nextDayTyp[typName][1];
end;

function AdditionalContractTypes:resetNextDayTyp(typName)
	if self.nextDayTyp[typName] == nil then return;end;
	self.nextDayTyp[typName][2] = 0;
end;
---next day system---

--------------------------------------
function AdditionalContractTypes:insertSeasonTyp(typName, seasonData)
	self.seasonTyp[typName] = seasonData;
	self.seasonTyp[typName][4] = 0; --next season day
end;

function AdditionalContractTypes:removeSeasonTyp(typName)
	if self.seasonTyp[typName] ~= nil then self.seasonTyp[typName] = nil;end;
end;

function AdditionalContractTypes:hasSeasonTyp(typName)
	return typName ~= nil and self.seasonTyp[typName] ~= nil;
end;

function AdditionalContractTypes:resetSeasonTyp(typName)
	if typName ~= nil then
		if self:hasSeasonTyp(typName) then self.seasonTyp[typName][2] = 0;end;
	else
		for seasonTyp, _ in pairs (self.seasonTyp) do
			if seasonTyp ~= nil then self.seasonTyp[seasonTyp][2] = 0;end;
		end;
	end;	
end;

function AdditionalContractTypes:setNumSeasonTyp(typName, negativ)
	if not self:hasSeasonTyp(typName) or self:isMaxNumSeasonTyp(typName) then return;end;
	if negativ ~= nil and negativ then
		if self.seasonTyp[typName][2] > 0 then self.seasonTyp[typName][2] = self.seasonTyp[typName][2] - 1;end;
	else
		self.seasonTyp[typName][2] = self.seasonTyp[typName][2] + 1;
	end;
end;

function AdditionalContractTypes:isMaxNumSeasonTyp(typName)	
	if self.seasonTyp[typName] ~= nil and self.seasonTyp[typName][2] >= self.seasonTyp[typName][1] then return true;end;
	return false;
end;

function AdditionalContractTypes:setNextDayByNumSeasonTyp(typName)	
	if self.seasonTyp[typName] ~= nil then self.seasonTyp[typName][4] = self:getNextDayByNumSeasonTyp(typName);end;	
end;

function AdditionalContractTypes:getNextDayByNumSeasonTyp(typName)	
	if self.seasonTyp[typName] ~= nil then return self.seasonTyp[typName][3] + g_currentMission.environment.currentMonotonicDay;end;
	return 0;
end;

function AdditionalContractTypes:isNextDayByNumSeasonTyp(typName)	
	if self:hasSeasonTyp(typName) then return self.seasonTyp[typName][4] <= g_currentMission.environment.currentMonotonicDay;end;
	return true;
end;
-----------------------------------------

function AdditionalContractTypes:getMissionTyp(balanceTyp, randomTyp, typName)
	if self.typ == nil then return nil;end;	
	if typName ~= nil and self.typ[typName] ~= nil then 
		return self.typ[typName];
	elseif randomTyp then		
		function random_elem()
			local keys = {};
			for randomTyp, available in pairs(self.randomTyp) do if available then table.insert(keys, randomTyp)end;end;
			return self:getMissionTyp(false, false, tostring(self.randomTyp[keys[math.random(#keys)]]));
		end;
		return random_elem();
	elseif balanceTyp then				
		local highestBalance = self:getHighestBalanceTyp();
		local lowestBalance = 0;
		local balanceLowest = {};
		local balanceHighest = {};
		function set_lowestBalanceTypes()
			for balanceTyp, values in pairs(self.balanceTyp) do
				if balanceTyp ~= nil and values[2] and (values[1] == 0 or values[1] < highestBalance) then
					table.insert(balanceLowest, balanceTyp);
				elseif balanceTyp ~= nil and values[2] and values[1] == highestBalance then
					table.insert(balanceHighest, balanceTyp);
				end;
			end;
		end;
		set_lowestBalanceTypes();
		if #balanceLowest > 0 then 
			return self:getMissionTyp(false, false, tostring(balanceLowest[math.random(1, #balanceLowest)]));
		elseif #balanceHighest > 0 then
			return self:getMissionTyp(false, false, tostring(balanceHighest[math.random(1, #balanceHighest)]));
		end;		
	end;	
	return nil;
end;

function AdditionalContractTypes:hasAutoload()
	return g_modIsLoaded["FS25_UniversalAutoload"] and FS25_UniversalAutoload ~= nil;
end;

function AdditionalContractTypes:loadMap()

end;

function AdditionalContractTypes:onStartMap(args)
	self:loadSettingsXML(g_currentMission);	
	for _, typ in pairs (self.typ) do
		if typ ~= nil and typ.onStartMap ~= nil then typ:onStartMap(args);end;
	end;
	for nextDayTyp, _ in pairs (self.nextDayTyp) do
		if nextDayTyp ~= nil then self:setNextDayTyp(nextDayTyp);end;
	end;		
	if g_server ~= nil and AdditionalContractTypes.addConsoleCommand and not g_addTestCommands then
		addConsoleCommand("ACMissionGenerate", "Force generating a new mission for given farmland", "consoleGenerateMission", self, "farmlandId; missionType; optional setMaxNumSeason higher [true]")
		addConsoleCommand("ACMissionLoadVehicleSet", "Loads a specific vehicle set", "consoleLoadVehicleSet", self, "missionType; [size (small|medium|large)]; [groupIndex]")
	end;	
end;

function AdditionalContractTypes:isOnStartMap(args)
	self.multiplier = g_currentMission.missionInfo.economicDifficulty == EconomicDifficulty.NORMAL and 1 or (g_currentMission.missionInfo.economicDifficulty == EconomicDifficulty.EASY and 1.2 or 0.8);
	for _, typ in pairs (self.typ) do
		if typ ~= nil and typ.isOnStartMap ~= nil then typ:isOnStartMap(args);end;
	end;
end;

function AdditionalContractTypes:loadSettingsFromServer(mission, connection, x, y, z, viewDistanceCoeff)
	if g_currentMission ~= nil and g_currentMission.missionDynamicInfo ~= nil and g_currentMission.missionDynamicInfo.isMultiplayer then
		---
		g_additionalContractTypes:loadSettingsEvent(mission, connection, x, y, z, viewDistanceCoeff);
		---
		for _, typ in pairs (g_additionalContractTypes.typ) do
			if typ ~= nil and typ.loadSettingsEvent ~= nil then typ:loadSettingsEvent(mission, connection, x, y, z, viewDistanceCoeff);end;
		end;
	end;
end;

function AdditionalContractTypes: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(AdditionalContractLoadSettingsEvent.new());
	end;
end;

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

function AdditionalContractTypes:onChangeSettings(settingsId, state)
	if settingsId == "additionalContract_successFactor" then		
		g_additionalContractTypes:setSuccessFactor(state);	
	end;	
end;

function AdditionalContractTypes:loadSettingsXML(mission)	
	if mission:getIsServer() then        
		if mission.missionInfo.savegameDirectory ~= nil and fileExists(mission.missionInfo.savegameDirectory .. "/additionalContracts.xml") then
           	local xmlFile = XMLFile.load("AdditionalContractsXML", mission.missionInfo.savegameDirectory .. "/additionalContracts.xml");
            if xmlFile ~= nil then
                ---
				self:loadOwnSettings(xmlFile);				
				---
				for _, typ in pairs (g_additionalContractTypes.typ) do
					if typ ~= nil and typ.loadSettingsXML ~= nil then typ:loadSettingsXML(xmlFile, self.xmlPrefix);end;
				end;
                xmlFile:delete();
            end;
        end;
    end;
end;

function AdditionalContractTypes:loadOwnSettings(xmlFile)
	if not xmlFile:hasProperty(self.xmlPrefix.. ".successFactor") then return;end;
	local successFactor = xmlFile:getInt(self.xmlPrefix.. ".successFactor");
	if successFactor < AdditionalContractTypes.SUCCESS_FACTOR[2] or successFactor > AdditionalContractTypes.SUCCESS_FACTOR[3] then successFactor = AdditionalContractTypes.SUCCESS_FACTOR[1];end;	
	g_additionalContractTypes:setSuccessFactor(successFactor);
end;

function AdditionalContractTypes:saveSettingsXML(mission)    
	local xmlFile = XMLFile.create("AdditionalContractsXML", mission.missionInfo.savegameDirectory .. "/additionalContracts.xml", self.xmlPrefix);
    if xmlFile ~= nil then
        ---
		self:saveOwnSettings(xmlFile);
		---
		for _, typ in pairs (g_additionalContractTypes.typ) do
			if typ ~= nil and typ.saveSettingsXML ~= nil then typ:saveSettingsXML(xmlFile, self.xmlPrefix);end;
		end;
        xmlFile:save();
		xmlFile:delete();
    end;
end;

function AdditionalContractTypes:saveOwnSettings(xmlFile)
	xmlFile:setInt(self.xmlPrefix.. ".successFactor", g_additionalContractTypes.settings["additionalContract_successFactor"]);
end;

function AdditionalContractTypes:setSuccessFactor(successFactor)
	self.uiData.settings["additionalContract_successFactor"] = successFactor;
	g_additionalContractTypes:replaceUISettings("additionalContract_successFactor", successFactor);
end;

function AdditionalContractTypes:update(dt)
	
end;

function AdditionalContractTypes:setUISettings(key, value)	
	if self.settings[key] == nil then self.settings[key] = value;return true;end;
	return false;
end;

function AdditionalContractTypes:getUISettings(key)
	if self.settings[key] ~= nil then return self.settings[key];end;
	return nil;
end;

function AdditionalContractTypes:replaceUISettings(key, value)	
	if self.settings[key] ~= nil then self.settings[key] = value;end;	
end;

function AdditionalContractTypes:delUISettings(key)	
	if self.settings[key] ~= nil then self.settings[key] = nil;end;	
end;

function AdditionalContractTypes:setUIControls(control)	
	table.insert(self.controls, control);	
end;

function AdditionalContractTypes:getUIControls(controlName)
	for _, control in ipairs(g_additionalContractTypes.controls) do
		if control.name == controlName then return control;end;			
	end;
	return nil;
end;

function AdditionalContractTypes:registerOrginalMission(class, name, maxNumInstance)
	g_missionManager:registerMissionType(class, name, maxNumInstance);
end;

function AdditionalContractTypes:unregisterOrginalMission(name)
	g_missionManager:unregisterMissionType(name);
end;
----
function AdditionalContractTypes:consoleGenerateMission(farmlandId, missionTypeName, setMaxNumSeason)
	local farmland = g_farmlandManager:getFarmlandById(tonumber(farmlandId));
	if farmland == nil then
		printError("Error: Given farmland not found");
		return;
	else
		local field = farmland:getField();
		if field == nil then
			printError("Error: No found farmland field");
		elseif not field.isMissionAllowed then
			printError("Error: Farmland field not ready for a mission");
		end;
		g_fieldManager.debugField = field;
		if missionTypeName == nil then
			printError(string.format("Error: No mission type given"));
			print(string.format("Available mission types: %s", table.concatKeys(g_missionManager.nameToMissionType, ", ")))
			return;
		else
			local success = false;
			local missionType = g_missionManager:getMissionType(missionTypeName);
			if missionType == nil then
				printError(string.format("Error: Given missionType %q not found", missionTypeName));
				print(string.format("Available mission types: %s", table.concatKeys(g_missionManager.nameToMissionType, ", ")))
			else
				local classObject = missionType.classObject;
				if classObject.tryGenerateMission ~= nil then					
					local mission = classObject.tryGenerateMission(true, setMaxNumSeason);
					if mission ~= nil then
						g_missionManager:registerMission(mission, missionType);
						success = true;
					end;
				end;
				g_fieldManager.debugField = nil;
				if success then
					return "Mission created";
				end;
				printError("Error: Failed to create mission");
			end;
		end;
	end;
end;

function AdditionalContractTypes:consoleLoadVehicleSet(missionTypeName, size, groupIndex)
	local missionTypes = {};
	local foundMissionType = false;
	local fieldSize = size or "medium";
	for _, missionTypeNames in ipairs(g_missionManager.missionTypes) do
		local missionType = missionTypeNames.name;
		table.insert(missionTypes, missionType);
		if missionTypeNames.name == missionTypeName then
			foundMissionType = true;
		end;
	end;
	if foundMissionType then
		local vehicles, _, errorMessage = g_missionManager:getVehicleGroupFromIdentifier(missionTypeName, fieldSize, tonumber(groupIndex) or 1);
		if vehicles == nil then
			Logging.error("No vehicles defined for parameter. %s", errorMessage);
		else
			local numLoadedVehicles = 0;
			local numVehiclesToLoad = #vehicles;
			local function onSpawnedVehicle(_, loadedVehicles, loadingState, _)
				if loadingState == VehicleLoadingState.OK then
					numLoadedVehicles = numLoadedVehicles + 1;
					if numLoadedVehicles == numVehiclesToLoad then
						Logging.info("Finished mission vehicle loading");
						return;
					end;
				else
					for _, vehicle in ipairs(loadedVehicles) do
						vehicle:delete();
					end;
					Logging.error("Failed to load vehicles");
				end;
			end;
			for _, vehicleInfo in ipairs(vehicles) do
				local data = VehicleLoadingData.new();
				data:setFilename(vehicleInfo.filename);
				if data.isValid then
					if vehicleInfo.configurations ~= nil then
						data:setConfigurations(vehicleInfo.configurations);
					end;
					data:setLoadingPlace(g_currentMission.storeSpawnPlaces, g_currentMission.usedStorePlaces);
					data:setOwnerFarmId(g_localPlayer:getFarmId());
					data:load(onSpawnedVehicle, nil, nil);
				end;
			end;
		end;
	else
		Logging.error("Unknown missionType %q", missionTypeName);
		print(string.format("Available mission types: %s", table.concat(missionTypes, ", ")))
		return;
	end;
end;
----
g_additionalContractTypes = AdditionalContractTypes.new();

function loadInit()
	local isReady = false;
	for key, value in pairs(AdditionalContractTypes.uiData.settings) do			
		isReady = g_additionalContractTypes:setUISettings(key, value);
		if not isReady then break;end; 
	end;
	if isReady then
		for _, control in ipairs(AdditionalContractTypes.uiData.controls) do
			g_additionalContractTypes:setUIControls(control);			
		end;
	else
		for key, value in pairs(AdditionalContractTypes.uiData.settings) do
			g_additionalContractTypes:delUISettings(key);				 
		end;
	end;
end;
loadInit();

source(AdditionalContracts.modDir.. "missions/baleCollectMission/BaleCollectMission.lua");
source(AdditionalContracts.modDir.. "missions/chaffMission/ChaffMission.lua");
source(AdditionalContracts.modDir.. "missions/mulcherMission/MulcherMission.lua");
source(AdditionalContracts.modDir.. "missions/rollerMission/RollerMission.lua");
source(AdditionalContracts.modDir.. "missions/fruitCollectMission/FruitCollectMission.lua");
source(AdditionalContracts.modDir.. "missions/universalMission/vehicleTransportMission/VehicleTransportMission.lua");
source(AdditionalContracts.modDir.. "missions/universalMission/supplyDeliveryBulkMission/SupplyDeliveryBulkMission.lua");
source(AdditionalContracts.modDir.. "missions/universalMission/supplyFieldGoodsMission/SupplyFieldGoodsMission.lua");
source(AdditionalContracts.modDir.. "missions/universalMission/UniversalMission.lua");

function orgOnDayChanged()
	if g_server ~= nil then		
		for typName, _ in pairs (g_additionalContractTypes.nextDayTyp) do
			if typName ~= nil then 
				if g_additionalContractTypes:canRunNextDayTyp(typName) then					
					if not g_additionalContractTypes:isMaxNextDayTyp(typName) then
						
					else
						g_additionalContractTypes:resetNextDayTyp(typName);
						g_additionalContractTypes:setNextDayTyp(typName);
					end;
					if g_additionalContractTypes:hasBalanceTyp(typName) then g_additionalContractTypes:enabledBalanceTyp(typName);end;
				else
					if g_additionalContractTypes:hasBalanceTyp(typName) then g_additionalContractTypes:disabledBalanceTyp(typName);end;
				end;			
			end;
		end;
	end;
end;
FSBaseMission.onDayChanged = Utils.appendedFunction(FSBaseMission.onDayChanged, orgOnDayChanged);

function orgLoadFromXMLFile(self, xmlFilename)
	if xmlFilename ~= nil then
		local xmlFile = XMLFile.load("missionsXML", xmlFilename, MissionManager.xmlSchemaSavegame);
		if xmlFile ~= nil then
			local version = xmlFile:getValue("missions#version");
			if version == MissionManager.VERSION then
				local numElements = {}
				for _, key in xmlFile:iterator("missions.*") do
					local missionTypeName = xmlFile:getElementName(key);
										
					if missionTypeName == "universalMission" and xmlFile:hasProperty(key.. "#typName") then					
						numElements[missionTypeName] = (numElements[missionTypeName] or 0) + 1;
						local missionTypeKey = string.format("missions.%s(%d)", missionTypeName, numElements[missionTypeName]-1);						
						
						local typName = xmlFile:getValue(missionTypeKey.. "#typName");						
						table.insert(g_additionalContractTypes.numElements, typName);					
					end;
				end				
			end;
			xmlFile:delete();			
		end;
    end;
end;
MissionManager.loadFromXMLFile = Utils.prependedFunction(MissionManager.loadFromXMLFile, orgLoadFromXMLFile);