"use strict";
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
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;
};
Object.defineProperty(exports, "__esModule", { value: true });
var errors_1 = require("../../../components/error_boundary/errors");
var constants_1 = require("../../../scales/constants");
var commons_1 = require("../../../utils/commons");
var domain_1 = require("../../../utils/domain");
var logger_1 = require("../../../utils/logger");
var axis_type_utils_1 = require("../utils/axis_type_utils");
var specs_1 = require("../utils/specs");
function mergeYDomain(_a, specs, domainsByGroupId) {
    var stacked = _a.stacked, nonStacked = _a.nonStacked;
    var specsByGroupIds = splitSpecsByGroupId(specs);
    var specsByGroupIdsEntries = __spread(specsByGroupIds.entries());
    var globalId = specs_1.DEFAULT_GLOBAL_ID;
    var yDomains = specsByGroupIdsEntries.map(function (_a) {
        var _b = __read(_a, 2), groupId = _b[0], groupSpecs = _b[1];
        var _c, _d;
        var customDomain = domainsByGroupId.get(groupId);
        var emptyDS = {
            dataSeries: [],
            groupId: groupId,
            counts: { area: 0, bubble: 0, bar: 0, line: 0 },
        };
        var stackedDS = (_c = stacked.find(function (d) { return d.groupId === groupId; }), (_c !== null && _c !== void 0 ? _c : emptyDS));
        var nonStackedDS = (_d = nonStacked.find(function (d) { return d.groupId === groupId; }), (_d !== null && _d !== void 0 ? _d : emptyDS));
        var nonZeroBaselineSpecs = stackedDS.counts.bar + stackedDS.counts.area + nonStackedDS.counts.bar + nonStackedDS.counts.area;
        return mergeYDomainForGroup(stackedDS.dataSeries, nonStackedDS.dataSeries, groupId, groupSpecs, nonZeroBaselineSpecs > 0, customDomain);
    });
    var globalGroupIds = specs.reduce(function (acc, _a) {
        var groupId = _a.groupId, useDefaultGroupDomain = _a.useDefaultGroupDomain;
        if (groupId !== globalId && useDefaultGroupDomain) {
            acc.add(groupId);
        }
        return acc;
    }, new Set());
    globalGroupIds.add(globalId);
    var globalYDomains = yDomains.filter(function (domain) { return globalGroupIds.has(domain.groupId); });
    var globalYDomain = [Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER];
    globalYDomains.forEach(function (domain) {
        globalYDomain = [Math.min(globalYDomain[0], domain.domain[0]), Math.max(globalYDomain[1], domain.domain[1])];
    });
    return yDomains.map(function (domain) {
        if (globalGroupIds.has(domain.groupId)) {
            return __assign(__assign({}, domain), { domain: globalYDomain });
        }
        return domain;
    });
}
exports.mergeYDomain = mergeYDomain;
function mergeYDomainForGroup(stacked, nonStacked, groupId, groupSpecs, hasZeroBaselineSpecs, customDomain) {
    var _a;
    var groupYScaleType = coerceYScaleTypes(__spread(groupSpecs.stacked, groupSpecs.nonStacked));
    var stackMode = groupSpecs.stackMode;
    var domain;
    if (stackMode === specs_1.StackMode.Percentage) {
        domain = domain_1.computeContinuousDataDomain([0, 1], commons_1.identity, customDomain);
    }
    else {
        var newCustomDomain = customDomain ? __assign({}, customDomain) : {};
        var shouldScaleToExtent = groupSpecs.stacked.some(function (_a) {
            var yScaleToDataExtent = _a.yScaleToDataExtent;
            return yScaleToDataExtent;
        }) ||
            groupSpecs.nonStacked.some(function (_a) {
                var yScaleToDataExtent = _a.yScaleToDataExtent;
                return yScaleToDataExtent;
            });
        if (((_a = customDomain) === null || _a === void 0 ? void 0 : _a.fit) !== true && shouldScaleToExtent) {
            newCustomDomain.fit = true;
        }
        var stackedDomain = computeYDomain(stacked, hasZeroBaselineSpecs);
        var nonStackedDomain = computeYDomain(nonStacked, hasZeroBaselineSpecs);
        domain = domain_1.computeContinuousDataDomain(__spread(stackedDomain, nonStackedDomain), commons_1.identity, newCustomDomain);
        var _b = __read(domain, 2), computedDomainMin = _b[0], computedDomainMax = _b[1];
        if (newCustomDomain && axis_type_utils_1.isCompleteBound(newCustomDomain)) {
            domain = [newCustomDomain.min, newCustomDomain.max];
        }
        else if (newCustomDomain && axis_type_utils_1.isLowerBound(newCustomDomain)) {
            if (newCustomDomain.min > computedDomainMax) {
                throw new errors_1.GracefulError("custom yDomain for " + groupId + " is invalid, custom min is greater than computed max");
            }
            domain = [newCustomDomain.min, computedDomainMax];
        }
        else if (newCustomDomain && axis_type_utils_1.isUpperBound(newCustomDomain)) {
            if (computedDomainMin > newCustomDomain.max) {
                throw new Error("custom yDomain for " + groupId + " is invalid, computed min is greater than custom max");
            }
            domain = [computedDomainMin, newCustomDomain.max];
        }
    }
    return {
        type: 'yDomain',
        isBandScale: false,
        scaleType: groupYScaleType,
        groupId: groupId,
        domain: domain,
    };
}
function computeYDomain(dataseries, hasZeroBaselineSpecs) {
    var yValues = new Set();
    dataseries.forEach(function (ds) {
        ds.data.forEach(function (datum) {
            yValues.add(datum.y1);
            if (hasZeroBaselineSpecs && datum.y0 != null) {
                yValues.add(datum.y0);
            }
        });
    });
    if (yValues.size === 0) {
        return [];
    }
    return domain_1.computeContinuousDataDomain(__spread(yValues.values()), commons_1.identity, null);
}
function splitSpecsByGroupId(specs) {
    var specsByGroupIds = new Map();
    var isHistogramEnabled = specs.some(function (_a) {
        var seriesType = _a.seriesType, enableHistogramMode = _a.enableHistogramMode;
        return seriesType === specs_1.SeriesTypes.Bar && enableHistogramMode;
    });
    specs.forEach(function (spec) {
        var group = specsByGroupIds.get(spec.groupId) || {
            stackMode: undefined,
            stacked: [],
            nonStacked: [],
        };
        if ((spec.seriesType === specs_1.SeriesTypes.Bar && isHistogramEnabled) ||
            (spec.stackAccessors && spec.stackAccessors.length > 0)) {
            group.stacked.push(spec);
        }
        else {
            group.nonStacked.push(spec);
        }
        if (group.stackMode === undefined && spec.stackMode !== undefined) {
            group.stackMode = spec.stackMode;
        }
        if (spec.stackMode !== undefined && group.stackMode !== undefined && group.stackMode !== spec.stackMode) {
            logger_1.Logger.warn("Is not possible to mix different stackModes, please align all stackMode on the same GroupId\n      to the same mode. The default behaviour will be to use the first encountered stackMode on the series");
        }
        specsByGroupIds.set(spec.groupId, group);
    });
    return specsByGroupIds;
}
exports.splitSpecsByGroupId = splitSpecsByGroupId;
function coerceYScaleTypes(specs) {
    var scaleTypes = new Set();
    specs.forEach(function (spec) {
        scaleTypes.add(spec.yScaleType);
    });
    return coerceYScale(scaleTypes);
}
exports.coerceYScaleTypes = coerceYScaleTypes;
function coerceYScale(scaleTypes) {
    if (scaleTypes.size === 1) {
        var scales = scaleTypes.values();
        var value = scales.next().value;
        return value;
    }
    return constants_1.ScaleType.Linear;
}
//# sourceMappingURL=y_domain.js.map