--
-- Passenger
-- Specialization for Passenger
--
-- @author  JoXXer
-- @date  26/11/11
--
-- LS2013 Ready: Alex2009(www.Alex2009.de)

Passenger = {};

function Passenger.prerequisitesPresent(specializations)
	return SpecializationUtil.hasSpecialization(Steerable, specializations);
end;

function Passenger:load(xmlFile)
	-- Set passenger function
	self.setPassenger = SpecializationUtil.callSpecializationsFunction("setPassenger");

	-- Nickname rendernode
	self.passengerFarmerNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.passengerFarmerNode#index"));
	self.passengerNicknameRenderNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.passengerNicknameRenderNode#index"));
	self.passengerNicknameRenderNodeOffset = {0,0,0};

	-- The passenger. He is the passenger, he rides and he rides.
	self.passengerPlayer = nil;

	-- The passengers name
	self.passengerName = "";

	-- Passenger cameras. Yes, there can be more then two, but that requires modifications in the script.
	self.passengerCameras = {};

	local passengerCameraName = string.format("vehicle.passengerCamera");
	local passengerCamera = VehicleCamera:new(self);

	if passengerCamera:loadFromXML(xmlFile, passengerCameraName) then
		table.insert(self.passengerCameras, passengerCamera);
	end;

	-- Variable for inrangecheck
	self.inRangeOfVehicle = false;

	-- Variable to check if user is chatting, to prevent exit on InputBinding.ENTER-event
	self.isChatting = false;
	
	self.PlayerAttach = {};
	setVisibility(self.passengerFarmerNode,false);
end;

function Passenger:delete()
	for _, passengerCamera in ipairs(self.passengerCameras) do
		passengerCamera:delete();
	end;
end;

function Passenger:readStream(streamId, connection)
	local passengerPlayerId = streamReadInt32(streamId);
	self.passengerName = streamReadString(streamId);

	if passengerPlayerId ~= -1 then
		self.passengerPlayer = networkGetObject(passengerPlayerId);
	end;
end;

function Passenger:writeStream(streamId, connection)
	if self.passengerPlayer ~= nil then
		streamWriteInt32(streamId, networkGetObjectId(self.passengerPlayer));
	else
		streamWriteInt32(streamId, -1);
	end;
	streamWriteString(streamId, self.passengerName);
end;

function Passenger:readUpdateStream(streamId, timestamp, connection)

end;

function Passenger:writeUpdateStream(streamId, connection, dirtyMask)

end;

function Passenger:mouseEvent(posX, posY, isDown, isUp, button)
end;

function Passenger:keyEvent(unicode, sym, modifier, isDown)
end;

function Passenger:update(dt)
	if self.passengerPlayer ~= nil then
		-- if player joins a vehicle, set passenger-spot not taken!
		if not self.passengerPlayer.isControlled and not self.passengerPlayer.isEntered then
			if self.passengerPlayer == g_currentMission.player then
				g_currentMission.isPlayerFrozen = false;
			end;
			self:setPassenger("ExitedToOtherVehicle", nil);
			return;
		end;
	end;
	-- Manage key events for inrange --
	if self.inRangeOfVehicle and self.passengerPlayer == nil and self.isControlled and g_settingsNickname ~= self.controllerName then
		g_currentMission:addHelpButtonText(string.format(g_i18n:getText("ENTER_PASSENGERSEAT"), self.typeDesc), InputBinding.ENTER);
		if InputBinding.hasEvent(InputBinding.ENTER) then   
			self:setPassenger(g_settingsNickname, g_currentMission.player);
			g_currentMission.hasSpecialCamera = true;
			self.passengerCameras[1]:onActivate();
			g_currentMission.hasSpecialCamera = true;
			self.passengerPlayer.rotX = 0;
			self.passengerPlayer.rotY = 180;
			return;
		end;
	end;
	if self.passengerPlayer ~= nil then
		if self.passengerPlayer ~= nil then
			if g_currentMission:getIsServer() then
				if g_currentMission.connectionsToPlayer[self.passengerPlayer.creatorConnection] == nil then
					self:setPassenger("Disconnected", nil);
					return;
				end;
			end;
		end;
		self.passengerCameras[1]:update(dt);
		if self.passengerName == g_settingsNickname then
			if InputBinding.hasEvent(InputBinding.CHAT) and not self.isChatting then
				self.isChatting = true;
			end;
			if InputBinding.hasEvent(InputBinding.MENU_ACCEPT) and self.isChatting then
				self.isChatting = false;
			end;
			local inputZ = InputBinding.getDigitalInputAxis(InputBinding.AXIS_LOOK_LEFTRIGHT_PLAYER)
			local inputW = InputBinding.getDigitalInputAxis(InputBinding.AXIS_LOOK_UPDOWN_PLAYER)
			if InputBinding.isAxisZero(inputZ) then
			  inputZ = InputBinding.getAnalogInputAxis(InputBinding.AXIS_LOOK_LEFTRIGHT_PLAYER)
			end
			if InputBinding.isAxisZero(inputW) then
			  inputW = InputBinding.getAnalogInputAxis(InputBinding.AXIS_LOOK_UPDOWN_PLAYER)
			end
			local rotSpeed = 0.001 * dt
			self.passengerPlayer.rotX = self.passengerPlayer.rotX - rotSpeed * inputW
			self.passengerPlayer.rotY = self.passengerPlayer.rotY - rotSpeed * inputZ
			self.passengerPlayer.rotX = math.min(1.2, math.max(-1.5, self.passengerPlayer.rotX))
			setRotation(self.passengerPlayer.cameraId, self.passengerPlayer.rotX, 0, 0)
			setRotation(self.passengerPlayer.graphicsRootNode, 0, self.passengerPlayer.rotY, 0)
			if self.passengerPlayer ~= nil and self.passengerPlayer.cameraId ~= nil and self.passengerPlayer.graphicsRootNode ~= nil then
				local pcx, pcy, pcz = getRotation(self.passengerPlayer.cameraId);
				local prx, pry, prz = getRotation(self.passengerPlayer.graphicsRootNode);
				setRotation(self.passengerCameras[1].cameraNode, pcx, (pry+180), 0);
			end;
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("EXIT_PASSENGERSEAT"), self.typeDesc), InputBinding.ENTER);
			if InputBinding.hasEvent(InputBinding.ENTER) and not self.isChatting then
				g_currentMission.hasSpecialCamera = false;
				self.passengerCameras[1]:onDeactivate();
				g_currentMission.hasSpecialCamera = false;
				setCamera(self.passengerPlayer.cameraId);
				g_currentMission.hasSpecialCamera = false;
				g_currentMission.isPlayerFrozen = false;
				self:setPassenger("Exited", nil);
			end;
		else
			setVisibility(self.passengerFarmerNode,true);
		end;
	end;
end;

function Passenger:updateTick(dt)
	if g_currentMission.player ~= nil then
		-- Getting the distance between the player and the implement
		local nearestDistance = 4.0; --max distance allowed
		local px, py, pz = getWorldTranslation(self.rootNode);
		local vx, vy, vz = getWorldTranslation(g_currentMission.player.rootNode);
		local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
		if distance < nearestDistance then
			self.inRangeOfVehicle = true;
		else
			self.inRangeOfVehicle = false;
		end;
	end;
end;

function Passenger:draw()
	-- Renders the passenger name for everyone except the passenger
	if g_settingsNickname ~= nil then
		if self.passengerName ~= g_settingsNickname and self.isControlled and self.passengerPlayer ~= nil and g_gui.currentGui == nil then
			local x,y,z = getWorldTranslation(self.passengerNicknameRenderNode);
			local x1,y1,z1 = getWorldTranslation(getCamera())
			local distSq = Utils.vector3LengthSq(x-x1,y-y1,z-z1);
			if distSq <= 100*100 then
				x = x + self.passengerNicknameRenderNodeOffset[1];
				y = y + self.passengerNicknameRenderNodeOffset[2];
				z = z + self.passengerNicknameRenderNodeOffset[3];
				local sx,sy,sz = project(x,y,z);
				if sz <= 1 then
					setTextAlignment(RenderText.ALIGN_CENTER);
					setTextBold(false);
					setTextColor(0.0, 0.0, 0.0, 0.75);
					renderText(sx, sy-0.0015, 0.02, self.passengerName);

					setTextColor(0.5, 1.0, 0.5, 1.0);
					renderText(sx, sy, 0.02, self.passengerName);

					setTextAlignment(RenderText.ALIGN_LEFT);
				end;
			end;
		end;
	end;
end;

function Passenger:onLeave()
end;

function Passenger:onEnter()
end;

function Passenger:setPassenger(passengerName, passengerPlayer, noEventSend)
	SetPassengerEvent.sendEvent(self, passengerName, passengerPlayer, noEventSend);
	if passengerPlayer ~= nil then
		local x,y,z = getWorldTranslation(self.passengerFarmerNode);
		passengerPlayer:moveToAbsolute(x,(y-500),z);
		setTranslation(passengerPlayer.rootNode,x,(y-500),z);
		if self.HoldAtVehiclePlayer == g_currentMission.player then
			g_currentMission.isPlayerFrozen = true;
		end;
		self.passengerName = passengerName;
	elseif passengerName == "Exited" then
		self.passengerPlayer:moveToExitPoint(self);
		self.passengerName = "";
		setVisibility(self.passengerFarmerNode,false);
	else
		self.passengerName = "";
		setVisibility(self.passengerFarmerNode,false);
	end;

	self.passengerPlayer = passengerPlayer;
end;

-- Passenger on enter event-class
SetPassengerEvent = {};
SetPassengerEvent_mt = Class(SetPassengerEvent, Event);

InitEventClass(SetPassengerEvent, "SetPassengerEvent");

function SetPassengerEvent:emptyNew()
	local self = Event:new(SetPassengerEvent_mt);
	self.className="SetPassengerEvent";
	return self;
end;

function SetPassengerEvent:new(vehicle, passengerName, passengerPlayer)
	local self = SetPassengerEvent:emptyNew()
	self.vehicle = vehicle;
	self.passengerName = passengerName;
	self.passengerPlayer = passengerPlayer;
	return self;
end;

function SetPassengerEvent:readStream(streamId, connection)
	local id = streamReadInt32(streamId);
	local passengerPlayerId = streamReadInt32(streamId);
	self.passengerName = streamReadString(streamId);

	self.vehicle = networkGetObject(id);
	self.passengerPlayer = networkGetObject(passengerPlayerId);
	self:run(connection);
end;

function SetPassengerEvent:writeStream(streamId, connection)
	streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteInt32(streamId, networkGetObjectId(self.passengerPlayer));
	streamWriteString(streamId, self.passengerName);
end;

function SetPassengerEvent:run(connection)
	self.vehicle:setPassenger(self.passengerName, self.passengerPlayer, true);
	if not connection:getIsServer() then
		g_server:broadcastEvent(SetPassengerEvent:new(self.vehicle, self.passengerName, self.passengerPlayer), nil, connection, self.vehicle);
	end;
end;

function SetPassengerEvent.sendEvent(vehicle, passengerName, passengerPlayer, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(SetPassengerEvent:new(vehicle, passengerName, passengerPlayer), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(SetPassengerEvent:new(vehicle, passengerName, passengerPlayer));
		end;
	end;
end;