"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: all[name]
    });
}
_export(exports, {
    EPSILON: function() {
        return EPSILON;
    },
    createAngularScale: function() {
        return createAngularScale;
    },
    createRadialScale: function() {
        return createRadialScale;
    },
    formatAngle: function() {
        return formatAngle;
    },
    getContinuousScaleDomain: function() {
        return getContinuousScaleDomain;
    },
    getScaleType: function() {
        return getScaleType;
    }
});
const _d3scale = require("d3-scale");
const _d3array = require("d3-array");
const _d3format = require("d3-format");
const _utilities = require("../../utilities/utilities");
const _chartutilities = require("@fluentui/chart-utilities");
const _d3timeformat = require("d3-time-format");
const EPSILON = 1e-6;
const createRadialScale = (scaleType, domain, range, opts = {})=>{
    if (scaleType === 'category') {
        const scale = (0, _d3scale.scaleBand)().domain(domain).range(range).paddingInner(1);
        const tickValues = Array.isArray(opts.tickValues) ? opts.tickValues : domain;
        const tickFormat = (domainValue, index)=>{
            if (Array.isArray(opts.tickValues) && Array.isArray(opts.tickText) && !(0, _chartutilities.isInvalidValue)(opts.tickText[index])) {
                return opts.tickText[index];
            }
            return domainValue;
        };
        return {
            scale,
            tickValues,
            tickLabels: tickValues.map(tickFormat)
        };
    }
    let scale;
    if (scaleType === 'date') {
        scale = opts.useUTC ? (0, _d3scale.scaleUtc)() : (0, _d3scale.scaleTime)();
    } else {
        scale = scaleType === 'log' ? (0, _d3scale.scaleLog)() : (0, _d3scale.scaleLinear)();
    }
    scale.domain(domain);
    scale.range(range);
    scale.nice();
    var _opts_tickCount;
    const tickCount = (_opts_tickCount = opts.tickCount) !== null && _opts_tickCount !== void 0 ? _opts_tickCount : 4;
    let tickFormat;
    let customTickValues = Array.isArray(opts.tickValues) ? opts.tickValues : undefined;
    if (scaleType === 'date') {
        let lowestFormatLevel = 100;
        let highestFormatLevel = -1;
        scale.ticks().forEach((domainValue)=>{
            const formatLevel = (0, _utilities.getDateFormatLevel)(domainValue, opts.useUTC);
            if (formatLevel > highestFormatLevel) {
                highestFormatLevel = formatLevel;
            }
            if (formatLevel < lowestFormatLevel) {
                lowestFormatLevel = formatLevel;
            }
        });
        var _opts_dateLocalizeOptions;
        const formatOptions = (_opts_dateLocalizeOptions = opts.dateLocalizeOptions) !== null && _opts_dateLocalizeOptions !== void 0 ? _opts_dateLocalizeOptions : (0, _chartutilities.getMultiLevelDateTimeFormatOptions)(lowestFormatLevel, highestFormatLevel);
        tickFormat = (domainValue, index)=>{
            if (Array.isArray(opts.tickValues) && Array.isArray(opts.tickText) && !(0, _chartutilities.isInvalidValue)(opts.tickText[index])) {
                return opts.tickText[index];
            }
            if ((0, _chartutilities.isInvalidValue)(opts.culture) && typeof opts.tickFormat === 'string') {
                if (opts.useUTC) {
                    return (0, _d3timeformat.utcFormat)(opts.tickFormat)(domainValue);
                } else {
                    return (0, _d3timeformat.timeFormat)(opts.tickFormat)(domainValue);
                }
            }
            return (0, _chartutilities.formatDateToLocaleString)(domainValue, opts.culture, opts.useUTC, false, formatOptions);
        };
        if (opts.tickStep) {
            customTickValues = (0, _utilities.generateDateTicks)(opts.tickStep, opts.tick0, scale.domain(), opts.useUTC);
        }
    } else {
        const defaultTickFormat = scale.tickFormat(tickCount);
        tickFormat = (domainValue, index)=>{
            if (Array.isArray(opts.tickValues) && Array.isArray(opts.tickText) && !(0, _chartutilities.isInvalidValue)(opts.tickText[index])) {
                return opts.tickText[index];
            }
            if (typeof opts.tickFormat === 'string') {
                return (0, _d3format.format)(opts.tickFormat)(domainValue);
            }
            const value = typeof domainValue === 'number' ? domainValue : domainValue.valueOf();
            return defaultTickFormat(value) === '' ? '' : (0, _chartutilities.formatToLocaleString)(value, opts.culture);
        };
        if (opts.tickStep) {
            customTickValues = (0, _utilities.generateNumericTicks)(scaleType, opts.tickStep, opts.tick0, scale.domain());
        }
    }
    const tickValues = customTickValues !== null && customTickValues !== void 0 ? customTickValues : scale.ticks(tickCount);
    return {
        scale,
        tickValues,
        tickLabels: tickValues.map(tickFormat)
    };
};
const getScaleType = (values, opts = {})=>{
    let scaleType = 'category';
    if (typeof values[0] === 'number') {
        if (opts.supportsLog && opts.scaleType === 'log') {
            scaleType = 'log';
        } else {
            scaleType = 'linear';
        }
    } else if (values[0] instanceof Date) {
        scaleType = 'date';
    }
    return scaleType;
};
const getContinuousScaleDomain = (scaleType, values, opts = {})=>{
    let [min, max] = (0, _d3array.extent)(values.filter((v)=>(0, _utilities.isValidDomainValue)(v, scaleType)));
    if (scaleType === 'linear') {
        [min, max] = (0, _d3array.extent)([
            min,
            max,
            0
        ]);
    }
    if (!(0, _chartutilities.isInvalidValue)(opts.rangeStart)) {
        min = opts.rangeStart;
    }
    if (!(0, _chartutilities.isInvalidValue)(opts.rangeEnd)) {
        max = opts.rangeEnd;
    }
    if ((0, _chartutilities.isInvalidValue)(min) || (0, _chartutilities.isInvalidValue)(max)) {
        return [];
    }
    return [
        min,
        max
    ];
};
const degToRad = (deg)=>deg * Math.PI / 180;
const radToDeg = (rad)=>rad * 180 / Math.PI;
const normalizeAngle = (deg, direction)=>((direction === 'clockwise' ? deg : 450 - deg) % 360 + 360) % 360;
const createAngularScale = (scaleType, domain, opts = {})=>{
    if (scaleType === 'category') {
        const categoryIndexMap = {};
        domain.forEach((d, i)=>{
            categoryIndexMap[d] = i;
        });
        const period = 360 / domain.length;
        const tickValues = Array.isArray(opts.tickValues) ? opts.tickValues : domain;
        const tickFormat = (domainValue, index)=>{
            if (Array.isArray(opts.tickValues) && Array.isArray(opts.tickText) && !(0, _chartutilities.isInvalidValue)(opts.tickText[index])) {
                return opts.tickText[index];
            }
            return domainValue;
        };
        return {
            scale: (v)=>degToRad(normalizeAngle(categoryIndexMap[v] * period, opts.direction)),
            tickValues,
            tickLabels: tickValues.map(tickFormat)
        };
    }
    let customTickValues = Array.isArray(opts.tickValues) ? opts.tickValues : undefined;
    const tickFormat = (domainValue, index)=>{
        if (Array.isArray(opts.tickValues) && Array.isArray(opts.tickText) && !(0, _chartutilities.isInvalidValue)(opts.tickText[index])) {
            return opts.tickText[index];
        }
        if (typeof opts.tickFormat === 'string') {
            return (0, _d3format.format)(opts.tickFormat)(domainValue);
        }
        return formatAngle(domainValue, opts.unit);
    };
    if (opts.tickStep) {
        var _generateNumericTicks;
        customTickValues = (_generateNumericTicks = (0, _utilities.generateNumericTicks)(scaleType, opts.tickStep, opts.tick0, [
            0,
            (opts.unit === 'radians' ? 2 * Math.PI : 360) - EPSILON
        ])) === null || _generateNumericTicks === void 0 ? void 0 : _generateNumericTicks.map((v)=>opts.unit === 'radians' ? radToDeg(v) : v);
    }
    var _opts_tickCount;
    const tickValues = customTickValues !== null && customTickValues !== void 0 ? customTickValues : (0, _d3array.range)(0, 360, 360 / ((_opts_tickCount = opts.tickCount) !== null && _opts_tickCount !== void 0 ? _opts_tickCount : 8));
    return {
        scale: (v)=>degToRad(normalizeAngle(v, opts.direction)),
        tickValues,
        tickLabels: tickValues.map(tickFormat)
    };
};
const formatAngle = (value, unit)=>typeof value === 'string' ? value : unit === 'radians' ? `${(0, _utilities.precisionRound)(value / 180, 6)}π` : `${(0, _utilities.precisionRound)(value, 6)}°`;
