--
-- Passenger
-- Specialization for Passenger
--
-- @author  JoXXer
-- @date  26/11/11
--

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.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;
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
		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.SEND_CHAT_MESSAGE) and self.isChatting then
				self.isChatting = false;
			end;
			if InputBinding.hasEvent(InputBinding.ENTER) and not self.isChatting then
				self.passengerCameras[1]:onDeactivate();
				setCamera(self.passengerPlayer.cameraId);
				self:setPassenger("Exited", nil);
			end;

			local pcx, pcy, pcz = getRotation(self.passengerPlayer.cameraId);
			local prx, pry, prz = getRotation(self.passengerPlayer.graphicsRootNode);

			setRotation(self.passengerCameras[1].cameraNode, pcx, pry, 0);

			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("EXIT_PASSENGERSEAT"), self.typeDesc), InputBinding.ENTER);
		end;

		if self.passengerPlayer ~= nil then
			if g_currentMission:getIsServer() then
				if g_currentMission.connectionsToPlayer[self.passengerPlayer.creatorConnection] == nil then
					self:setPassenger("Disconnected", nil);
				end;
			end;
		end;
	end;
	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
			self:setPassenger("ExitedToOtherVehicle", nil);
		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);
			self.passengerCameras[1]:onActivate();
		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
		setTranslation(passengerPlayer.rootNode, 0, 0, 0);
		self.passengerName = passengerName;
	elseif passengerName == "Exited" then
		local exitX, exitY, exitZ = getWorldTranslation(self.exitPoint);
		setTranslation(self.passengerPlayer.rootNode, exitX, exitY+2, exitZ);
		self.passengerName = "";
	else
		self.passengerName = "";
	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;
