--
-- 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(savegame)
    -- 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;