VehicleTransferMission = {};
VehicleTransferMission.REGISTER_XML_PATHS = true;
VehicleTransferMission.NAME = "vehicleTransferMission";
VehicleTransferMission.MISSIONS_XML = {};
VehicleTransferMission.MAX_NUM_INSTANCE = 1;
VehicleTransferMission.NUM_INSTANCE = 0;
VehicleTransferMission.TARGET_TRIGGER_DISTANCE = 300; --dropoff trigger
VehicleTransferMission.MAX_NUM_DAY = {8,0,1}; --max,is,nextDay + ingame day

VehicleTransferMission.data = {	
	ownTable = {classOverlay="tractor", typOverlay="unknownTrailer"};	
	reward = {dismiss=0, min=2000, PER_METER=3, PER_OBJECT=1100, NUM_OBJECTS_PER_DRIVE=1};
	jobTypName = g_i18n:getText("contract_typ_vehicle_transfer");	
};

VehicleTransferMission.metadata = {
	interface = "FS25 ...", --new
	title = "Vehicle Transfer Contracts",
	notes = "Dieser Mod generiert Fahrzeug Transfer Aufträge.",
	author = "(by HappyLooser)",		
	build = 3,
	datum = "23.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 VehicleTransferMission_mt = Class(VehicleTransferMission, AbstractMission);
InitObjectClass(VehicleTransferMission, "VehicleTransferMission");

function VehicleTransferMission.new(isServer, isClient)	
	local title = g_i18n:getText("contract_universal_title");
	local description = g_i18n:getText("typDescription_vehicle_transfer_customer");	
	local self = AbstractMission.new(isServer, isClient, title, description, VehicleTransferMission_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
	VehicleTransferMission.NUM_INSTANCE = VehicleTransferMission.NUM_INSTANCE + 1;	
	return self;
end;

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

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

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

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

function VehicleTransferMission:finish(success)
	VehicleTransferMission: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 VehicleTransferMission:dismiss(mission)
	VehicleTransferMission:superClass().dismiss(self);
end;

function VehicleTransferMission:delete()	
	self:deleteObjects();	
	if VehicleTransferMission.NUM_INSTANCE > 0 then VehicleTransferMission.NUM_INSTANCE = VehicleTransferMission.NUM_INSTANCE - 1;end;
	self:destroyHotspots();
	self:removeMissionTriggers();
	VehicleTransferMission:superClass().delete(self);
end;

function VehicleTransferMission:deleteObjects()
	for _, object in pairs(self.objects) do
		self:deleteObject(object);
	end;
	self.objects = {};
end;

function VehicleTransferMission:deleteObject(object)
	if object ~= nil and object.rootNode ~= nil and entityExists(object.rootNode) then
		g_currentMission.nodeToObject[object.rootNode]:delete();			
	end;
end;

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

function VehicleTransferMission:loadFromXMLFile(xmlFile, key)
	local vehicleTransferKey = string.format("%s.vehicleTransfer", key);
	if not xmlFile:hasProperty(vehicleTransferKey .. "#missionConfig") then return false;end;
	local missionConfig = xmlFile:getValue(vehicleTransferKey .. "#missionConfig");	
	self.missionConfig = self:getTransferMissionConfigByName(missionConfig);
	if self.missionConfig == nil then
		return false;
	end;
	local objectConfig = xmlFile:getValue(vehicleTransferKey .. "#objectConfig");
	self.objectConfig = self:getTransferMissionObjectConfigByIndex(objectConfig);
	if self.objectConfig == nil then
		return false;
	end;
	self.numObjects = xmlFile:getValue(vehicleTransferKey .. "#numObjects");
	local pickupTriggerX = xmlFile:getValue(vehicleTransferKey .. "#pickupTriggerX");
	local pickupTriggerZ = xmlFile:getValue(vehicleTransferKey .. "#pickupTriggerZ");
	local dropoffTriggerUniqueId = xmlFile:getValue(vehicleTransferKey .. "#dropoffTriggerUniqueId");
	local dropoffTriggerTyp = xmlFile:getValue(vehicleTransferKey .. "#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)", vehicleTransferKey, 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	
	if not VehicleTransferMission:superClass().loadFromXMLFile(self, xmlFile, key) then
		return false;
	end;
	return true;
end;

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

function VehicleTransferMission:unloadMapData()
	
end;

function VehicleTransferMission:onSavegameLoaded()
	if self.pendingLoadingData ~= nil then
		local dropoff = g_additionalContractMapData:getTriggerByUniqueId(self.pendingLoadingData.dropoff.uniqueId);
		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_additionalContractMapData:getStorePlaceTriggerByPosition(self.pendingLoadingData.pickup.x, self.pendingLoadingData.pickup.z);
		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:setMaxSpeed(self.objectConfig, vehicle); --replace maxspeed
				self.loadingObjects:setCanBeReset(self.objectConfig, vehicle); --replace can be reset
				self.objects[vehicle.rootNode] = vehicle;
			end;
		end;
		self:setTypDescription();
	end;	
	
	VehicleTransferMission:superClass().onSavegameLoaded(self)
end;

function VehicleTransferMission:onStartMap(args)
	
end;

function VehicleTransferMission.canRun()	
	if (g_server ~= nil and g_additionalContractMapData:getStorePlaceTrigger() == nil) or not g_additionalContractMapData:hasTrigger("sellingStation") or #VehicleTransferMission.MISSIONS_XML == 0 then 
		g_additionalContractTypes:removeBalanceTyp(VehicleTransferMission.NAME);
		g_additionalContractTypes:removeRandomTyp(VehicleTransferMission.NAME);
		g_additionalContractTypes:removeNextDayTyp(VehicleTransferMission.NAME);
		return false;
	end;
	return not g_additionalContractTypes:isMaxNextDayTyp(VehicleTransferMission.NAME) and VehicleTransferMission.NUM_INSTANCE < VehicleTransferMission.MAX_NUM_INSTANCE;
end;

function VehicleTransferMission: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 VehicleTransferMission: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 VehicleTransferMission:getActiveTriggers() --md mod
--	return self.pickup, self.dropoff, self:getTriggerTitle(self.dropoff, false);
--end;

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

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

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

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

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

function VehicleTransferMission: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 VehicleTransferMission:getOwnTableValue(key)
	if key == nil or self.data.ownTable[key] == nil then return;end;
	return self.data.ownTable[key];
end;

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

function VehicleTransferMission:init()	
	--if not VehicleTransferMission:superClass().init(self) then
	--	return false;
	--end;
	
	local transferMission = table.getRandomElement(VehicleTransferMission.MISSIONS_XML);
	if transferMission == nil then return false;end;
	local object = table.getRandomElement(transferMission.objects);
	if object == nil then return false;end;
	local dropoffTrigger = g_additionalContractMapData:getRandomTriggerNoFarmId("sellingStation", nil, false, nil);
	if dropoffTrigger == nil then return false;end;
	local distance = VehicleTransferMission.TARGET_TRIGGER_DISTANCE;
	if object.targetTriggerDistance ~= nil then distance = object.targetTriggerDistance;end;
	--local pickupTrigger = g_additionalContractMapData:getRandomSplineByMinDistance(dropoffTrigger.x, dropoffTrigger.z, distance, object.groundType);	
	local pickupTrigger = g_additionalContractMapData:getStorePlaceTrigger(2, true);
	if pickupTrigger == nil then return false;end;	
	self.numObjects = g_additionalContractUtils:getIntegerToVector(object.minMax);	
	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 = transferMission;
	self.objectConfig = object;		
	self:setTypDescription();
	self.reward = self:calculateReward(object.rewardScale);
	self:setMinReward();
	self:setLeasingVehicles(object.leasingSize, object.leasingVariant);	
	return VehicleTransferMission:superClass().init(self);		
end;

function VehicleTransferMission: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 VehicleTransferMission:addMissionTrigger(trigger)	
	self.triggers[trigger.index] = trigger;	
end;

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

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

function VehicleTransferMission: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));
	
	NetworkUtil.writeNodeObject(streamId, g_currentMission.placeableSystem:getPlaceableByUniqueId(self.dropoff.uniqueId));
	
	streamWriteFloat32(streamId, self.pickup.x);
	streamWriteFloat32(streamId, self.pickup.z);	
	VehicleTransferMission:superClass().writeStream(self, streamId, connection);
end;

function VehicleTransferMission:readStream(streamId, connection) --client
	self.numObjects = streamReadUInt8(streamId);	
	self.missionConfig = self:getTransferMissionConfigById(streamReadUInt8(streamId));
	self.objectConfig = self:getTransferMissionObjectConfigByIndex(streamReadUInt8(streamId));
	self:setTypDescription();	
	----
	local dropoffTriggerTyp = streamReadString(streamId);
	local dropoffTriggerUniqueId = streamReadString(streamId);
	
	local dropoffNodeObjectId = NetworkUtil.readNodeObjectId(streamId);
	
	local pickupTriggerX = streamReadFloat32(streamId);		
	local pickupTriggerZ = streamReadFloat32(streamId);
		
	self.pendingLoadingData = {
		["dropoff"] = {uniqueId=dropoffTriggerUniqueId, nodeObjectId=dropoffNodeObjectId, triggerTyp=dropoffTriggerTyp};
		["pickup"] = {x=pickupTriggerX, z=pickupTriggerZ};
	};	
	VehicleTransferMission:superClass().readStream(self, streamId, connection);
end;

function VehicleTransferMission:triggerUpdate(trigger, dt)	
	if self.status == MissionStatus.RUNNING and trigger.triggerId ~= nil then		
		local xD, yD, zD = getWorldTranslation(trigger.triggerId);		
		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 < 30 then
						self.numFinished = self.numFinished + 1;
						self.objectsAtTrigger[nodeId] = true;
					end;			
				end;
			end;
		end;
	end;	
end;

function VehicleTransferMission:getTransferMissionConfigById(id)
	for _, transferMission in pairs(VehicleTransferMission.MISSIONS_XML) do
		if transferMission.id == id then
			return transferMission;
		end;
	end;
	return nil;
end;

function VehicleTransferMission:getTransferMissionConfigByName(name)
	for _, transferMission in pairs(VehicleTransferMission.MISSIONS_XML) do
		if transferMission.name == name then
			return transferMission;
		end;
	end;
	return nil;
end;

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

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

function VehicleTransferMission:setLeasingVehicles(size, variant)	
	--if self.vehicleGroupIdentifier ~= nil then
	--	if variant == "NONE" then self.vehiclesToLoad = nil;self.vehicleGroupIdentifier = 1;else self.vehiclesToLoad, self.vehicleGroupIdentifier = self:getVehicleGroup();end;
	--end;	
end;

function VehicleTransferMission:calculateReward(rewardScale)	
	local pickupTrigger = self:getPickupTrigger();
	local dropoffTrigger = self:getDropoffTrigger();
	local distance = g_additionalContractUtils:getObjectDistance( {x=dropoffTrigger.x, z=dropoffTrigger.z}, {x=pickupTrigger.x, z=pickupTrigger.z} );
	local driveReward = self.numObjects / VehicleTransferMission.data.reward.NUM_OBJECTS_PER_DRIVE;
	return (math.ceil(driveReward) * VehicleTransferMission.data.reward.PER_METER * distance + self.numObjects * VehicleTransferMission.data.reward.PER_OBJECT) * rewardScale;	
end;

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

function VehicleTransferMission:calculateStealingCost()	
	return 0;
end;

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

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

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

--function VehicleTransferMission:getVehicleSize()	
--	return "small";
--end;

--function VehicleTransferMission:getVehicleVariant()	
--	return 1;	
--end;

function VehicleTransferMission:getVehicleCosts()
	return 0;
end;

function VehicleTransferMission: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 VehicleTransferMission:getDetails()	
	local details = VehicleTransferMission:superClass().getDetails(self);	
	local pickupTrigger = {
		["title"] = g_i18n:getText("contract_title");
		["value"] = g_i18n:getText("shopItem_workshop")
	}
	local dropoffTrigger = self:getDropoffTrigger();	
	if dropoffTrigger ~= nil then
		local sellingStation = {
			["title"] = g_i18n:getText("ai_parameterGroupTitlePosition"); 
			["value"] = tostring(dropoffTrigger.name);
		};	
		table.insert(details, sellingStation);
	end;
	local objectName = "";
	for _, object in pairs(self.objects) do			
		if object ~= nil then objectName = object:getFullName();break;end;
	end;
	if objectName:len() == 0 or objectName == "nil" or objectName == "Unknown" then objectName = g_i18n:getText(self.objectConfig.typTitle);end;
	local category = {
		["title"] = g_i18n:getText("typeDesc_vehicle");
		["value"] = tostring(objectName);
	};
	table.insert(details, category);
	return details;
end;

function VehicleTransferMission:update(dt)
	VehicleTransferMission: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;
	if self.status == MissionStatus.RUNNING then
		--ai helper not possible + (AD) ?
	end;
end;

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

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

function VehicleTransferMission: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, "ls15");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, "ls15");end;	
end;

function VehicleTransferMission: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 VehicleTransferMission: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 VehicleTransferMission:setPickupTrigger()
	self.pickup = {x=self.pendingLoadingData.pickup.x, z=self.pendingLoadingData.pickup.z};
	self.pendingLoadingData.pickup = nil;
end;

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

function VehicleTransferMission:setDropoffTrigger()	
	if g_currentMission.missionDynamicInfo.isMultiplayer then
		self.dropoff = g_additionalContractMapData:getTriggerByNetwork(self.pendingLoadingData.dropoff);
	else
		self.dropoff = g_additionalContractMapData:getTriggerByUniqueId(self.pendingLoadingData.dropoff.uniqueId);
	end;
	if self.dropoff ~= nil then self.pendingLoadingData.dropoff = nil;end;
end;

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

function VehicleTransferMission: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.triggerId ~= nil then x, _, z = getWorldTranslation(trigger.triggerId);elseif 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(); --fake for InGameMenuContractsFrame
	contractsFrameMapHotspot:setWorldPosition(x, z);
	table.addElement(self.mapHotspots, contractsFrameMapHotspot);
	return mapHotspot;
end;

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

function VehicleTransferMission: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); --g_additionalContractUtils:getObjectsSpawnPosition(trigger, nil, self.numObjects, objectConfig); --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 VehicleTransferMission:loadInit()
	g_additionalContractTypes:insertRandomTyp(VehicleTransferMission.NAME);
	g_additionalContractTypes:insertBalanceTyp(VehicleTransferMission.NAME);
	g_additionalContractTypes:insertNextDayTyp(VehicleTransferMission.NAME, VehicleTransferMission.MAX_NUM_DAY);	
	local xmlFilename = Utils.getFilename("missions/universalMission/vehicleTransferMission/missions.xml", AdditionalContracts.modDir);
	if xmlFilename ~= nil and xmlFilename ~= "" then VehicleTransferMission.MISSIONS_XML = g_additionalContractUtils:loadMissionsXml(xmlFilename);end;
	--xmlFilename = Utils.getFilename("missionVehicles/vehicleTransferMissionVehicles.xml", AdditionalContracts.modDir)
	--if xmlFilename ~= nil and xmlFilename ~= "" then g_missionManager:addPendingMissionVehiclesFile(xmlFilename, AdditionalContracts.modDir);end;
end;

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

function VehicleTransferMission: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(VehicleTransferMission, VehicleTransferMission.NAME);