LostCargoMission = {};
LostCargoMission.REGISTER_XML_PATHS = true;
LostCargoMission.NAME = "lostCargoMission";
LostCargoMission.MISSIONS_XML = {};
LostCargoMission.MAX_NUM_INSTANCE = 1;
LostCargoMission.NUM_INSTANCE = 0;
LostCargoMission.TARGET_TRIGGER_DISTANCE = 60; --dropoff trigger
LostCargoMission.MAX_NUM_DAY = {4,0,2}; --max,is,nextDay + ingame day
LostCargoMission.LAST_OBJECTS = {PALLETS_BALES_CONSUMABLES={}};

LostCargoMission.data = {	
	ownTable = {VEHICLE_USE_COST=10, classOverlay="tractor", typOverlay="unknownTrailer"};	
	reward = {dismiss=0, minTotalLimit=3500, min=1500, PER_METER=1, PER_OBJECT=1000, NUM_OBJECTS_PER_DRIVE=1};
	jobTypName = g_i18n:getText("contract_typ_lost_cargo");	
};

LostCargoMission.metadata = {
	interface = "FS25 ...", --new
	title = "Lost Cargo Contracts",
	notes = "Dieser Mod generiert Aufträge zum einsammeln verlorener Ladungen",
	author = "(by HappyLooser)",		
	build = 2,
	datum = "27.01.2026",
	update = "06.02.2026",
	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"
};

local LostCargoMission_mt = Class(LostCargoMission, AbstractMission);
InitObjectClass(LostCargoMission, "LostCargoMission");

function LostCargoMission.new(isServer, isClient)	
	local title = g_i18n:getText("contract_universal_title");
	local description = g_i18n:getText("typDescription_lost_cargo");	
	local self = AbstractMission.new(isServer, isClient, title, description, LostCargoMission_mt);
	
	--local uiScale = g_currentMission.hlUtils.getUiScale();
	--self.progressTitle = title.. " | ".. self.data.jobTypName;
	self.progressTitle = "*".. self.data.jobTypName;
	self.jobTypName = "*".. self.data.jobTypName;	
	
	self.loadingObjects = AdditionalContractsLoading.new();	
	self.triggers = {};
	self.objects = {};
	self.objectsAtTrigger = {};
	self.numFinished = 0;
	self.mapHotspots = {};
	self.farmlandId = FarmlandManager.NO_OWNER_FARM_ID;	--GUI does not do a nil check so just use 0
	--self.field = {fieldId=0,getName=function()return ""end}; -- or ... GUI does not do a nil check so just use 0
	LostCargoMission.NUM_INSTANCE = LostCargoMission.NUM_INSTANCE + 1;	
	return self;
end;

function LostCargoMission.registerSavegameXMLPaths(schema, key)
	LostCargoMission:superClass().registerSavegameXMLPaths(schema, key);	
	local lostCargoKey = string.format("%s.lostCargo", key);
	schema:register(XMLValueType.STRING, lostCargoKey .. "#missionConfig", "missionConfig name");
	schema:register(XMLValueType.INT, lostCargoKey .. "#objectConfig", "objcetConfig index");
	schema:register(XMLValueType.FLOAT, lostCargoKey .. "#pickupTriggerX", "pickup trigger position x");
	schema:register(XMLValueType.FLOAT, lostCargoKey .. "#pickupTriggerZ", "pickup trigger position z");
	schema:register(XMLValueType.STRING, lostCargoKey .. "#dropoffTriggerUniqueId", "dropoff trigger fake uniqueId");
	schema:register(XMLValueType.STRING, lostCargoKey .. "#dropoffTriggerTyp", "dropoff fake trigger typ");	
	schema:register(XMLValueType.INT, lostCargoKey .. "#numObjects", "Num objects spawned");
	schema:register(XMLValueType.STRING, lostCargoKey .. ".object(?)#uniqueId", "UniqueId of created object");
end;

function LostCargoMission:getOwnData()
	return self.data;
end;

function LostCargoMission:getNumObjects()
	return Utils.getNoNil(self.numObjects, #self.objects);
end;

function LostCargoMission:getMissionTypeName()
    return UniversalMission.NAME;
end;

function LostCargoMission:finish(success)
	LostCargoMission:superClass().finish(self, success);	
	if g_currentMission:getIsServer() then				
		if success then
			g_farmManager:getFarmById(self.farmId).stats:updateMissionDone();
		end;		
	end;
	if g_currentMission:getFarmId() == self.farmId then
		if success == MissionFinishState.SUCCESS then
			g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_OK, string.format(g_i18n:getText("contract_universal_finish"), self.jobTypName));
		elseif success == MissionFinishState.FAILED or success == MissionFinishState.CANCELED or success == MissionFinishState.TIMED_OUT then
			g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_CRITICAL, string.format(g_i18n:getText("contract_universal_failed"), self.jobTypName));
		end;
	end;
end;

function LostCargoMission:dismiss(mission)
	LostCargoMission:superClass().dismiss(self);
end;

function LostCargoMission:delete()	
	for _, object in pairs(self.objects) do
		self:deleteObject(object);
	end;
	self.objects = {};
	if LostCargoMission.NUM_INSTANCE > 0 then LostCargoMission.NUM_INSTANCE = LostCargoMission.NUM_INSTANCE - 1;end;
	self:destroyHotspots();
	self:removeMissionTriggers();
	LostCargoMission:superClass().delete(self);
end;

function LostCargoMission:deleteObject(object)
	if object ~= nil and object.rootNode ~= nil and entityExists(object.rootNode) then
		if self.status ~= MissionStatus.FINISHED and self.finishState == MissionFinishState.SUCCESS then
			g_currentMission.nodeToObject[object.rootNode]:setOwnerFarmId(self.farmId);
		else
			g_currentMission.nodeToObject[object.rootNode]:delete();
		end;
	end;
end;

function LostCargoMission:saveToXMLFile(xmlFile, key)	
	xmlFile:setValue(key .. "#typName", LostCargoMission.NAME);
	local lostCargoKey = string.format("%s.lostCargo", key);
	xmlFile:setValue(lostCargoKey .. "#missionConfig", self.missionConfig.name);
	xmlFile:setValue(lostCargoKey .. "#objectConfig", self.objectConfig.index);
	xmlFile:setValue(lostCargoKey .. "#pickupTriggerX", self.pickup.x);
	xmlFile:setValue(lostCargoKey .. "#pickupTriggerZ", self.pickup.z);
	xmlFile:setValue(lostCargoKey .. "#dropoffTriggerUniqueId", self.dropoff.uniqueId);
	xmlFile:setValue(lostCargoKey .. "#dropoffTriggerTyp", self.dropoff.triggerTyp);	
	xmlFile:setValue(lostCargoKey .. "#numObjects", self.numObjects);
		
	local int = 0
	for _, object in pairs(self.objects) do
		local uniqueId = object:getUniqueId();		
		local objectKey = string.format("%s.object(%d)", lostCargoKey, int);
		xmlFile:setValue(objectKey .. "#uniqueId", uniqueId);		
		int = int + 1;
	end;	
	LostCargoMission:superClass().saveToXMLFile(self, xmlFile, key);	
end;

function LostCargoMission:loadFromXMLFile(xmlFile, key)
	local lostCargoKey = string.format("%s.lostCargo", key);
	if not xmlFile:hasProperty(lostCargoKey .. "#missionConfig") then return false;end;
	local missionConfig = xmlFile:getValue(lostCargoKey .. "#missionConfig");	
	self.missionConfig = self:getLostCargoMissionConfigByName(missionConfig);
	if self.missionConfig == nil then
		return false;
	end;
	local objectConfig = xmlFile:getValue(lostCargoKey .. "#objectConfig");
	self.objectConfig = self:getLostCargoMissionObjectConfigByIndex(objectConfig);
	if self.objectConfig == nil then
		return false;
	end;
	self.numObjects = xmlFile:getValue(lostCargoKey .. "#numObjects");
	local pickupTriggerX = xmlFile:getValue(lostCargoKey .. "#pickupTriggerX");
	local pickupTriggerZ = xmlFile:getValue(lostCargoKey .. "#pickupTriggerZ");
	local dropoffTriggerUniqueId = xmlFile:getValue(lostCargoKey .. "#dropoffTriggerUniqueId");
	local dropoffTriggerTyp = xmlFile:getValue(lostCargoKey .. "#dropoffTriggerTyp");
	
	self.pendingLoadingData = {
		["dropoff"] = {uniqueId=dropoffTriggerUniqueId, triggerTyp=dropoffTriggerTyp};
		["pickup"] = {x=pickupTriggerX, z=pickupTriggerZ};
		["objects"] = {};
	};
	
	--if self.status == MissionStatus.RUNNING then
		local int = 0;
		while true do
			local objectKey = string.format("%s.object(%d)", lostCargoKey, int);
			if not xmlFile:hasProperty(objectKey .. "#uniqueId") then
				break;
			end;
			local uniqueId = xmlFile:getValue(objectKey .. "#uniqueId");
			table.insert(self.pendingLoadingData.objects, uniqueId);			
			int = int + 1;			
		end;
	--end
	self:setLeasingVehicles();
	LostCargoMission.LAST_OBJECTS[self.missionConfig.typ][objectConfig] = objectConfig;
	if not LostCargoMission:superClass().loadFromXMLFile(self, xmlFile, key) then
		return false;
	end;
	return true;
end;

function LostCargoMission:loadMapData(xmlFile, key, baseDirectory)
	
end;

function LostCargoMission:unloadMapData()
	
end;

function LostCargoMission:onSavegameLoaded()
	if self.pendingLoadingData ~= nil then
		local dropoff = g_additionalContractMapData:getVirtualTrigger(self.pendingLoadingData.dropoff.uniqueId, "lostCargo");
		if dropoff ~= nil then 
			self.dropoff = dropoff;
			if g_server ~= nil then
				local trigger = UniversalMissionFakeTrigger.new(dropoff.triggerId, 1, g_dedicatedServer == nil, true);			
				self:addMissionTrigger(trigger);
				if trigger.mission == nil then trigger:setMission(self);end;
			end;
		end;
		local pickup = g_additionalContractSplineManager:getSplineByPosition(self.pendingLoadingData.pickup.x, self.pendingLoadingData.pickup.z); --g_additionalContractMapData:getSplineByPosition(self.pendingLoadingData.pickup.x, self.pendingLoadingData.pickup.z); --old
		if pickup ~= nil then
			self.pickup = pickup; --on server
		else
			self.pickup = {x=self.pendingLoadingData.pickup.x, z=self.pendingLoadingData.pickup.z}; --on client
		end;
		for _, uniqueId in ipairs(self.pendingLoadingData.objects) do
			local vehicle = g_currentMission.vehicleSystem:getVehicleByUniqueId(uniqueId);
			if vehicle ~= nil then
				self.loadingObjects:setCanBeReset(self.objectConfig, vehicle); --replace can be reset
				self.objects[vehicle.rootNode] = vehicle;
			end;
		end;
		self:setTypDescription();		
	end;	
	
	LostCargoMission:superClass().onSavegameLoaded(self)
end;

function LostCargoMission:onStartMap(args)
	
end;

function LostCargoMission.canRun()	
	if (g_server ~= nil and not g_additionalContractSplineManager:hasSplines()) or #LostCargoMission.MISSIONS_XML == 0 then 
		g_additionalContractTypes:removeBalanceTyp(LostCargoMission.NAME);
		g_additionalContractTypes:removeRandomTyp(LostCargoMission.NAME);
		g_additionalContractTypes:removeNextDayTyp(LostCargoMission.NAME);
		return false;
	end;
	return not g_additionalContractTypes:isMaxNextDayTyp(LostCargoMission.NAME) and LostCargoMission.NUM_INSTANCE < LostCargoMission.MAX_NUM_INSTANCE;
end;

function LostCargoMission:getTriggerInfo(index, isPickup) --md mod
	local triggers = self.missionConfig.dropoffTriggers;
	if isPickup then
		triggers = self.missionConfig.pickupTriggers;
	end;
	for _, info in ipairs(triggers) do
		if info.index == index then
			return info;
		end;
	end;
	return {};
end;

function LostCargoMission:getTriggerTitle(index, isPickup) --md mod
	return "";
	--local info = self:getTriggerInfo(index, isPickup);
	--return info == nil and "" or g_i18n:convertText(Utils.getNoNil(info.title, ""));
end;

--function LostCargoMission:getActiveTriggers() --md mod
--	return self.pickup, self.dropoff, self:getTriggerTitle(self.dropoff, false);
--end;

function LostCargoMission:getTriggerHotspot(isPickup) --md mod
	if isPickup then
		return nil; --self.pickup;
	end;
	return nil; --self.dropoff;
end;

function LostCargoMission:getNPC()	
	local npc, subData = g_additionalContractNpcManager:getNPCByName("ADC_HELPER", "neutralall");
	if npc == nil then 
		npc = g_npcManager:getNPCByIndex(1);
	elseif subData ~= nil then
		local subTitle = g_i18n:getText("ui_farmlandScreen");
		npc.title = g_i18n:getText(subData.title).. " (".. tostring(subTitle).. ")";
		local imageFilename = Utils.getFilename(subData.imageFilename, AdditionalContracts.modDir);
		if imageFilename ~= nil then npc.imageFilename = imageFilename;end;
	end;
	return npc;
end;

function LostCargoMission:getRewards()
	return LostCargoMission.data.reward;
end;

function LostCargoMission:setOwnTable(ownTable)
	self.data.ownTable = ownTable;
end;

function LostCargoMission:getOnwTable()
	return self.data.ownTable;
end;

function LostCargoMission:setOwnTableValue(key, value)
	if key == nil then return;end;
	if self.data.ownTable[key] == nil then self.data.ownTable[key] = {};end;
	self.data.ownTable[key] = value;
end;

function LostCargoMission:getOwnTableValue(key)
	if key == nil or self.data.ownTable[key] == nil then return;end;
	return self.data.ownTable[key];
end;

function LostCargoMission:start(spawnVehicles)	
	if not self:loadObjects() then
		return false;
	end;
	if not LostCargoMission:superClass().start(self, spawnVehicles) then
		return false;
	end;
	return true;	
end;

function LostCargoMission:init()	
	--if not LostCargoMission:superClass().init(self) then
	--	return false;
	--end;
	
	local lostCargoMission = table.getRandomElement(LostCargoMission.MISSIONS_XML);
	if lostCargoMission == nil then return false;end;
	
	if lostCargoMission.objects ~= nil and #LostCargoMission.LAST_OBJECTS[lostCargoMission.typ] >= #lostCargoMission.objects then LostCargoMission.LAST_OBJECTS[lostCargoMission.typ] = {};end;
	
	local object = g_additionalContractUtils:getRandomElement(lostCargoMission.objects, 2, LostCargoMission.LAST_OBJECTS[lostCargoMission.typ], "index"); --table.getRandomElement(lostCargoMission.objects);
	if object == nil then return false;end;
	local dropoffTrigger = g_additionalContractMapData:getVirtualTrigger(nil, "lostCargo");
	if dropoffTrigger == nil then return false;end;	
	local pickupTrigger = g_additionalContractSplineManager:getRandomSpline(object.groundType); --g_additionalContractMapData:getRandomSpline(object.groundType);	--old
	if pickupTrigger == nil then return false;end;	
	self.numObjects = g_additionalContractUtils:getIntegerToVector(object.minMax);	
	
	if object.category ~= nil then
		if object.category == "category_pallets" then
			if not g_currentMission.slotSystem:getCanAddLimitedObjects(SlotSystem.LIMITED_OBJECT_PALLET, self.numObjects) then return false;end;
		end;
	end;
	LostCargoMission.LAST_OBJECTS[lostCargoMission.typ][object.index] = object.index;
	
	self.pickup = pickupTrigger;
	self.dropoff = dropoffTrigger;
	local trigger = UniversalMissionFakeTrigger.new(self.dropoff.triggerId, 1, g_dedicatedServer == nil, true);
	--trigger.index = 1;
	self:addMissionTrigger(trigger);
	if trigger.mission == nil then trigger:setMission(self);end;		
	self.missionConfig = lostCargoMission;
	self.objectConfig = object;		
	self:setTypDescription();
	self.reward = self:calculateReward(object.rewardScale);
	self:setMinReward();
	self:setLeasingVehicles();	
	return LostCargoMission:superClass().init(self);		
end;

function LostCargoMission:setTypDescription()
	if self.objectConfig.typDescription ~= nil then
		local typDescription = g_i18n:getText(self.objectConfig.typDescription);
		if self.numObjects > 1 then 
			local typDescriptionMultiple = g_i18n:getText(self.objectConfig.typDescription.. "_multiple");
			if typDescriptionMultiple ~= nil and not string.find(typDescriptionMultiple:lower(), "missing") then typDescription = typDescriptionMultiple;end;
		end;
		self.description = typDescription;
	end;
end;

function LostCargoMission:addMissionTrigger(trigger)	
	self.triggers[trigger.index] = trigger;	
end;

function LostCargoMission:removeMissionTrigger(trigger)	
	if trigger ~= nil and trigger.index ~= nil then 
		self.triggers[trigger.index]:delete();
		self.triggers[trigger.index] = nil;		
	end;	
end;

function LostCargoMission:removeMissionTriggers()
	for _, trigger in pairs(self.triggers) do
		trigger:delete();		
	end;
	self.triggers = {};	
end;

function LostCargoMission:writeStream(streamId, connection) --server
	streamWriteUInt8(streamId, self.numObjects);
	streamWriteUInt8(streamId, self.missionConfig.id);
	streamWriteUInt8(streamId, self.objectConfig.index);	
	----	
	streamWriteString(streamId, tostring(self.dropoff.triggerTyp));	
	streamWriteString(streamId, tostring(self.dropoff.uniqueId));
	
	
	
	streamWriteFloat32(streamId, self.pickup.x);
	streamWriteFloat32(streamId, self.pickup.z);	
	LostCargoMission:superClass().writeStream(self, streamId, connection);
end;

function LostCargoMission:readStream(streamId, connection) --client
	self.numObjects = streamReadUInt8(streamId);	
	self.missionConfig = self:getLostCargoMissionConfigById(streamReadUInt8(streamId));
	self.objectConfig = self:getLostCargoMissionObjectConfigByIndex(streamReadUInt8(streamId));
	self:setTypDescription();
	self:setLeasingVehicles();
	----
	local dropoffTriggerTyp = streamReadString(streamId);
	local dropoffTriggerUniqueId = streamReadString(streamId);	
	
	local pickupTriggerX = streamReadFloat32(streamId);		
	local pickupTriggerZ = streamReadFloat32(streamId);
		
	self.pendingLoadingData = {
		["dropoff"] = {uniqueId=dropoffTriggerUniqueId, triggerTyp=dropoffTriggerTyp};
		["pickup"] = {x=pickupTriggerX, z=pickupTriggerZ};
	};	
	LostCargoMission:superClass().readStream(self, streamId, connection);
end;

function LostCargoMission:triggerUpdate(trigger, dt)	
	if self.status == MissionStatus.RUNNING and trigger.triggerId ~= nil and self.pickup ~= nil then		
		local xD, yD, zD = self.pickup.x, 0, self.pickup.z;		
		for loadingNodeId, object in pairs(self.objects) do			
			if object ~= nil and entityExists(loadingNodeId) then
				local nodeId = object.rootNode or object.nodeId;
				if nodeId ~= nil and (self.objectsAtTrigger[nodeId] == nil or not self.objectsAtTrigger[nodeId]) then				
					local xV, yV, zV = getWorldTranslation(nodeId);	
					local distance = g_additionalContractUtils:getObjectDistance( {x=xD, y=yD, z=zD}, {x=xV, y=yV, z=zV} );
					if distance > LostCargoMission.TARGET_TRIGGER_DISTANCE then
						self.numFinished = self.numFinished + 1;
						self.objectsAtTrigger[nodeId] = true;
					end;			
				end;
			end;
		end;
	end;	
end;

function LostCargoMission:getLostCargoMissionConfigById(id)
	for _, lostCargoMission in pairs(LostCargoMission.MISSIONS_XML) do
		if lostCargoMission.id == id then
			return lostCargoMission;
		end;
	end;
	return nil;
end;

function LostCargoMission:getLostCargoMissionConfigByName(name)
	for _, lostCargoMission in pairs(LostCargoMission.MISSIONS_XML) do
		if lostCargoMission.name == name then
			return lostCargoMission;
		end;
	end;
	return nil;
end;

function LostCargoMission:getLostCargoMissionObjectConfigByIndex(index)
	for _, object in pairs(self.missionConfig.objects) do
		if object.index == index then
			return object;
		end;
	end;	
end;

function LostCargoMission:setMinReward()
	if self.reward < LostCargoMission.data.reward.min then self.reward = LostCargoMission.data.reward.min;end;	
end;

function LostCargoMission:setLeasingVehicles()	
	if self.missionConfig.typ ~= nil then
		--if g_additionalContractUtils:hasOtherMods("universalAutoload") then			
		--	if self.missionConfig.typ == "PALLETS_BALES_CONSUMABLES" and self.numObjects <= 2 then 
		--		self.objectConfig.leasingSize = "small_lostCargoMission";
		--		self.objectConfig.leasingVariant = "SMALL_AUTOLOAD";
		--	else	
		--		self.objectConfig.leasingSize = "medium_lostCargoMission";
		--		self.objectConfig.leasingVariant = "MEDIUM_AUTOLOAD";
		--	end;			
		--else
			if self.missionConfig.typ == "PALLETS_BALES_CONSUMABLES" and self.numObjects <= 2 then
				--if category == "category_pallets" then
				self.objectConfig.leasingSize = "small_lostCargoMission";
				self.objectConfig.leasingVariant = "SMALL_DEFAULT";			
			else
				--if category == "category_pallets" then
				self.objectConfig.leasingSize = "medium_lostCargoMission";
				self.objectConfig.leasingVariant = "MEDIUM_DEFAULT";
			end;
		--end;
	end;
end;

function LostCargoMission:getRewardByFillType(rewardScale)
	local fillType = nil;
	if self.objectConfig.fillType ~= nil then fillType = g_fillTypeManager:getFillTypeByName(self.objectConfig.fillType);end;
	if fillType == nil then return LostCargoMission.data.reward.min*rewardScale;end;
	local _, highestPrice = g_additionalContractMapData:getSellingStationWithHighestPrice(fillType.index);
	if highestPrice*self.numObjects < LostCargoMission.data.reward.min then return LostCargoMission.data.reward.min*self.numObjects*rewardScale;else return highestPrice*self.numObjects;end;
end;

function LostCargoMission:calculateReward(rewardScale)	
	local distance = LostCargoMission.TARGET_TRIGGER_DISTANCE;
	local driveReward = self.numObjects / LostCargoMission.data.reward.NUM_OBJECTS_PER_DRIVE;
	local reward = (math.ceil(driveReward) * LostCargoMission.data.reward.PER_METER * distance + self.numObjects * LostCargoMission.data.reward.PER_OBJECT) * rewardScale;
	local rewardFillType = self:getRewardByFillType(rewardScale);
	if reward + rewardFillType < LostCargoMission.data.reward.minTotalLimit then return math.random(LostCargoMission.data.reward.minTotalLimit, LostCargoMission.data.reward.minTotalLimit+500);else return reward;end;	
end;

function LostCargoMission:getReward()
	local reward = self.reward; -- * g_additionalContractTypes.multiplier;
	if reward < self.reward then reward = self.reward;end;
	return reward;
end;

function LostCargoMission:calculateStealingCost()	
	return 0;
end;

function LostCargoMission:getStealingCosts()	
	return self:calculateStealingCost();
end;

--function LostCargoMission:getVehicleGroupFromIdentifier(identifier, ...) --no leasing vehicles
--   local vehicles, rewardScale, errorMessage, vehicleGroup = LostCargoMission:superClass().getVehicleGroupFromIdentifier(self, identifier, ...); --by giants
--    return {}, rewardScale, errorMessage, vehicleGroup;
--end;

--function LostCargoMission:hasLeasableVehicles() --no leasing vehicles
--    return false;
--end;

function LostCargoMission:getVehicleSize()	
	if self.objectConfig == nil or self.objectConfig.leasingSize == nil then return nil;end;
	return self.objectConfig.leasingSize;
end;

function LostCargoMission:getVehicleVariant()	
	if self.objectConfig == nil or self.objectConfig.leasingVariant == "NONE" then return nil;end;
	local leasingSize = self:getVehicleSize();	
	if leasingSize == nil or leasingSize == "NONE" then return nil;end;	
	return self.objectConfig.leasingVariant;	
end;

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

function LostCargoMission:getFarmlandId()
   return self.farmlandId or FarmlandManager.NO_OWNER_FARM_ID; --GUI does not do a nil check so just use 0 / Error: Running LUA method 'update'. dataS/scripts/gui/InGameMenuContractsFrame.lua:572: attempt to compare nil < nil
end;

function LostCargoMission:getDetails()	
	local details = LostCargoMission:superClass().getDetails(self);
	if self.status == MissionStatus.RUNNING then
		local category = {
			["title"] = tostring(self.numObjects).. "x ".. g_i18n:getText(self.objectConfig.category);
			["value"] = g_i18n:getText(self.objectConfig.typTitle);
		};
		table.insert(details, category);	
	end;
	return details;
end;

function LostCargoMission:update(dt)
	LostCargoMission:superClass().update(self, dt);	
	if self.status == MissionStatus.RUNNING and g_localPlayer ~= nil and g_localPlayer.farmId == self.farmId and not self:hasHotspots() then		
		self:createHotspots();		
	end;	
end;

function LostCargoMission:getMapHotspots()
	return self.mapHotspots;
end;

function LostCargoMission:hasHotspots()
	return self.pickupHotspot ~= nil and self.dropoffHotspot == nil and g_additionalContractMapData:isDataLoaded();	
end;

function LostCargoMission:createHotspots()
	if self:getDropoffTrigger() == nil and self.pendingLoadingData ~= nil and self.pendingLoadingData.dropoff ~= nil then self:setDropoffTrigger();end;
	--if self:getDropoffTrigger() == nil then return;end; --mp waiting login
	--if self.dropoffHotspot == nil then self.dropoffHotspot = self:createHotspot(self:getDropoffTrigger(), "dropoff", self.objectConfig.dropoffHotspotTyp, false, "orangeRed");end;	
	
	if self:getPickupTrigger() == nil and self.pendingLoadingData ~= nil and self.pendingLoadingData.pickup ~= nil then self:setPickupTrigger();end;
	if self:getPickupTrigger() == nil then return;end; --mp waiting login
	if self.pickupHotspot == nil then self.pickupHotspot = self:createHotspot(self:getPickupTrigger(), "pickup", self.objectConfig.pickupHotspotTyp, false, "yellow");end;	
end;

function LostCargoMission:destroyHotspots()
	if self.pickupHotspot ~= nil then
		g_currentMission:removeMapHotspot(self.pickupHotspot);
		self.pickupHotspot:delete();
		self.pickupHotspot = nil;
	end;
	if self.dropoffHotspot ~= nil then
		g_currentMission:removeMapHotspot(self.dropoffHotspot);
		self.dropoffHotspot:delete();
		self.dropoffHotspot = nil;
	end;
end;

function LostCargoMission:visibleHotspot(hotspot, state)
	if hotspot == "pickupHotspot" then
		if self.pickupHotspot ~= nil then			
			self.pickupHotspot:setVisible(state);			
		end;
	elseif hotspot == "dropoffHotspot" then
		if self.dropoffHotspot ~= nil then			
			self.dropoffHotspot:setVisible(state);			
		end;
	end;
end;

function LostCargoMission:setPickupTrigger()
	self.pickup = {x=self.pendingLoadingData.pickup.x, z=self.pendingLoadingData.pickup.z};
	self.pendingLoadingData.pickup = nil;
end;

function LostCargoMission:getPickupTrigger()	
	return self.pickup;	
end;

function LostCargoMission:setDropoffTrigger()	
	self.dropoff = g_additionalContractMapData:getVirtualTrigger(self.pendingLoadingData.dropoff.uniqueId, "lostCargo");	
	self.pendingLoadingData.dropoff = nil;
end;

function LostCargoMission:getDropoffTrigger()	
	return self.dropoff;	
end;

function LostCargoMission:createHotspot(trigger, typ, hotspotTyp, blinking, color, fillTypeName)
	if trigger == nil or not g_additionalContractUtils:isLoadedHotspotOverlays() then return nil;end; --MP
	local x, _, z;
	if trigger.x ~= nil and trigger.z ~= nil then x = trigger.x;z = trigger.z;end;
	if x == nil then return nil;end;
	local mapHotspot = UniversalMissionHotspot.new(nil, self.farmId, typ, hotspotTyp, blinking, color, fillTypeName);
	mapHotspot:setWorldPosition(x, z);
	g_currentMission:addMapHotspot(mapHotspot);		
	local contractsFrameMapHotspot = UniversalCircleMissionHotspot.new(nil, "yellow", LostCargoMission.TARGET_TRIGGER_DISTANCE); --fake for InGameMenuContractsFrame
	contractsFrameMapHotspot:setWorldPosition(x, z);
	table.addElement(self.mapHotspots, contractsFrameMapHotspot);
	return mapHotspot;
end;

function LostCargoMission:getCompletion()
	return self.numFinished / self.numObjects;
end;

function LostCargoMission:loadObjects()
	local trigger = self:getPickupTrigger();
	local objectConfig = self.objectConfig;	
	if objectConfig == nil then
		return false;
	end;
	local canSpawn, objectsSpawnPosition = g_additionalContractSpawnManager:getObjectsSpawnPosition(trigger, nil, self.numObjects, objectConfig, nil, 0.5); --g_additionalContractUtils:getObjectsSpawnPosition(trigger, nil, self.numObjects, objectConfig, nil, 0.5); --old
	if not canSpawn or #objectsSpawnPosition <= 0 then return false;end;
	for o=1, #objectsSpawnPosition do		
		self.loadingObjects:spawnObject(self, objectsSpawnPosition[o], trigger, objectConfig);		
	end;	
	return true;
end;

function LostCargoMission:loadInit()
	g_additionalContractTypes:insertRandomTyp(LostCargoMission.NAME);
	g_additionalContractTypes:insertBalanceTyp(LostCargoMission.NAME);
	g_additionalContractTypes:insertNextDayTyp(LostCargoMission.NAME, LostCargoMission.MAX_NUM_DAY);	
	local xmlFilename = Utils.getFilename("missions/universalMission/lostCargoMission/missions.xml", AdditionalContracts.modDir);
	if xmlFilename ~= nil and xmlFilename ~= "" then LostCargoMission.MISSIONS_XML = g_additionalContractUtils:loadMissionsXml(xmlFilename);end;
	xmlFilename = Utils.getFilename("missionVehicles/lostCargoMissionVehicles.xml", AdditionalContracts.modDir)
	if xmlFilename ~= nil and xmlFilename ~= "" then g_missionManager:addPendingMissionVehiclesFile(xmlFilename, AdditionalContracts.modDir);end;
end;

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

function LostCargoMission:getClassTypOverlay(args)
	local classOverlay = "tractor";
	local typOverlay = "unknownTrailer";
	if self.objectConfig.classOverlay ~= nil then classOverlay = self.objectConfig.classOverlay;end;
	if self.objectConfig.typOverlay ~= nil then typOverlay = self.objectConfig.typOverlay;end;	
	return classOverlay, typOverlay;
end;

---balance system---

---balance system---

g_additionalContractTypes:registerTyp(LostCargoMission, LostCargoMission.NAME);