Door = {};
local Door_mt = Class(Door);

function Door.onCreate(id)
	g_currentMission:addUpdateable(Door:new(id));
end;


function Door:new(id, customMt)
	
	local instance = {};
	if customMt ~= nil then
		setmetatable(instance, customMt);
	else
		setmetatable(instance, Door_mt);
	end;

	instance.triggerId = id;
	
	
	instance.autoOpen = Utils.getNoNil(getUserAttribute(id,'autoOpen'),false);
	
	addTrigger(id, "triggerCallback", instance);
	if instance.autoOpen then
	else
		local defaultInputBinding = 'DOORTRIGGER_ACTION'
		if InputBinding[defaultInputBinding] == nil then
			defaultInputBinding = 'IMPLEMENT_EXTRA3';
		end;
		local openTextID = Utils.getNoNil(getUserAttribute(id,'openText'),'doorTriggerOpen');
		local closeTextID = Utils.getNoNil(getUserAttribute(id,'closeText'),'doorTriggerClose');
		instance.openText = Utils.getNoNil(g_i18n:getText(openTextID),'Tür öffnen');
		instance.closeText = Utils.getNoNil(g_i18n:getText(closeTextID),'Tür schließen');
		instance.inputBinding = Utils.getNoNil(getUserAttribute(id,'inputBinding'),defaultInputBinding);
	end;
	
	
	instance.objects = {}
	
	
	getMovingObjects(id,instance.objects);		
	
	self.state = 3;
	self.objectsIn = 0;
	self.playerIn = false;
	self.justEntered = false;
	instance.vehicles = {};
	return instance;
 end;

 function Door:delete()
	--if self.autoOpen then
		removeTrigger(self.triggerId);
	--end;
 end;
 
 function Door:update(dt)
	if self.autoOpen then
	else
		local showHelpButton = false;
		
		if self.playerIn then
			if not g_currentMission.controlPlayer then
				self.playerIn = false;
			else
				showHelpButton = true;
			end;
		else
			-- Prüfen, ob ein Fahrzeug aktiv
			for node,vehicle in pairs(self.vehicles) do
				if not vehicle:getIsActiveForInput(false) then
					showHelpButton = false;
				else
					showHelpButton = true;
				end;
				
			end;
		end;
	--	self.justEntered = false;
		-- Prüfen ob Spieler in Reichweite
		if showHelpButton then
			-- Prüfen ob Eingabe
			if InputBinding.hasEvent(InputBinding[self.inputBinding]) then
				
				if self.state == 1 or self.state == 2 then
					self.state = 3;
				else
					self.state = 1;
				end;
			end;
			-- Prüfen, ob Hilfstexte angezeigt werden müssen und welche
			if self.state == 1 or self.state == 2 then
				g_currentMission:addHelpButtonText(self.closeText, InputBinding[self.inputBinding]);
			else
				g_currentMission:addHelpButtonText(self.openText, InputBinding[self.inputBinding]);
			end;
		end;
	end;
	
	-- Türen öffnen/schließen, wenn nötig
	if self.state == 1 then --opening
		
		self.state = 2; -- opened
		for _,v in pairs(self.objects) do
			if v:open(dt/1000) then
			else
				self.state = 1;
			end;
		end;
	elseif self.state == 3 then --closing
		self.state = 0;		-- closed
		for _,v in pairs(self.objects) do
			if 	v:close(dt/1000) then
			else
				self.state = 3;
			end;
		end;
	end; 
 
end;


function Door:triggerCallback(triggerId, otherId, onEnter, onLeave, onStay)
	
	if triggerId == self.triggerId then
	else
		return;
	end;
	if self.autoOpen then
		if onEnter then
			self.objectsIn = self.objectsIn + 1;
			if self.state ~= 2 then
				self.state = 1;
			end;
		elseif onLeave then
			
			self.objectsIn = self.objectsIn - 1;
			if self.state ~= 0 and self.objectsIn == 0 then
				self.state = 3;
			end;
		end; 
	else
		--if g_currentMission.player == nil then
		--	return;
		--end;
		if onEnter then --and otherId == g_currentMission.player.rootNode then
			if g_currentMission.player ~= nil then
				if otherId == g_currentMission.player.rootNode then
					self.playerIn = true;
				end;
			end;
			--self.justEntered = true;
			local vehicle = g_currentMission.nodeToVehicle[otherId];
			if vehicle == nil then
				if not g_currentMission.controlPlayer then
					self.playerIn = false;
				end;
			else				
				self.vehicles[otherId] = vehicle;
			end;
		elseif onLeave then --and otherId == g_currentMission.player.rootNode then
			if g_currentMission.controlPlayer then
				self.playerIn = false;
			end;
			if self.vehicles[otherId] then
				if self.vehicles[otherId]:getIsActiveForInput() then
					self.playerIn = false;
				end;
			end;
			self.vehicles[otherId] = nil;
			--self.justEntered = false;
		end;
	end;
end;

MovingObject = {};
local MovingObject_mt = Class(MovingObject);


function MovingObject:new(id, customMt)

	local instance = {};
	if customMt ~= nil then
		setmetatable(instance, customMt);
	else
		setmetatable(instance, MovingObject_mt);
	end;
	instance.id = id;
	self.state = 1;
	self.stateTime = 0;
	self.numStates = 0;
	
	return instance;
end;

function MovingObject:setTranslations(x,y,z)
	
	self.tx = stringToNumTable(x);
	self.ty = stringToNumTable(y);
	self.tz = stringToNumTable(z);	
	
	
	self.lastTx = Utils.getNoNil(self.tx[tablelength(self.tx)],x);
	self.lastTy = Utils.getNoNil(self.ty[tablelength(self.ty)],y);
	self.lastTz = Utils.getNoNil(self.tz[tablelength(self.tz)],z);
end;

function MovingObject:setRotations(x,y,z)
	self.rx = stringToNumTableRad(x);
	self.ry = stringToNumTableRad(y);
	self.rz = stringToNumTableRad(z);	
	
	
	self.lastRx = Utils.getNoNil((self.rx[tablelength(self.rx)]),(x));
	self.lastRy = Utils.getNoNil((self.ry[tablelength(self.ry)]),(y));
	self.lastRz = Utils.getNoNil((self.rz[tablelength(self.rz)]),(z));
end;

function MovingObject:setTimes(times)
	self.time = stringToNumTable(times);
	self.numStates = tablelength(self.time) - 1;
	--printtable(self.time);
end;

function MovingObject:open(dt)
	if self.state == self.numStates and self.stateTime == (self.time[self.state+1]) then
		return true;	
	else
		self.stateTime = self.stateTime + dt;
		while self.stateTime > (self.time[self.state+1]) do -- nächster Zustand?
			if self.state == self.numStates then -- letzter Zustand/ kein neuer Zustand mehr
				self.stateTime = (self.time[self.state+1]);
			else
				self.stateTime = self.stateTime - (self.time[self.state+1]);
				self.state = self.state + 1;
			end;
		end;
		local ctx, cty, ctz = getTranslation(self.id)
		local crx, cry, crz = getRotation(self.id);
		ctx = Utils.getNoNil((self.tx[self.state]),(self.lastTx)) + (Utils.getNoNil((self.tx[self.state+1]),self.lastTx) - Utils.getNoNil((self.tx[self.state]),self.lastTx)) * self.stateTime / (self.time[self.state+1]);
		crx = Utils.getNoNil((self.rx[self.state]),(self.lastRx)) + (Utils.getNoNil((self.rx[self.state+1]),self.lastRx) - Utils.getNoNil((self.rx[self.state]),self.lastRx)) * self.stateTime / (self.time[self.state+1]);
		cty = Utils.getNoNil((self.ty[self.state]),(self.lastTy)) + (Utils.getNoNil((self.ty[self.state+1]),self.lastTy) - Utils.getNoNil((self.ty[self.state]),self.lastTy)) * self.stateTime / (self.time[self.state+1]);
		cry = Utils.getNoNil((self.ry[self.state]),(self.lastRy)) + (Utils.getNoNil((self.ry[self.state+1]),self.lastRy) - Utils.getNoNil((self.ry[self.state]),self.lastRy)) * self.stateTime / (self.time[self.state+1]);
		ctz = Utils.getNoNil((self.tz[self.state]),(self.lastTz)) + (Utils.getNoNil((self.tz[self.state+1]),self.lastTz) - Utils.getNoNil((self.tz[self.state]),self.lastTz)) * self.stateTime / (self.time[self.state+1]);
		crz = Utils.getNoNil((self.rz[self.state]),(self.lastRz)) + (Utils.getNoNil((self.rz[self.state+1]),self.lastRz) - Utils.getNoNil((self.rz[self.state]),self.lastRz)) * self.stateTime / (self.time[self.state+1]);
				
		setTranslation(self.id, ctx, cty, ctz);
		setRotation(self.id, crx, cry, crz);
		return false;
	end;
	
end;

function MovingObject:close(dt)
	if self.state == 1 and self.stateTime == 0 then
		return true;	
	else
		self.stateTime = self.stateTime - dt;
		while self.stateTime < 0 do
			if self.state <= 1 then
				self.state = 1;
				self.stateTime = 0;
			else
				self.stateTime = self.stateTime + (self.time[self.state]);
				self.state = self.state - 1;
			end;
		end;
		local ctx, cty, ctz = getTranslation(self.id);
		local crx, cry, crz = getRotation(self.id);
		ctx = Utils.getNoNil((self.tx[self.state]),(self.lastTx)) + (Utils.getNoNil((self.tx[self.state+1]),self.lastTx) - Utils.getNoNil((self.tx[self.state]),self.lastTx)) * self.stateTime / (self.time[self.state+1]);
		crx = Utils.getNoNil((self.rx[self.state]),(self.lastRx)) + (Utils.getNoNil((self.rx[self.state+1]),self.lastRx) - Utils.getNoNil((self.rx[self.state]),self.lastRx)) * self.stateTime / (self.time[self.state+1]);
		cty = Utils.getNoNil((self.ty[self.state]),(self.lastTy)) + (Utils.getNoNil((self.ty[self.state+1]),self.lastTy) - Utils.getNoNil((self.ty[self.state]),self.lastTy)) * self.stateTime / (self.time[self.state+1]);
		cry = Utils.getNoNil((self.ry[self.state]),(self.lastRy)) + (Utils.getNoNil((self.ry[self.state+1]),self.lastRy) - Utils.getNoNil((self.ry[self.state]),self.lastRy)) * self.stateTime / (self.time[self.state+1]);
		ctz = Utils.getNoNil((self.tz[self.state]),(self.lastTz)) + (Utils.getNoNil((self.tz[self.state+1]),self.lastTz) - Utils.getNoNil((self.tz[self.state]),self.lastTz)) * self.stateTime / (self.time[self.state+1]);
		crz = Utils.getNoNil((self.rz[self.state]),(self.lastRz)) + (Utils.getNoNil((self.rz[self.state+1]),self.lastRz) - Utils.getNoNil((self.rz[self.state]),self.lastRz)) * self.stateTime / (self.time[self.state+1]);
				
		setTranslation(self.id, ctx, cty, ctz);
		setRotation(self.id, crx, cry, crz);
		return false;
	end;
end;

function tablelength(T)
  local count = 0
  if T ~= nil then
	for _ in pairs(T) do count = count + 1 end
  end;
  return count
end

function printtable(tab)
	for k,v in pairs(tab) do
		print(k,": ", v);
	end;
end;

function stringToNumTable(str)
	local ret = {};
	local splited = Utils.splitString(' ',string.gsub(str,'  ',' '));
	if splited == nil then
		ret[1] = tonumber(str);
		return ret;
	else
		for k,v in pairs(splited) do
			if tonumber(v) ~= nil then
				ret[k] = tonumber(v);
			end;
		end;
		return ret;
	end;
end;

function stringToNumTableRad(str)
	local ret = {};
	local splited = Utils.splitString(' ',string.gsub(str,'  ',' '));
	if splited == nil then		
		ret[1] = math.rad(tonumber(str));
		return ret;
	else
		for k,v in pairs(splited) do
			if tonumber(v) ~= nil then
				ret[k] = math.rad( tonumber(v) );
			end;
		end;
		return ret;
	end;
end;


function getMovingObjects(id,objectTable)
	local numC = getNumOfChildren(id);
	if id ~= 0 and numC >= 1 then
		for j=0, numC-1 do
			local child = getChildAt(id,j);
			if child ~= 0 then
				if Utils.getNoNil(getUserAttribute(child,'isMoving'),false) then
					local object = MovingObject:new(child);
					local cx, cy, cz = getTranslation(child);
					local x = Utils.getNoNil(getUserAttribute(child,'translateX'),"");
					local y = Utils.getNoNil(getUserAttribute(child,'translateY'),"");
					local z = Utils.getNoNil(getUserAttribute(child,'translateZ'),"");
					object:setTranslations(cx..' '..x,cy..' '..y,cz..' '..z);
										
					cx, cy, cz = getRotation(child);
					x = Utils.getNoNil(getUserAttribute(child,'rotateX'),"");
					y = Utils.getNoNil(getUserAttribute(child,'rotateY'),"");
					z = Utils.getNoNil(getUserAttribute(child,'rotateZ'),"");
					object:setRotations(math.deg(cx)..' '..x,math.deg(cy)..' '..y,math.deg(cz)..' '..z);
					
					local times = Utils.getNoNil(getUserAttribute(child,'time'),"");
					object:setTimes('0 '..times);
					
					table.insert(objectTable,object);
				end;
				
				if Utils.getNoNil(getUserAttribute(child,'hasMovingChild'),false) then
					getMovingObjects(child,objectTable);
				end;
			end;
			
		end;
	end;
end;

g_onCreateUtil.addOnCreateFunction("DoorOnCreate", Door.onCreate);