Umi.Users = (function() {
    const users = new Map;

    const onAdd = [],
        onRemove = [],
        onClear = [],
        onUpdate = [];

    return {
        OnAdd: onAdd,
        OnRemove: onRemove,
        OnClear: onClear,
        OnUpdate: onUpdate,
        Add: function(user) {
            const userId = user.getId();
            if(!users.has(userId)) {
                users.set(userId, user);

                for(const i in onAdd)
                    onAdd[i](user);
            }
        },
        Remove: function(user) {
            const userId = user.getId();
            if(users.has(userId)) {
                users.delete(userId);

                for(const i in onRemove)
                    onRemove[i](user);
            }
        },
        Clear: function() {
            users.clear();

            for(const i in onClear)
                onClear[i]();
        },
        All: function() {
            return Array.from(users.values());
        },
        Get: function(userId) {
            userId = userId.toString();
            if(users.has(userId))
                return users.get(userId);
            return null;
        },
        Find: function(userName) {
            const found = [];
            userName = userName.toLowerCase();

            users.forEach(function(user) {
                if(user.getName().toLowerCase().includes(userName))
                    found.push(user);
            });

            return found;
        },
        FindExact: function(userName) {
            userName = userName.toLowerCase();

            for(const user of users.values())
                if(user.getName().toLowerCase() === userName)
                    return user;

            return null;
        },
        Update: function(userId, user) {
            userId = userId.toString();

            users.set(userId, user);
            user.bumpAvatarTime();

            for(const i in onUpdate)
                onUpdate[i](userId, user);
        },
    };
})();
