"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;
};
Object.defineProperty(exports, "__esModule", { value: true });
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 mergeXDomain(specs, xValues, customXDomain, fallbackScale) {
    var mainXScaleType = convertXScaleTypes(specs);
    if (!mainXScaleType) {
        throw new Error("Cannot merge the domain. Missing X scale types " + JSON.stringify(specs));
    }
    var values = __spread(xValues.values());
    var seriesXComputedDomains;
    var minInterval = 0;
    if (mainXScaleType.scaleType === constants_1.ScaleType.Ordinal || fallbackScale === constants_1.ScaleType.Ordinal) {
        if (mainXScaleType.scaleType !== constants_1.ScaleType.Ordinal) {
            logger_1.Logger.warn("Each X value in a " + mainXScaleType.scaleType + " x scale needs be be a number. Using ordinal x scale as fallback.");
        }
        seriesXComputedDomains = domain_1.computeOrdinalDataDomain(values, commons_1.identity, false, true);
        if (customXDomain) {
            if (Array.isArray(customXDomain)) {
                seriesXComputedDomains = customXDomain;
            }
            else {
                if (fallbackScale === constants_1.ScaleType.Ordinal) {
                    logger_1.Logger.warn("xDomain ignored for fallback ordinal scale. Options to resolve:\n\n1) Correct data to match " + mainXScaleType.scaleType + " scale type (see previous warning)\n2) Change xScaleType to ordinal and set xDomain to Domain array");
                }
                else {
                    throw new TypeError('xDomain for ordinal scale should be an array of values, not a DomainRange object.');
                }
            }
        }
    }
    else {
        seriesXComputedDomains = domain_1.computeContinuousDataDomain(values, commons_1.identity, { fit: true });
        var customMinInterval = void 0;
        if (customXDomain) {
            if (Array.isArray(customXDomain)) {
                throw new TypeError('xDomain for continuous scale should be a DomainRange object, not an array');
            }
            customMinInterval = customXDomain.minInterval;
            var _a = __read(seriesXComputedDomains, 2), computedDomainMin = _a[0], computedDomainMax = _a[1];
            if (axis_type_utils_1.isCompleteBound(customXDomain)) {
                if (customXDomain.min > customXDomain.max) {
                    throw new Error('custom xDomain is invalid, min is greater than max');
                }
                seriesXComputedDomains = [customXDomain.min, customXDomain.max];
            }
            else if (axis_type_utils_1.isLowerBound(customXDomain)) {
                if (customXDomain.min > computedDomainMax) {
                    throw new Error('custom xDomain is invalid, custom min is greater than computed max');
                }
                seriesXComputedDomains = [customXDomain.min, computedDomainMax];
            }
            else if (axis_type_utils_1.isUpperBound(customXDomain)) {
                if (computedDomainMin > customXDomain.max) {
                    throw new Error('custom xDomain is invalid, computed min is greater than custom max');
                }
                seriesXComputedDomains = [computedDomainMin, customXDomain.max];
            }
        }
        var computedMinInterval = findMinInterval(values);
        if (customMinInterval != null) {
            if (xValues.size > 1 && customMinInterval > computedMinInterval) {
                throw new Error('custom xDomain is invalid, custom minInterval is greater than computed minInterval');
            }
            if (customMinInterval < 0) {
                throw new Error('custom xDomain is invalid, custom minInterval is less than 0');
            }
        }
        minInterval = customMinInterval || computedMinInterval;
    }
    return {
        type: 'xDomain',
        scaleType: (fallbackScale !== null && fallbackScale !== void 0 ? fallbackScale : mainXScaleType.scaleType),
        isBandScale: mainXScaleType.isBandScale,
        domain: seriesXComputedDomains,
        minInterval: minInterval,
        timeZone: mainXScaleType.timeZone,
    };
}
exports.mergeXDomain = mergeXDomain;
function findMinInterval(xValues) {
    var valuesLength = xValues.length;
    if (valuesLength <= 0) {
        return 0;
    }
    if (valuesLength === 1) {
        return 1;
    }
    var sortedValues = xValues.slice().sort(commons_1.compareByValueAsc);
    var i;
    var minInterval = Math.abs(sortedValues[1] - sortedValues[0]);
    for (i = 1; i < valuesLength - 1; i++) {
        var current = sortedValues[i];
        var next = sortedValues[i + 1];
        var interval = Math.abs(next - current);
        minInterval = Math.min(minInterval, interval);
    }
    return minInterval;
}
exports.findMinInterval = findMinInterval;
function convertXScaleTypes(specs) {
    var seriesTypes = new Set();
    var scaleTypes = new Set();
    var timeZones = new Set();
    specs.forEach(function (spec) {
        seriesTypes.add(spec.seriesType);
        scaleTypes.add(spec.xScaleType);
        if (spec.timeZone) {
            timeZones.add(spec.timeZone.toLowerCase());
        }
    });
    if (specs.length === 0 || seriesTypes.size === 0 || scaleTypes.size === 0) {
        return null;
    }
    var isBandScale = seriesTypes.has(specs_1.SeriesTypes.Bar);
    if (scaleTypes.size === 1) {
        var scaleType = scaleTypes.values().next().value;
        var timeZone = void 0;
        if (scaleType === constants_1.ScaleType.Time) {
            if (timeZones.size > 1) {
                timeZone = 'utc';
            }
            else {
                timeZone = timeZones.values().next().value;
            }
        }
        return { scaleType: scaleType, isBandScale: isBandScale, timeZone: timeZone };
    }
    if (scaleTypes.size > 1 && scaleTypes.has(constants_1.ScaleType.Ordinal)) {
        return { scaleType: constants_1.ScaleType.Ordinal, isBandScale: isBandScale };
    }
    return { scaleType: constants_1.ScaleType.Linear, isBandScale: isBandScale };
}
exports.convertXScaleTypes = convertXScaleTypes;
//# sourceMappingURL=x_domain.js.map