"use strict";

module.exports = {

	/**
  * Generates a random value from normal distribution
  * (Copied from StackOverflow)
  * @return {float}
  */
	generateNormal(mean, dev, min = null, max = null) {

		// Generate raw deviation
		var u = 1 - Math.random(); // Subtraction to flip [0, 1) to (0, 1].
		var v = 1 - Math.random();
		let val = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);

		// Apply to our mean
		val = mean + val * dev;

		if (min !== null && max !== null) {
			return Math.min(Math.max(val, min), max);
		} else if (min !== null) {
			return Math.max(val, min);
		} else if (max !== null) {
			return Math.min(val, max);
		} else {
			return val;
		}
	},

	/**
  * Generates a random value from normal distribution, and rounds it
  * for convenience.
  * @return {int}
  */
	generateRoundedNormal(mean, dev, min = null, max = null) {
		return Math.round(this.generateNormal(mean, dev, min, max));
	},

	/**
  * This will take an average, a range, and a number of items, and it will
  * generate a data set where the items can fit within the range, but the
  * average of the set will forcibly match the average provided.
  * @param  {int|float} average (Can be a float, but only if you don't mind a minor variance from the average)
  * @param  {int} range 
  * @param  {int} numItems
  * @return {array}       
  */
	generateDataWithForcedAverage(average, range, numItems) {

		let set = [];

		let remaining = numItems * average;
		for (let i = 0; i < numItems; i++) {

			let val;

			if (i === numItems - 1) {

				val = Math.round(remaining);
			} else {

				// Prep
				let itemsRemaining = numItems - i;
				let itemsRemainingAfterThisOne = numItems - i - 1;
				let averageRemaining = remaining / itemsRemaining;
				let min = average - range * 0.5;
				let max = average + range * 0.5;

				// Ensure we always end up with the correct average
				if (averageRemaining < average) {
					max = Math.min(max, remaining - itemsRemainingAfterThisOne * min);
				} else if (averageRemaining > average) {
					min = Math.max(min, remaining - itemsRemainingAfterThisOne * max);
				}

				// Figure out skill level
				val = Math.round(Math.floor(Math.random() * (max - min + 1)) + min);
			}

			// Tracking
			remaining -= val;

			set.push(val);
		}

		return set;
	}

};
//# sourceMappingURL=stats.js.map