"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const EventEmitter_js_1 = __importStar(require("./utilities/EventEmitter.js"));
const Leavers_js_1 = __importDefault(require("./Leavers.js"));
class Members extends EventEmitter_js_1.default {
    constructor(space) {
        super();
        this.space = space;
        this.lastMemberUpdate = {};
        this.leavers = new Leavers_js_1.default(this.space.options.offlineTimeout);
    }
    processPresenceMessage(message) {
        return __awaiter(this, void 0, void 0, function* () {
            const { action, connectionId } = message;
            const isLeaver = !!this.leavers.getByConnectionId(connectionId);
            const member = this.createMember(message);
            if (action === 'leave') {
                this.leavers.addLeaver(member, () => this.onMemberOffline(member));
                this.emit('leave', member);
                this.emit('update', member);
            }
            else if (isLeaver) {
                this.leavers.removeLeaver(connectionId);
            }
            if (action === 'enter') {
                this.emit('enter', member);
                this.emit('update', member);
            }
            // Emit profileData updates only if they are different then the last held update.
            // A locationUpdate is handled in Locations.
            if (message.data.profileUpdate.id && this.lastMemberUpdate[connectionId] !== message.data.profileUpdate.id) {
                this.lastMemberUpdate[message.connectionId] = message.data.profileUpdate.id;
                this.emit('updateProfile', member);
                this.emit('update', member);
            }
        });
    }
    getSelf() {
        return __awaiter(this, void 0, void 0, function* () {
            return this.space.connectionId ? yield this.getByConnectionId(this.space.connectionId) : null;
        });
    }
    getAll() {
        return __awaiter(this, void 0, void 0, function* () {
            const presenceMembers = yield this.space.channel.presence.get();
            const members = presenceMembers.map((m) => this.createMember(m));
            return members.concat(this.leavers.getAll().map((l) => l.member));
        });
    }
    getOthers() {
        return __awaiter(this, void 0, void 0, function* () {
            const members = yield this.getAll();
            return members.filter((m) => m.connectionId !== this.space.connectionId);
        });
    }
    subscribe(listenerOrEvents, listener) {
        try {
            super.on(listenerOrEvents, listener);
        }
        catch (e) {
            if (e instanceof EventEmitter_js_1.InvalidArgumentError) {
                throw new EventEmitter_js_1.InvalidArgumentError('Members.subscribe(): Invalid arguments: ' + (0, EventEmitter_js_1.inspect)([listenerOrEvents, listener]));
            }
            else {
                throw e;
            }
        }
    }
    unsubscribe(listenerOrEvents, listener) {
        try {
            super.off(listenerOrEvents, listener);
        }
        catch (e) {
            if (e instanceof EventEmitter_js_1.InvalidArgumentError) {
                throw new EventEmitter_js_1.InvalidArgumentError('Members.unsubscribe(): Invalid arguments: ' + (0, EventEmitter_js_1.inspect)([listenerOrEvents, listener]));
            }
            else {
                throw e;
            }
        }
    }
    getByConnectionId(connectionId) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            const members = yield this.getAll();
            return (_a = members.find((m) => m.connectionId === connectionId)) !== null && _a !== void 0 ? _a : null;
        });
    }
    createMember(message) {
        return {
            clientId: message.clientId,
            connectionId: message.connectionId,
            isConnected: message.action !== 'leave',
            profileData: message.data.profileUpdate.current,
            location: message.data.locationUpdate.current,
            lastEvent: {
                name: message.action,
                timestamp: message.timestamp,
            },
        };
    }
    onMemberOffline(member) {
        return __awaiter(this, void 0, void 0, function* () {
            this.leavers.removeLeaver(member.connectionId);
            this.emit('remove', member);
            this.emit('update', member);
            if (member.location) {
                this.space.locations.emit('update', {
                    previousLocation: member.location,
                    currentLocation: null,
                    member: Object.assign(Object.assign({}, member), { location: null }),
                });
            }
            this.space.emit('update', { members: yield this.getAll() });
        });
    }
}
exports.default = Members;
//# sourceMappingURL=Members.js.map