"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.sumSet = exports.setHas = exports.setAdd = exports.objectValuesToSet = exports.objectValuesToReadonlySet = exports.objectKeysToSet = exports.objectKeysToReadonlySet = exports.getSortedSetValues = exports.getSetCombinations = exports.getRandomSetElement = exports.deleteSetsFromSet = exports.copySet = exports.combineSets = exports.addSetsToSet = void 0;
const ReadonlySet_1 = require("../types/ReadonlySet");
const array_1 = require("./array");
const types_1 = require("./types");
/**
 * Helper function to add all of the values in one set to another set. The first set passed will be
 * modified in place.
 *
 * This function is variadic, meaning that you can specify N sets to add to the first set.
 */
function addSetsToSet(
// eslint-disable-next-line isaacscript/prefer-readonly-parameter-types
mainSet, ...setsToAdd) {
    for (const set of setsToAdd) {
        for (const value of set) {
            mainSet.add(value);
        }
    }
}
exports.addSetsToSet = addSetsToSet;
/**
 * Helper function to create a new set that is the composition of two or more sets.
 *
 * This function is variadic, meaning that you can specify N sets.
 */
// eslint-disable-next-line isaacscript/no-mutable-return
function combineSets(...sets) {
    const newSet = new Set();
    for (const set of sets) {
        for (const value of set) {
            newSet.add(value);
        }
    }
    return newSet;
}
exports.combineSets = combineSets;
/** Helper function to copy a set. (You can also use a Set constructor to accomplish this task.) */
// eslint-disable-next-line isaacscript/no-mutable-return
function copySet(oldSet) {
    const newSet = new Set();
    for (const value of oldSet) {
        newSet.add(value);
    }
    return newSet;
}
exports.copySet = copySet;
/**
 * Helper function to delete all of the values in one set from another set. The first set passed
 * will be modified in place.
 *
 * This function is variadic, meaning that you can specify N sets to remove from the first set.
 */
function deleteSetsFromSet(
// eslint-disable-next-line isaacscript/prefer-readonly-parameter-types
mainSet, ...setsToRemove) {
    for (const set of setsToRemove) {
        for (const value of set) {
            mainSet.delete(value);
        }
    }
}
exports.deleteSetsFromSet = deleteSetsFromSet;
/**
 * Helper function to get a random element from the provided set.
 *
 * If you want to get an unseeded element, you must explicitly pass `undefined` to the `seedOrRNG`
 * parameter.
 *
 * @param set The set to get an element from.
 * @param seedOrRNG The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
 *                  `RNG.Next` method will be called. If `undefined` is provided, it will default to
 *                  a random seed.
 * @param exceptions Optional. An array of elements to skip over if selected.
 */
function getRandomSetElement(set, seedOrRNG, exceptions = []) {
    const array = getSortedSetValues(set);
    return (0, array_1.getRandomArrayElement)(array, seedOrRNG, exceptions);
}
exports.getRandomSetElement = getRandomSetElement;
/**
 * Helper function to get all possible combinations of the given set. This includes the combination
 * of an empty set.
 *
 * For example, if this function is provided a set containing 1, 2, and 3, then it will return an
 * array containing the following sets:
 *
 * - [] (if `includeEmptyArray` is set to true)
 * - [1]
 * - [2]
 * - [3]
 * - [1, 2]
 * - [1, 3]
 * - [2, 3]
 * - [1, 2, 3]
 *
 * @param set The set to get the combinations of.
 * @param includeEmptyArray Whether to include an empty array in the combinations.
 */
function getSetCombinations(set, includeEmptyArray) {
    const values = getSortedSetValues(set);
    const combinations = (0, array_1.getArrayCombinations)(values, includeEmptyArray);
    return combinations.map((array) => new ReadonlySet_1.ReadonlySet(array));
}
exports.getSetCombinations = getSetCombinations;
/**
 * Helper function to get a sorted array based on the contents of a set.
 *
 * Normally, set values are returned in insertion order, so use this function when the ordering of
 * the contents is important.
 */
// eslint-disable-next-line isaacscript/no-mutable-return
function getSortedSetValues(set) {
    const values = [...set];
    // Check for problematic types in order to throw a helpful error message.
    const firstElement = values[0];
    if (firstElement !== undefined) {
        const arrayType = type(firstElement);
        if (!(0, types_1.isPrimitive)(arrayType)) {
            error(`Failed to get the sorted set values because the provided set was of type "${arrayType}". Having sets with non-primitive types doesn't make much sense in general, so you might need to rethink what you are doing.`);
        }
    }
    values.sort();
    return values;
}
exports.getSortedSetValues = getSortedSetValues;
/**
 * Helper function to convert the keys of an object to a read-only set.
 *
 * Note that the set values will be inserted in a random order, due to how `pairs` works under the
 * hood.
 *
 * Also see the `objectKeysToSet` function.
 */
function objectKeysToReadonlySet(object) {
    return objectKeysToSet(object);
}
exports.objectKeysToReadonlySet = objectKeysToReadonlySet;
/**
 * Helper function to convert the keys of an object to a set.
 *
 * Note that the set values will be inserted in a random order, due to how `pairs` works under the
 * hood.
 *
 * Also see the `objectKeysToReadonlySet` function.
 */
// eslint-disable-next-line isaacscript/no-mutable-return
function objectKeysToSet(object) {
    const set = new Set();
    for (const key of Object.keys(object)) {
        set.add(key);
    }
    return set;
}
exports.objectKeysToSet = objectKeysToSet;
/**
 * Helper function to convert the values of an object to a read-only set.
 *
 * Note that the set values will be inserted in a random order, due to how `pairs` works under the
 * hood.
 *
 * Also see the `objectValuesToSet` function.
 */
function objectValuesToReadonlySet(object) {
    return objectValuesToSet(object);
}
exports.objectValuesToReadonlySet = objectValuesToReadonlySet;
/**
 * Helper function to convert the values of an object to a set.
 *
 * Note that the set values will be inserted in a random order, due to how `pairs` works under the
 * hood.
 *
 * Also see the `objectValuesToReadonlySet` function.
 */
// eslint-disable-next-line isaacscript/no-mutable-return
function objectValuesToSet(object) {
    const set = new Set();
    for (const key of Object.values(object)) {
        set.add(key);
    }
    return set;
}
exports.objectValuesToSet = objectValuesToSet;
/**
 * Helper function to add one or more elements to a set at once without having to repeatedly call
 * the `Set.add` method.
 *
 * This function is variadic, meaning that you can pass as many things as you want to add.
 */
// eslint-disable-next-line isaacscript/prefer-readonly-parameter-types
function setAdd(set, ...elements) {
    for (const element of elements) {
        set.add(element);
    }
}
exports.setAdd = setAdd;
/**
 * Helper function to check for one or more elements in a set at once without having to repeatedly
 * call the `Set.has` method.
 *
 * This function is variadic, meaning that you can pass as many things as you want to check for. It
 * will return true if one or more elements are found.
 */
function setHas(set, ...elements) {
    return elements.some((element) => set.has(element));
}
exports.setHas = setHas;
/** Helper function to sum every value in a set together. */
function sumSet(set) {
    const values = [...set];
    return (0, array_1.sumArray)(values);
}
exports.sumSet = sumSet;
