Source: util/carManager.js

/**
 * @file carSpeedManager.js
 * @description Manages car speed states and broadcasts updates to WebSocket clients.
 * @author Lior Jigalo
 * @license MIT
 */

/** Load environment variables from .env file */
require("dotenv").config();

/** Extract environment variables */
const {maxSpeed, updateFreq} = process.env;

/** Import WebSocket library */
const WebSocket = require("ws");

/** Import constants and utility functions */
const {units} = require("./const");
const {carState} = require("./global");
const {getRandomInt} = require("./util");

/** Current speed of the car, starting from 0 */
let speed = 0;

/**
 * Updates the car's speed based on its state.
 */
function updateSpeed() {
    if (carState.accelerating)
        accelerateCar();
    if (carState.decelerating || speed >= 120)
        decelerateCar();
    if (carState.cruising     || speed >= 100)
        cruiseDrive();
    // if (carState.stopped)
    //     console.log("car stopped"); // TODO: add logic of constant beeping
}

/**
 * Logs the current state of the car to the console.
 */
function logStatus(){
    console.log("accelerating: ", carState.accelerating)
    console.log("decelerating: ", carState.decelerating)
    console.log("stopped: "     , carState.stopped)
    console.log("cruising: "        , carState.cruising)
    console.log("speed: ", speed)
    console.log("\n")
}

/**
 * Starts broadcasting the car's speed to all connected WebSocket clients.
 * @param {WebSocket.Server} wss - The WebSocket server instance.
 */
function startSpeedBroadcast(wss) {
    setInterval(() => {
        updateSpeed();
        // logStatus();
        broadcastSpeed(wss, speed);
    }, updateFreq * units.second);
}

/**
 * Broadcasts the current speed to all connected WebSocket clients.
 * @param {WebSocket.Server} wss - The WebSocket server instance.
 * @param {number} speed - The current speed of the car.
 */
function broadcastSpeed(wss, speed) {
    if (carState.stopped)
        return;

    const message = JSON.stringify({
        type: "speed",
        msgData: speed
    });
    wss.clients.forEach((client) => {
        if (client.readyState === WebSocket.OPEN) {
            client.send(message);
        }
    });
}

/**
 * Accelerates the car and updates its state.
 */
function accelerateCar(){
    carState.accelerating = true;
    carState.decelerating = false;
    carState.stopped      = false;
    carState.cruising     = false;
    speed += Math.floor(9 * ((7 + getRandomInt(5)) / 10));
}

/**
 * Decelerates the car and updates its state.
 */
function decelerateCar(){
    carState.accelerating = false;
    carState.decelerating = true;
    carState.stopped      = false;
    carState.cruising       = false;
    if (speed <= 0){
        carState.stopped = true;
        carState.decelerating = false;
        speed = 0;
        return
    }
    speed += Math.floor(-9 * ((7 + getRandomInt(3)) / 10));
}

/**
 * Sets the car to cruise mode and updates its state.
 */
function cruiseDrive(){
    carState.accelerating = false;
    carState.decelerating = false;
    carState.stopped      = false;
    carState.cruising       = true;

    getRandomInt(101) >= 50 ? speed += getRandomInt(5) :  speed -= getRandomInt(3);
}

/** Export functions */
module.exports = {
    startSpeedBroadcast,
    maxSpeed,
    accelerateCar,
    decelerateCar,
    cruiseDrive,
};