AdditionalContractTriggerManager = {};

local AdditionalContractTriggerManager_mt = Class(AdditionalContractTriggerManager, AbstractManager);

function AdditionalContractTriggerManager:debugPrint(text, ...)
	if self.printDebug then		
		Logging.info(text,...);		
	end;
end;

function AdditionalContractTriggerManager.new()	
	local self = AbstractManager.new(AdditionalContractTriggerManager_mt)
	self.printDebug = false;
	self:initDataStructures();	
	return self;
end;

function AdditionalContractTriggerManager:initDataStructures()
	self.sharedLoadingIds = {};
	self.triggerNodeToData = {};
	self.activeTriggers = {};	
end;

function AdditionalContractTriggerManager:loadMapData(xmlFile, missionInfo)
	AdditionalContractTriggerManager:superClass().loadMapData(self);	
	return true;
end;

function AdditionalContractTriggerManager:unloadMapData()
	--g_currentMission.activatableObjectsSystem:removeActivatable(self.activatable)
	for _, sharedLoadingId in ipairs(self.sharedLoadingIds) do
		if sharedLoadingId ~= nil then g_i3DManager:releaseSharedI3DFile(sharedLoadingId);self.sharedLoadingIds[sharedLoadingId] = nil;end;
	end;
	for trigger, _ in ipairs(self.triggerNodeToData) do		
		if trigger ~= nil and trigger.triggerNode ~= nil then
			self:removeTrigger(trigger.triggerNode);
			delete(trigger.node);
		end;
	end;
	AdditionalContractTriggerManager:superClass().unloadMapData(self);
end;

function AdditionalContractTriggerManager:insertTrigger(trigger)
	if trigger == nil or type(trigger) ~= "table" or trigger.triggerNode == nil or trigger.node == nil then return false;end;
	if trigger.data == nil then trigger.data = {};end;
	if trigger.typ == nil then trigger.typ = "default";end;
	self.triggerNodeToData[trigger.triggerNode] = trigger;	
	return true;
end;

function AdditionalContractTriggerManager:insertValue(triggerId, key, value, data)
	if triggerId ~= nil then
		local trigger = self.triggerNodeToData[triggerId];
		if trigger ~= nil then
			if data and trigger.data == nil then self.triggerNodeToData[triggerId].data = {};end;			
			if data then self.triggerNodeToData[triggerId].data[key] = value;else self.triggerNodeToData[triggerId][key] = value;end;			
		end;
	end;
end;

function AdditionalContractTriggerManager:setState(triggerId, key, state, data)
	if triggerId ~= nil then
		local trigger = self.triggerNodeToData[triggerId];
		if trigger ~= nil then
			if data then
				if trigger.data ~= nil then self.triggerNodeToData[triggerId].data[key] = state;return true;end;			
			else
				if trigger[key] ~= nil then self.triggerNodeToData[triggerId][key] = state;return true;end;				
			end;
		end;
	end;
	return nil;
end;

function AdditionalContractTriggerManager:getState(triggerId, key, data)
	if triggerId ~= nil then
		local trigger = self.triggerNodeToData[triggerId];
		if trigger ~= nil then
			if data then
				if trigger.data ~= nil then return self.triggerNodeToData[triggerId].data[key];end;
			else
				return trigger[key];
			end;
		end;
	end;
	return nil;
end;

function AdditionalContractTriggerManager:generateTrigger(filename, modDir, x, y, z, triggerCallback, data)
	if x ~= nil and y ~= nil and z ~= nil and filename ~= nil then
		local filename = Utils.getFilename(filename, modDir or AdditionalContracts.modDir);
		if filename ~= nil then
			if triggerCallback ~= nil and type(triggerCallback) ~= "function" then triggerCallback = nil;end;
			local trigger = {
				position = {x, y, z};			
				triggerCallback = triggerCallback;
				filename = filename;
				typ = "default";
				data = data or {};
				isEnabled = false;
				onStayTimer = 0;
				mission = nil;
			};
			if trigger.data ~= nil and trigger.data.typ ~= nil then trigger.typ = trigger.data.typ;end;
			local sharedLoadingId, nodeId, _, createTrigger = g_i3DManager:loadSharedI3DFileAsync(filename, false, false, AdditionalContractTriggerManager.onTriggerLoaded, self, trigger);
			table.insert(self.sharedLoadingIds, sharedLoadingId);			
			return true;
		end;
	end;
	return false, "arguments x,y,z or filename missing";
end;

function AdditionalContractTriggerManager:onTriggerLoaded(i3dNode, failedReason, trigger)
	if i3dNode ~= nil and i3dNode ~= 0 then
		trigger.node = i3dNode;
		trigger.triggerNode = getChildAt(getChildAt(i3dNode, 0), 0);
		self.triggerNodeToData[trigger.triggerNode] = trigger;
		link(getRootNode(), i3dNode);
		local setPosition = Utils.getNoNil(trigger.data.setPosition, false);
		local activatePhysics = Utils.getNoNil(trigger.data.addToPhysics, false);
		local activateTrigger = Utils.getNoNil(trigger.data.addTrigger, false);
		if activateTrigger then self:addTrigger(trigger.triggerNode);end;
		if activatePhysics then self:addToPhysics(trigger.triggerNode);end;
		if setPosition then setWorldTranslation(i3dNode, trigger.position[1], trigger.position[2], trigger.position[3]);end;		
	end;
end;

function AdditionalContractTriggerManager:triggerCallback(triggerId, otherId, onEnter, onLeave, onStay)
	local trigger = self.triggerNodeToData[triggerId];
	if g_localPlayer ~= nil then
		if g_localPlayer:getIsInVehicle() or otherId == g_localPlayer.rootNode then
			local playerVehicle = g_localPlayer:getCurrentVehicle();
			if playerVehicle ~= nil and playerVehicle == g_currentMission.nodeToObject[otherId] then
				if onEnter then
					AdditionalContracts.testString[1] = "in trigger mit vehicle";
					return;
				end;
			end;
		end;
	end;
	local otherIdText = "/otherId: ";
	if otherId ~= nil then otherIdText = otherIdText.. tostring(otherId);else otherIdText = otherIdText.. "nil";end;
	if trigger ~= nil then		
		if trigger.triggerCallback ~= nil then trigger.triggerCallback(otherId, onEnter, onLeave, onStay, trigger);end;
		if onEnter then
			AdditionalContracts.testString[1] = "in trigger".. otherIdText;
			--print(DebugUtil.printTableRecursively(trigger, "trigger ", 0, 3))
			return;	
		elseif onLeave and otherId ~= nil then
			AdditionalContracts.testString[1] = "aus trigger".. otherIdText;			
		elseif onStay then
			AdditionalContracts.testString[1] = "standing im trigger".. otherIdText;
			
		end;
		return;
	end;	
end;

function AdditionalContractTriggerManager:addTrigger(triggerId)
	local trigger = self.triggerNodeToData[triggerId];
	if trigger ~= nil and trigger.triggerNode ~= nil then
		addTrigger(trigger.triggerNode, "triggerCallback", self);
		return true;
	end;
	return false;
end;

function AdditionalContractTriggerManager:getTriggersByTyp(typName)
	if typName == nil or type(typName) ~= "string" then return {};end;
	local typTriggers = {};
	for _, trigger in pairs (self.triggerNodeToData) do
		if trigger.typ == typName then
			table.insert(typTriggers, trigger);
		end;
	end;
	return typTriggers;
end;

function AdditionalContractTriggerManager:getTriggerById(triggerId)
	return self.triggerNodeToData[triggerId];
end;

function AdditionalContractTriggerManager:removeTrigger(triggerId)
	local trigger = self.triggerNodeToData[triggerId];
	if trigger ~= nil and trigger.triggerNode ~= nil then
		removeTrigger(trigger.triggerNode);
		return true;
	end;
	return false;
end;

function AdditionalContractTriggerManager:addToPhysics(triggerId)
	local trigger = self.triggerNodeToData[triggerId];
	if trigger ~= nil and trigger.node ~= nil then
		addToPhysics(trigger.node);
		return true;
	end;
	return false;
end;

function AdditionalContractTriggerManager:removeFromPhysics(triggerId)
	local trigger = self.triggerNodeToData[triggerId];
	if trigger ~= nil and trigger.node ~= nil then
		removeFromPhysics(trigger.node);
		return true;
	end;
	return false;
end;

function AdditionalContractTriggerManager:setPosition(triggerId, x, y, z, refreshPosition)
	local trigger = self.triggerNodeToData[triggerId];
	if trigger ~= nil then
		if trigger.position ~= nil then
			trigger.position[1] = x;
			trigger.position[2] = y;
			trigger.position[3] = z;
		else
			trigger.position = {x, y, z};
		end;
		local refreshPosition = refreshPosition or false;
		if refreshPosition and trigger.node ~= nil then setWorldTranslation(trigger.node, unpack(trigger.position));return true, true;end;
		return true, false;
	end;
	return false, false;
end;

function AdditionalContractTriggerManager:getPosition(triggerId)
	local trigger = self.triggerNodeToData[triggerId];
	if trigger ~= nil and trigger.position ~= nil then
		return unpack(trigger.position);
	end;
	return nil, nil, nil;
end;

function AdditionalContractTriggerManager:setVisible(triggerId, state)
	local trigger = self.triggerNodeToData[triggerId];
	if trigger ~= nil and trigger.node ~= nil and state ~= nil then
		setVisibility(trigger.node, state);
		return true;
	end;
	return false;
end;

------
MissionTrigger = {};
local MissionTrigger_mt = Class(MissionTrigger);

function MissionTrigger.new(id, index, isClient)
	local self = setmetatable({}, MissionTrigger_mt)
	self.triggerId = id;
	self.index = index or "mission_1";
	self.isClient = Utils.getNoNil(isClient, false);	
	addTrigger(id, "triggerCallback", self);
	self.isEnabled = false;	
	self:setMission(nil);	
	return self;
end;

function MissionTrigger:delete()	
	if self.mission ~= nil and self.mission.removeMissionTrigger ~= nil then self.mission:removeMissionTrigger(self.triggerId);end;
	removeTrigger(self.triggerId);
end;

function MissionTrigger:setMission(mission)
	self.mission = mission;
	self:onMissionUpdated();
end;

function MissionTrigger:onMissionUpdated()	
	local isVisible = false;
	if self.mission ~= nil then	
		isVisible = self.mission.status == MissionStatus.RUNNING;
	end;
	--local trigger = g_currentMission.nodeToObject[self.triggerId];
	--if trigger ~= nil then trigger:setVisibility(isVisible);end;
	setVisibility(self.triggerId, isVisible); --old function
end;

function MissionTrigger:triggerCallback(triggerId, otherId, onEnter, onLeave, onStay)
	if self.isEnabled and self.mission ~= nil then		
		if onEnter then
			if self.mission.onEnterTrigger ~= nil then self.mission:onEnterTrigger(self, otherId);end;			
			return;
		end;
		if onLeave then
			if self.mission.onLeaveTrigger ~= nil then self.mission:onLeaveTrigger(self, otherId);end;			
		end;	
	end;
end;
------

g_additionalContractTriggerManager = AdditionalContractTriggerManager.new();