{"version":3,"file":"index.umd.cjs","sources":["../src/index.ts"],"sourcesContent":["interface Options<T> {\n  /**\n   * Optional shuffle function. If provided, this function will be used to shuffle the entries.\n   */\n  shuffle?: (input: T[]) => T[];\n  /**\n   * Optional channel name. If provided, this name will be used as the channel name.\n   */\n  channelName?: string;\n  /**\n   * @default true\n   * - By defult, replacement is set to ture, drawn entries will be put back into the pool for feature draws.\n   * - If true, the winner is not removed from the lottery and can be drawn again.\n   * - If false, the winner is removed from the lottery after being drawn.\n   */\n  replacement?: boolean;\n}\n\ninterface DrawOptions<T> {\n  /**\n   * By default, the value inherits from the `options.replacement` provided in the constructor.\n   */\n  replacement?: Options<T>[\"replacement\"];\n}\n\nclass MagicLottery<T> {\n  private entries: T[] = [];\n  private shuffledEntries: T[] = [];\n  private shuffle: (input: T[]) => T[];\n  private channelName?: string;\n  private replacement: boolean;\n\n  constructor(entries: T[], options: Options<T> = {}) {\n    this.entries = entries;\n\n    this.shuffle = options.shuffle || this.defaultShuffle;\n    this.shuffledEntries = this.shuffle([...this.entries]);\n\n    this.channelName = options.channelName;\n    this.replacement = options.replacement || true;\n  }\n\n  /**\n   * Set the channel name.\n   * @param channelName - The name of the channel.\n   */\n  setChannelName(channelName: string): void {\n    this.channelName = channelName;\n  }\n\n  /**\n   * Get the channel name.\n   * @returns The name of the channel or undefined if not set.\n   */\n  getChannelName(): string | undefined {\n    return this.channelName;\n  }\n\n  /**\n   * Add entries to the lottery.\n   * @param entries - The entries to add.\n   */\n  add(entries: T[]): void {\n    this.entries.push(...entries);\n    this.shuffledEntries = this.shuffle([...this.entries]);\n  }\n\n  /**\n   * Draw all shuffled entries.\n   * @returns The shuffled entries.\n   */\n  draw(): T[] {\n    return [...this.shuffledEntries];\n  }\n\n  /**\n   * Draw all original entries.\n   * @returns The original entries.\n   */\n  drawOriginal(): T[] {\n    return [...this.entries];\n  }\n\n  /**\n   * Draw the first winner from the shuffled entries.\n   * @param [options={ replacement: this.replacement }]\n   * @returns The first winner. Throws an error if there is no entry.\n   */\n  drawWinner(options: DrawOptions<T> = { replacement: this.replacement }): T {\n    const { replacement } = options;\n\n    if (this.shuffledEntries.length > 0) {\n      const winner = this.shuffledEntries[0];\n      if (!replacement) {\n        this.remove(winner);\n      }\n      return winner;\n    } else {\n      throw new Error(\"At least one entry is required.\");\n    }\n  }\n\n  /**\n   * Draw a specified number of winners from the shuffled entries.\n   * @param num - The number of winners to draw.\n   * @param [options={ replacement: this.replacement }]\n   * @returns The winners. Throws an error if the requested number of winners exceeds the total entries.\n   */\n  drawWinners(\n    num: number,\n    options: DrawOptions<T> = { replacement: this.replacement }\n  ): T[] {\n    const { replacement } = options;\n\n    if (num <= this.shuffledEntries.length) {\n      const winners = this.shuffledEntries.slice(0, num);\n      if (!replacement) {\n        winners.forEach((winner) => this.remove(winner));\n      }\n      return winners;\n    } else {\n      throw new Error(\"Requested number of winners exceeds the total entries.\");\n    }\n  }\n\n  /**\n   * Set the shuffle method.\n   * @param shuffle - The shuffle method to set.\n   */\n  setShuffle(shuffle: (input: T[]) => T[]): void {\n    this.shuffle = shuffle;\n    this.shuffledEntries = this.shuffle([...this.entries]);\n  }\n\n  /**\n   * Get the shuffle method.\n   * @returns The shuffle method.\n   */\n  getShuffle(): (input: T[]) => T[] {\n    return this.shuffle;\n  }\n\n  /**\n   * Remove an entry from the lottery.\n   * @param entry - The entry to remove.\n   */\n  remove(entry: T): void {\n    const index = this.entries.indexOf(entry);\n    if (index > -1) {\n      this.entries.splice(index, 1);\n      this.shuffledEntries = this.shuffle([...this.entries]);\n    }\n  }\n\n  /**\n   * Check if an entry is in the lottery.\n   * @param entry - The entry to check.\n   * @returns True if the entry is in the lottery, false otherwise.\n   */\n  hasEntry(entry: T): boolean {\n    return this.entries.includes(entry);\n  }\n\n  /**\n   * Get the size of the lottery.\n   * @returns The size of the lottery.\n   */\n  size(): number {\n    return this.entries.length;\n  }\n\n  /**\n   * Check if the lottery is empty.\n   * @returns True if the lottery is empty, false otherwise.\n   */\n  isEmpty(): boolean {\n    return this.entries.length === 0;\n  }\n\n  /**\n   * Reset the lottery.\n   */\n  reset(): void {\n    this.entries = [];\n    this.shuffledEntries = [];\n  }\n\n  /**\n   * Draw the next winner from the shuffled entries and optionally remove them from the lottery.\n   * @param [options={ replacement: this.replacement }]\n   * @returns A promise that resolves with the next winner or rejects if there are no more entries left.\n   */\n  async nextWinner(\n    options: DrawOptions<T> = { replacement: this.replacement }\n  ): Promise<T | undefined> {\n    const { replacement } = options;\n\n    return new Promise((resolve, reject) => {\n      if (this.shuffledEntries.length > 0) {\n        const winner = this.shuffledEntries[0];\n        if (!replacement) {\n          this.remove(winner);\n        }\n        resolve(winner);\n      } else {\n        reject(\"No more entries left.\");\n      }\n    });\n  }\n\n  /**\n   * Implements the Fisher-Yates Shuffle Algorithm as the default shuffling method.\n   * This method is used to shuffle the entries of the lottery.\n   * See wikipedia at https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle.\n   * @param input - The array to shuffle.\n   * @returns The shuffled array.\n   */\n  private defaultShuffle(input: T[]): T[] {\n    const array = [...input];\n    let currentIndex = array.length;\n    let temporaryValue: T;\n    let randomIndex: number;\n\n    while (0 !== currentIndex) {\n      randomIndex = Math.floor(Math.random() * currentIndex);\n      currentIndex -= 1;\n\n      // swap array[currentIndex] with array[randomIndex]\n      temporaryValue = array[currentIndex];\n      array[currentIndex] = array[randomIndex];\n      array[randomIndex] = temporaryValue;\n    }\n\n    return array;\n  }\n}\n\n/**\n * This is the default export, but named exports are recommended for future usage.\n */\nexport default MagicLottery;\n\nexport { MagicLottery, MagicLottery as Lottery };\n"],"names":["MagicLottery","entries","options","__publicField","channelName","replacement","winner","num","winners","shuffle","entry","index","resolve","reject","input","array","currentIndex","temporaryValue","randomIndex"],"mappings":"4YAyBA,MAAMA,CAAgB,CAOpB,YAAYC,EAAcC,EAAsB,GAAI,CAN5CC,EAAA,eAAe,CAAA,GACfA,EAAA,uBAAuB,CAAA,GACvBA,EAAA,gBACAA,EAAA,oBACAA,EAAA,oBAGN,KAAK,QAAUF,EAEV,KAAA,QAAUC,EAAQ,SAAW,KAAK,eACvC,KAAK,gBAAkB,KAAK,QAAQ,CAAC,GAAG,KAAK,OAAO,CAAC,EAErD,KAAK,YAAcA,EAAQ,YACtB,KAAA,YAAcA,EAAQ,aAAe,EAC5C,CAMA,eAAeE,EAA2B,CACxC,KAAK,YAAcA,CACrB,CAMA,gBAAqC,CACnC,OAAO,KAAK,WACd,CAMA,IAAIH,EAAoB,CACjB,KAAA,QAAQ,KAAK,GAAGA,CAAO,EAC5B,KAAK,gBAAkB,KAAK,QAAQ,CAAC,GAAG,KAAK,OAAO,CAAC,CACvD,CAMA,MAAY,CACH,MAAA,CAAC,GAAG,KAAK,eAAe,CACjC,CAMA,cAAoB,CACX,MAAA,CAAC,GAAG,KAAK,OAAO,CACzB,CAOA,WAAWC,EAA0B,CAAE,YAAa,KAAK,aAAkB,CACnE,KAAA,CAAE,YAAAG,CAAgB,EAAAH,EAEpB,GAAA,KAAK,gBAAgB,OAAS,EAAG,CAC7B,MAAAI,EAAS,KAAK,gBAAgB,CAAC,EACrC,OAAKD,GACH,KAAK,OAAOC,CAAM,EAEbA,CAAA,KAED,OAAA,IAAI,MAAM,iCAAiC,CAErD,CAQA,YACEC,EACAL,EAA0B,CAAE,YAAa,KAAK,aACzC,CACC,KAAA,CAAE,YAAAG,CAAgB,EAAAH,EAEpB,GAAAK,GAAO,KAAK,gBAAgB,OAAQ,CACtC,MAAMC,EAAU,KAAK,gBAAgB,MAAM,EAAGD,CAAG,EACjD,OAAKF,GACHG,EAAQ,QAASF,GAAW,KAAK,OAAOA,CAAM,CAAC,EAE1CE,CAAA,KAED,OAAA,IAAI,MAAM,wDAAwD,CAE5E,CAMA,WAAWC,EAAoC,CAC7C,KAAK,QAAUA,EACf,KAAK,gBAAkB,KAAK,QAAQ,CAAC,GAAG,KAAK,OAAO,CAAC,CACvD,CAMA,YAAkC,CAChC,OAAO,KAAK,OACd,CAMA,OAAOC,EAAgB,CACrB,MAAMC,EAAQ,KAAK,QAAQ,QAAQD,CAAK,EACpCC,EAAQ,KACL,KAAA,QAAQ,OAAOA,EAAO,CAAC,EAC5B,KAAK,gBAAkB,KAAK,QAAQ,CAAC,GAAG,KAAK,OAAO,CAAC,EAEzD,CAOA,SAASD,EAAmB,CACnB,OAAA,KAAK,QAAQ,SAASA,CAAK,CACpC,CAMA,MAAe,CACb,OAAO,KAAK,QAAQ,MACtB,CAMA,SAAmB,CACV,OAAA,KAAK,QAAQ,SAAW,CACjC,CAKA,OAAc,CACZ,KAAK,QAAU,GACf,KAAK,gBAAkB,EACzB,CAOA,MAAM,WACJR,EAA0B,CAAE,YAAa,KAAK,aACtB,CAClB,KAAA,CAAE,YAAAG,CAAgB,EAAAH,EAExB,OAAO,IAAI,QAAQ,CAACU,EAASC,IAAW,CAClC,GAAA,KAAK,gBAAgB,OAAS,EAAG,CAC7B,MAAAP,EAAS,KAAK,gBAAgB,CAAC,EAChCD,GACH,KAAK,OAAOC,CAAM,EAEpBM,EAAQN,CAAM,CAAA,MAEdO,EAAO,uBAAuB,CAChC,CACD,CACH,CASQ,eAAeC,EAAiB,CAChC,MAAAC,EAAQ,CAAC,GAAGD,CAAK,EACvB,IAAIE,EAAeD,EAAM,OACrBE,EACAC,EAEJ,KAAaF,IAAN,GACLE,EAAc,KAAK,MAAM,KAAK,OAAA,EAAWF,CAAY,EACrCA,GAAA,EAGhBC,EAAiBF,EAAMC,CAAY,EAC7BD,EAAAC,CAAY,EAAID,EAAMG,CAAW,EACvCH,EAAMG,CAAW,EAAID,EAGhB,OAAAF,CACT,CACF"}