"use strict";
var __read = (this && this.__read) || function (o, n) {
    var m = typeof Symbol === "function" && o[Symbol.iterator];
    if (!m) return o;
    var i = m.call(o), r, ar = [], e;
    try {
        while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
    }
    catch (error) { e = { error: error }; }
    finally {
        try {
            if (r && !r.done && (m = i["return"])) m.call(i);
        }
        finally { if (e) throw e.error; }
    }
    return ar;
};
var __spread = (this && this.__spread) || function () {
    for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
    return ar;
};
var __values = (this && this.__values) || function (o) {
    var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
    if (m) return m.call(o);
    return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
};
exports.__esModule = true;
var Stream_1 = require("../../stream/Stream");
var Property_1 = require("../property/Property");
var UnbiasedProperty_1 = require("../property/UnbiasedProperty");
var QualifiedParameters_1 = require("./configuration/QualifiedParameters");
var Tosser_1 = require("./Tosser");
var PathWalker_1 = require("./utils/PathWalker");
/** @hidden */
function toProperty(generator, qParams) {
    var prop = !generator.hasOwnProperty('isAsync')
        ? new Property_1.Property(generator, function () { return true; })
        : generator;
    return qParams.unbiased === true ? new UnbiasedProperty_1.UnbiasedProperty(prop) : prop;
}
/** @hidden */
function streamSample(generator, params) {
    var qParams = QualifiedParameters_1.QualifiedParameters.readOrNumRuns(params);
    var tossedValues = Stream_1.stream(Tosser_1["default"](toProperty(generator, qParams), qParams.seed));
    if (qParams.path.length === 0) {
        return tossedValues.take(qParams.numRuns).map(function (s) { return s().value; });
    }
    return Stream_1.stream(PathWalker_1.pathWalk(qParams.path, tossedValues.map(function (s) { return s(); })))
        .take(qParams.numRuns)
        .map(function (s) { return s.value; });
}
/**
 * Generate an array containing all the values that would have been generated during {@link assert} or {@link check}
 *
 * @example
 * ```typescript
 * fc.sample(fc.nat(), 10); // extract 10 values from fc.nat() Arbitrary
 * fc.sample(fc.nat(), {seed: 42}); // extract values from fc.nat() as if we were running fc.assert with seed=42
 * ```
 *
 * @param generator {@link IProperty} or {@link Arbitrary} to extract the values from
 * @param params Integer representing the number of values to generate or {@link Parameters} as in {@link assert}
 */
function sample(generator, params) {
    return __spread(streamSample(generator, params));
}
exports.sample = sample;
/**
 * Gather useful statistics concerning generated values
 *
 * Print the result in `console.log` or `params.logger` (if defined)
 *
 * @example
 * ```typescript
 * fc.statistics(
 *     fc.nat(999),
 *     v => v < 100 ? 'Less than 100' : 'More or equal to 100',
 *     {numRuns: 1000, logger: console.log});
 * // Classify 1000 values generated by fc.nat(999) into two categories:
 * // - Less than 100
 * // - More or equal to 100
 * // The output will be sent line by line to the logger
 * ```
 *
 * @param generator {@link IProperty} or {@link Arbitrary} to extract the values from
 * @param classify Classifier function that can classify the generated value in zero, one or more categories (with free labels)
 * @param params Integer representing the number of values to generate or {@link Parameters} as in {@link assert}
 */
function statistics(generator, classify, params) {
    var qParams = QualifiedParameters_1.QualifiedParameters.readOrNumRuns(params);
    var recorded = {};
    try {
        for (var _a = __values(streamSample(generator, params)), _b = _a.next(); !_b.done; _b = _a.next()) {
            var g = _b.value;
            var out = classify(g);
            var categories = Array.isArray(out) ? out : [out];
            try {
                for (var categories_1 = __values(categories), categories_1_1 = categories_1.next(); !categories_1_1.done; categories_1_1 = categories_1.next()) {
                    var c = categories_1_1.value;
                    recorded[c] = (recorded[c] || 0) + 1;
                }
            }
            catch (e_1_1) { e_1 = { error: e_1_1 }; }
            finally {
                try {
                    if (categories_1_1 && !categories_1_1.done && (_c = categories_1["return"])) _c.call(categories_1);
                }
                finally { if (e_1) throw e_1.error; }
            }
        }
    }
    catch (e_2_1) { e_2 = { error: e_2_1 }; }
    finally {
        try {
            if (_b && !_b.done && (_d = _a["return"])) _d.call(_a);
        }
        finally { if (e_2) throw e_2.error; }
    }
    var data = Object.entries(recorded)
        .sort(function (a, b) { return b[1] - a[1]; })
        .map(function (i) { return [i[0], (i[1] * 100.0 / qParams.numRuns).toFixed(2) + "%"]; });
    var longestName = data.map(function (i) { return i[0].length; }).reduce(function (p, c) { return Math.max(p, c); }, 0);
    var longestPercent = data.map(function (i) { return i[1].length; }).reduce(function (p, c) { return Math.max(p, c); }, 0);
    try {
        for (var data_1 = __values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
            var item = data_1_1.value;
            qParams.logger(item[0].padEnd(longestName, '.') + ".." + item[1].padStart(longestPercent, '.'));
        }
    }
    catch (e_3_1) { e_3 = { error: e_3_1 }; }
    finally {
        try {
            if (data_1_1 && !data_1_1.done && (_e = data_1["return"])) _e.call(data_1);
        }
        finally { if (e_3) throw e_3.error; }
    }
    var e_2, _d, e_1, _c, e_3, _e;
}
exports.statistics = statistics;
//# sourceMappingURL=Sampler.js.map