"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
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 _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SmartDateLabelProvider = exports.DEFAULT_LABEL_THRESHOLDS = exports.EHighPrecisionLabelMode = exports.EDatePrecision = exports.ETradeChartLabelFormat = void 0;
var LabelProviderType_1 = require("../../../../types/LabelProviderType");
var NumericFormat_1 = require("../../../../types/NumericFormat");
var date_1 = require("../../../../utils/date");
var number_1 = require("../../../../utils/number");
var LabelProviderBase2D_1 = require("./LabelProviderBase2D");
var ETradeChartLabelFormat;
(function (ETradeChartLabelFormat) {
    ETradeChartLabelFormat["Nanoseconds"] = "Nanoseconds";
    ETradeChartLabelFormat["Microseconds"] = "Microseconds";
    /** @example `04:01`, `45.1234`, `46.3456` */
    ETradeChartLabelFormat["MilliSeconds"] = "MilliSeconds";
    /** @example `Apr 25`, `04:01:45`, `02:02:30` */
    ETradeChartLabelFormat["Seconds"] = "Seconds";
    /** @example `Apr 25`, `01:34`, `02:24` */
    ETradeChartLabelFormat["Minutes"] = "Minutes";
    /** @example `Apr`, `08`, `13` */
    ETradeChartLabelFormat["Days"] = "Days";
    /** @example `2020`, `Jan`, `Feb` */
    ETradeChartLabelFormat["Months"] = "Months";
})(ETradeChartLabelFormat = exports.ETradeChartLabelFormat || (exports.ETradeChartLabelFormat = {}));
var EDatePrecision;
(function (EDatePrecision) {
    /** "Second" or "Unix", where 1 second = 1.0 value */
    EDatePrecision[EDatePrecision["Seconds"] = 1] = "Seconds";
    /** 1 second = 1,000 value */
    EDatePrecision[EDatePrecision["Milliseconds"] = 1000] = "Milliseconds";
    /** 1 second = 1,000,000 value */
    EDatePrecision[EDatePrecision["Microseconds"] = 1000000] = "Microseconds";
    /** 1 second = 1,000,000,000 value */
    EDatePrecision[EDatePrecision["Nanoseconds"] = 1000000000] = "Nanoseconds";
})(EDatePrecision = exports.EDatePrecision || (exports.EDatePrecision = {}));
var EHighPrecisionLabelMode;
(function (EHighPrecisionLabelMode) {
    /**
     * Formats the precise values with their respective suffix (`ms`, `µs`, `ns`).
     *
     * @note It can also show seconds, depending on {@link SmartDateLabelProvider.showSecondsOnPreciseDate}
     *
     * @example
     * "345ms"
     * "59s345ms"
     */
    EHighPrecisionLabelMode["Suffix"] = "Suffix";
    /**
     * Formats the precise values as fractional seconds.
     *
     * @note It can also show seconds, depending on {@link SmartDateLabelProvider.showSecondsOnPreciseDate}
     *
     * @example
     * ".00345"
     * "59.00345"
     */
    EHighPrecisionLabelMode["Fractional"] = "Fractional";
    /**
     * Formats the precise values in scientific notation.
     *
     * @example
     * "4.00e-1s"
     */
    EHighPrecisionLabelMode["Scientific"] = "Scientific";
})(EHighPrecisionLabelMode = exports.EHighPrecisionLabelMode || (exports.EHighPrecisionLabelMode = {}));
var TEN_MICROSECONDS = 0.00001;
var TEN_MILLISECONDS = 0.01;
var TEN_SECONDS = 10;
var ONE_HOUR = 60 * 60;
var FIVE_DAYS = 60 * 60 * 24 * 5;
var FIFTY_DAYS = 60 * 60 * 24 * 50;
/**
 * Default label thresholds used by SmartDateLabelProvider.
 * Maps each label format to its maximum time range in seconds.
 */
exports.DEFAULT_LABEL_THRESHOLDS = (_a = {},
    _a[ETradeChartLabelFormat.Nanoseconds] = TEN_MICROSECONDS,
    _a[ETradeChartLabelFormat.Microseconds] = TEN_MILLISECONDS,
    _a[ETradeChartLabelFormat.MilliSeconds] = TEN_SECONDS,
    _a[ETradeChartLabelFormat.Seconds] = ONE_HOUR,
    _a[ETradeChartLabelFormat.Minutes] = FIVE_DAYS,
    _a[ETradeChartLabelFormat.Days] = FIFTY_DAYS,
    _a[ETradeChartLabelFormat.Months] = Infinity,
    _a);
/**
 * The order in which label formats should be evaluated (from smallest to largest time ranges).
 * Used to determine which format to use based on the visible time range.
 */
var LABEL_FORMAT_ORDER = [
    ETradeChartLabelFormat.Nanoseconds,
    ETradeChartLabelFormat.Microseconds,
    ETradeChartLabelFormat.MilliSeconds,
    ETradeChartLabelFormat.Seconds,
    ETradeChartLabelFormat.Minutes,
    ETradeChartLabelFormat.Days,
    ETradeChartLabelFormat.Months
];
/**
 * The {@link SmartDateLabelProvider} formats Axis Labels and Cursor / Tooltips for {@link NumericAxis} types
 */
var SmartDateLabelProvider = /** @class */ (function (_super) {
    __extends(SmartDateLabelProvider, _super);
    /**
     * Creates an instance of {@link SmartDateLabelProvider}
     */
    function SmartDateLabelProvider(options) {
        var _this = this;
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
        _this = _super.call(this, __assign(__assign({}, options), { labelFormat: (_a = options === null || options === void 0 ? void 0 : options.labelFormat) !== null && _a !== void 0 ? _a : NumericFormat_1.ENumericFormat.Date_DDMMYYYY, cursorLabelFormat: (_b = options === null || options === void 0 ? void 0 : options.cursorLabelFormat) !== null && _b !== void 0 ? _b : NumericFormat_1.ENumericFormat.Date_DDMMYYYY, alwaysShowFirstLabel: (_c = options === null || options === void 0 ? void 0 : options.alwaysShowFirstLabel) !== null && _c !== void 0 ? _c : true })) || this;
        _this.type = LabelProviderType_1.ELabelProviderType.SmartDate;
        _this.textVariesForSameTick = true;
        _this.showWiderDateOnFirstLabelProperty = true;
        _this.showYearOnWiderDateProperty = false;
        _this.dateOffsetProperty = 0;
        _this.datePrecisionProperty = EDatePrecision.Seconds;
        _this.highPrecisionLabelModeProperty = EHighPrecisionLabelMode.Suffix;
        _this.labelThresholdsProperty = exports.DEFAULT_LABEL_THRESHOLDS;
        _this.labelThresholdsUpdated = false;
        _this.splitWideDateWithCommaProperty = true;
        _this.showSecondsOnWideDateProperty = true;
        _this.showSecondsOnPreciseDateProperty = false;
        _this.firstLabel = true;
        _this.showWiderDateOnFirstLabelProperty = (_d = options === null || options === void 0 ? void 0 : options.showWiderDateOnFirstLabel) !== null && _d !== void 0 ? _d : _this.showWiderDateOnFirstLabelProperty;
        _this.showYearOnWiderDateProperty = (_e = options === null || options === void 0 ? void 0 : options.showYearOnWiderDate) !== null && _e !== void 0 ? _e : _this.showYearOnWiderDateProperty;
        _this.dateOffsetProperty = (_f = options === null || options === void 0 ? void 0 : options.dateOffset) !== null && _f !== void 0 ? _f : _this.dateOffsetProperty;
        _this.datePrecisionProperty = (_g = options === null || options === void 0 ? void 0 : options.datePrecision) !== null && _g !== void 0 ? _g : _this.datePrecisionProperty;
        _this.highPrecisionLabelModeProperty = (_h = options === null || options === void 0 ? void 0 : options.highPrecisionLabelMode) !== null && _h !== void 0 ? _h : _this.highPrecisionLabelModeProperty;
        _this.splitWideDateWithCommaProperty = (_j = options === null || options === void 0 ? void 0 : options.splitWideDateWithComma) !== null && _j !== void 0 ? _j : _this.splitWideDateWithCommaProperty;
        _this.showSecondsOnWideDateProperty = (_k = options === null || options === void 0 ? void 0 : options.showSecondsOnWideDate) !== null && _k !== void 0 ? _k : _this.showSecondsOnWideDateProperty;
        _this.showSecondsOnPreciseDateProperty = (_l = options === null || options === void 0 ? void 0 : options.showSecondsOnPreciseDate) !== null && _l !== void 0 ? _l : _this.showSecondsOnPreciseDateProperty;
        if (options === null || options === void 0 ? void 0 : options.labelThresholds) {
            _this.labelThresholdsProperty = __assign(__assign({}, exports.DEFAULT_LABEL_THRESHOLDS), options.labelThresholds);
            _this.labelThresholdsUpdated = true;
        }
        _this.formatCursorLabelProperty = function (dataValue) {
            var _a, _b;
            var seconds = _this.convertToUnixSeconds(dataValue) + _this.dateOffset;
            return _this.applyFormat((0, number_1.formatNumber)(seconds, (_a = _this.cursorNumericFormat) !== null && _a !== void 0 ? _a : _this.numericFormat, (_b = _this.cursorPrecision) !== null && _b !== void 0 ? _b : _this.precision));
        };
        _this.doFormat = _this.doFormat.bind(_this);
        _this.formatLabelProperty = _this.doFormat;
        return _this;
    }
    /**
     * Convert value from current precision (ticks) to standard Unix Seconds.
     * @note High precision values (nano) will lose precision here.
     * Use only for coarse-grained logic (year / month / day checks).
     */
    SmartDateLabelProvider.prototype.convertToUnixSeconds = function (value) {
        return value / this.datePrecisionProperty;
    };
    /**
     * Convert raw ticks to Unix seconds, preserving integer seconds.
     * Returns only the whole seconds part, discarding sub-second precision.
     */
    SmartDateLabelProvider.prototype.getWholeSeconds = function (rawTicks) {
        var tps = this.datePrecisionProperty;
        return Math.floor(rawTicks / tps);
    };
    Object.defineProperty(SmartDateLabelProvider.prototype, "showWiderDateOnFirstLabel", {
        get: function () {
            return this.showWiderDateOnFirstLabelProperty;
        },
        set: function (value) {
            if (this.showWiderDateOnFirstLabelProperty !== value) {
                this.showWiderDateOnFirstLabelProperty = value;
                this.invalidateParent();
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SmartDateLabelProvider.prototype, "dateOffset", {
        /**
         * A timestamp in seconds to add to the value being formatted.
         */
        get: function () {
            var _a;
            return (_a = this.dateOffsetProperty) !== null && _a !== void 0 ? _a : 0;
        },
        set: function (value) {
            if (this.dateOffsetProperty !== value) {
                this.dateOffsetProperty = value;
                this.invalidateParent();
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SmartDateLabelProvider.prototype, "datePrecision", {
        /**
         * Gets or sets the precision of the input data values.
         * Defaults to `EDatePrecision.Seconds` (Unix).
         */
        get: function () {
            return this.datePrecisionProperty;
        },
        set: function (value) {
            if (this.datePrecisionProperty !== value) {
                this.datePrecisionProperty = value;
                this.invalidateParent();
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SmartDateLabelProvider.prototype, "highPrecisionLabelMode", {
        /**
         * Gets or Sets the high precision label mode.
         * Default `EHighPrecisionLabelMode.Suffix`
         */
        get: function () {
            return this.highPrecisionLabelModeProperty;
        },
        set: function (value) {
            if (this.highPrecisionLabelModeProperty !== value) {
                this.highPrecisionLabelModeProperty = value;
                this.invalidateParent();
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SmartDateLabelProvider.prototype, "showYearOnWiderDate", {
        /**
         * Gets or Sets whether the year should be shown in the wider format used on first label. Default false.
         */
        get: function () {
            return this.showYearOnWiderDateProperty;
        },
        set: function (value) {
            if (this.showYearOnWiderDateProperty !== value) {
                this.showYearOnWiderDateProperty = value;
                this.invalidateParent();
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SmartDateLabelProvider.prototype, "labelThresholds", {
        /**
         * Gets or sets the custom label thresholds that map label formats to maximum time ranges.
         * Allows you to customize when different label formats are used based on the visible time range.
         * You can update individual thresholds by providing a partial object.
         * Default {@link DEFAULT_LABEL_THRESHOLDS}.
         *
         * @example
         * ```typescript
         * // Override only the Minutes threshold
         * labelProvider.labelThresholds = {
         *     [ETradeChartLabelFormat.Minutes]: 60 * 60 * 24 * 7 // 7 days
         * };
         * ```
         */
        get: function () {
            return this.labelThresholdsProperty;
        },
        set: function (value) {
            if (this.labelThresholdsProperty !== value) {
                this.labelThresholdsProperty = __assign(__assign({}, this.labelThresholdsProperty), value);
                this.labelThresholdsUpdated = true;
                this.invalidateParent();
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SmartDateLabelProvider.prototype, "splitWideDateWithComma", {
        /**
         * Gets or Sets whether your wide formatted dates have a comma in between date + month, and everything else
         */
        get: function () { return this.splitWideDateWithCommaProperty; },
        set: function (value) {
            if (this.splitWideDateWithCommaProperty !== value) {
                this.splitWideDateWithCommaProperty = value;
                this.invalidateParent();
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SmartDateLabelProvider.prototype, "showSecondsOnWideDate", {
        /**
         * Gets or Sets whether to show the seconds component on wide date formats.
         */
        get: function () { return this.showSecondsOnWideDateProperty; },
        set: function (value) {
            if (this.showSecondsOnWideDateProperty !== value) {
                this.showSecondsOnWideDateProperty = value;
                this.invalidateParent();
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SmartDateLabelProvider.prototype, "showSecondsOnPreciseDate", {
        /**
         * Gets or Sets whether to show the seconds component on precise date formats.
         */
        get: function () { return this.showSecondsOnPreciseDateProperty; },
        set: function (value) {
            if (this.showSecondsOnPreciseDateProperty !== value) {
                this.showSecondsOnPreciseDateProperty = value;
                this.invalidateParent();
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(SmartDateLabelProvider.prototype, "numericFormat", {
        /** @inheritDoc */
        get: function () {
            // SmartDate uses its own formatting; numericFormat is not applicable for axis labels.
            return undefined;
        },
        /** @inheritDoc */
        set: function (value) {
            // Intentionally no-op to avoid breaking serialization.
        },
        enumerable: false,
        configurable: true
    });
    SmartDateLabelProvider.prototype.onBeginAxisDraw = function () {
        // Could be extended by subclasses or user if needed
    };
    /**
     * @inheritDoc
     */
    SmartDateLabelProvider.prototype.getLabels = function (majorTicks) {
        var first = majorTicks[0];
        var ticksNumber = majorTicks.length;
        var last = majorTicks[ticksNumber - 1];
        // Only convert the values we need
        if (this.parentAxis.isCategoryAxis) {
            var categoryCoordCalc = this.parentAxis.getCurrentCoordinateCalculator();
            first = categoryCoordCalc.transformIndexToData(first);
            last = categoryCoordCalc.transformIndexToData(last);
        }
        this.prevPrevValue = undefined;
        this.prevValue = undefined;
        this.firstLabel = true;
        var timeRangeRaw = last - first;
        var timeRangeSeconds = timeRangeRaw / this.datePrecisionProperty;
        this.format = this.getLabelRange(timeRangeSeconds, ticksNumber);
        var labels = _super.prototype.getLabels.call(this, majorTicks);
        this.format = undefined;
        return labels;
    };
    /**
     * Formats the value in a wider format, used for the first label and when the formatted value changes
     * (e.g., when crossing day/hour boundaries). This method can be overridden to customize wide label formatting.
     *
     * @param labelRange - The label format range determined by the visible time span (e.g., Nanoseconds, Seconds, Days)
     * @param valueInSeconds - The data value converted to Unix seconds with dateOffset already applied
     * @returns The formatted wide label string
     *
     * @example
     * // For high precision: "Jan 2, 2026 12:59:59"
     * // For months: "Jan 2026"
     * // For years: "2026"
     */
    SmartDateLabelProvider.prototype.formatDateWide = function (labelRange, valueInSeconds) {
        var yearStr = (0, date_1.formatUnixDateToHumanStringYYYY)(valueInSeconds);
        var optionalYearLeftPadded = this.showYearOnWiderDate ? " " + yearStr : "";
        var optionalDateSeparator = this.splitWideDateWithComma ? "," : "";
        switch (labelRange) {
            case ETradeChartLabelFormat.Nanoseconds:
            case ETradeChartLabelFormat.Microseconds:
            case ETradeChartLabelFormat.MilliSeconds: {
                var time = this.showSecondsOnWideDate
                    ? (0, date_1.formatUnixDateToHumanStringHHMMSS)(valueInSeconds)
                    : (0, date_1.formatUnixDateToHumanStringHHMM)(valueInSeconds);
                // "Jan 1 2026 12:59:59"
                // "Jan 1, 12:59"
                return (0, date_1.formatUnixDateToHumanStringMMMDD)(valueInSeconds)
                    + optionalDateSeparator
                    + optionalYearLeftPadded
                    + " " + time;
            }
            case ETradeChartLabelFormat.Seconds:
            case ETradeChartLabelFormat.Minutes: {
                // "Jan 1, 2026"
                // "Jan 1"
                return (0, date_1.formatUnixDateToHumanStringMMMDD)(valueInSeconds)
                    + (this.showYearOnWiderDateProperty ? (optionalDateSeparator + optionalYearLeftPadded) : "");
            }
            case ETradeChartLabelFormat.Days: {
                // "Apr 2026"
                // "Apr"
                return (0, date_1.formatUnixDateToHumanStringMMM)(valueInSeconds)
                    + optionalYearLeftPadded;
            }
            default:
                return yearStr;
        }
    };
    /**
     * Formats the value using the precise format for non-wide labels. The format depends on the
     * `highPrecisionLabelMode` setting. This method can be overridden to customize precise label formatting.
     *
     * @param labelRange - The label format range determined by the visible time span (e.g., Nanoseconds, Seconds, Days)
     * @param valueInSeconds - The data value converted to Unix seconds with dateOffset already applied
     * @param rawValue - The original raw tick value, used to extract sub-second precision without floating point loss
     * @returns The formatted precise label string
     *
     * @remarks
     * For high precision formats (ns/µs/ms), the raw value is essential for maintaining precision. See {@link EHighPrecisionLabelMode} for more formatting details.
     *
     * @remarks
     * For coarser formats, only `valueInSeconds` is used.
     */
    SmartDateLabelProvider.prototype.formatDatePrecise = function (labelRange, valueInSeconds, rawValue) {
        var raw = rawValue !== null && rawValue !== void 0 ? rawValue : 0;
        switch (labelRange) {
            case ETradeChartLabelFormat.Nanoseconds:
            case ETradeChartLabelFormat.Microseconds:
            case ETradeChartLabelFormat.MilliSeconds: {
                var tps = this.getTicksPerSecond();
                var ticksWithinSecond = this.getTicksWithinSecond(raw);
                var subSecondOffset = ticksWithinSecond / tps;
                var optionalSecondsStr = this.showSecondsOnPreciseDate ? "".concat(this.getWholeSeconds(raw) % 60) : "";
                switch (this.highPrecisionLabelModeProperty) {
                    case EHighPrecisionLabelMode.Scientific:
                        return "".concat(subSecondOffset.toExponential(2), "s");
                    case EHighPrecisionLabelMode.Fractional: {
                        if (labelRange === ETradeChartLabelFormat.Nanoseconds) {
                            return "".concat(optionalSecondsStr, ".").concat(this.getNanosecondsWithinSecond(raw));
                        }
                        else if (labelRange === ETradeChartLabelFormat.Microseconds) {
                            return "".concat(optionalSecondsStr, ".").concat(this.getMicrosecondsWithinSecond(raw));
                        }
                        return "".concat(optionalSecondsStr, ".").concat(this.getMillisecondsWithinSecond(raw));
                    }
                    case EHighPrecisionLabelMode.Suffix:
                    default: {
                        var prefix = optionalSecondsStr ? optionalSecondsStr + "s" : "";
                        if (labelRange === ETradeChartLabelFormat.Nanoseconds) {
                            return "".concat(prefix).concat(Math.round(subSecondOffset * 1000000000), "ns");
                        }
                        else if (labelRange === ETradeChartLabelFormat.Microseconds) {
                            return "".concat(prefix).concat(Math.round(subSecondOffset * 1000000), "\u00B5s");
                        }
                        return "".concat(prefix).concat(Math.round(subSecondOffset * 1000), "ms");
                    }
                }
            }
            case ETradeChartLabelFormat.Seconds:
                return (0, date_1.formatUnixDateToHumanStringHHMMSS)(valueInSeconds);
            case ETradeChartLabelFormat.Minutes:
                return (0, date_1.formatUnixDateToHumanStringHHMM)(valueInSeconds);
            case ETradeChartLabelFormat.Days:
            case ETradeChartLabelFormat.Months:
                return (0, date_1.formatUnixDateToHumanStringDD)(valueInSeconds);
            default:
                return (0, number_1.formatNumber)(valueInSeconds, NumericFormat_1.ENumericFormat.Date_DDMMYY, 0);
        }
    };
    SmartDateLabelProvider.prototype.toJSON = function () {
        var json = _super.prototype.toJSON.call(this);
        var options = {
            dateOffset: this.dateOffset,
            highPrecisionLabelMode: this.highPrecisionLabelMode,
            showWiderDateOnFirstLabel: this.showWiderDateOnFirstLabel,
            showYearOnWiderDate: this.showYearOnWiderDate,
            datePrecision: this.datePrecision,
            splitWideDateWithComma: this.splitWideDateWithComma,
            showSecondsOnWideDate: this.showSecondsOnWideDate,
            showSecondsOnPreciseDate: this.showSecondsOnPreciseDate,
            labelThresholds: this.labelThresholdsUpdated ? this.labelThresholds : undefined
        };
        Object.assign(json.options, options);
        return json;
    };
    /** This method is bound to the formatLabel method of the base labelProvider. */
    SmartDateLabelProvider.prototype.doFormat = function (dataValue) {
        var _a, _b;
        // Convert raw ticks to seconds + offset
        var fullValueInSeconds = this.convertToUnixSeconds(dataValue) + this.dateOffset;
        if (this.format) {
            var text = this.formatSmartLabel(this.format, fullValueInSeconds, this.prevValue, this.prevPrevValue, dataValue);
            this.prevPrevValue = this.prevValue;
            this.prevValue = fullValueInSeconds;
            return text;
        }
        else {
            // Cursor / tooltip fallback
            return this.applyFormat((0, number_1.formatNumber)(fullValueInSeconds, (_a = this.cursorNumericFormat) !== null && _a !== void 0 ? _a : this.numericFormat, (_b = this.cursorPrecision) !== null && _b !== void 0 ? _b : this.precision));
        }
    };
    /**
     * Return a range string, based on the numeric range of the axis.
     * This will be used to choose which formatting to use.
     * Uses the {@link labelThresholds} property to determine the appropriate format.
     */
    SmartDateLabelProvider.prototype.getLabelRange = function (timeRangeSeconds, ticksNumber) {
        // Iterate through formats in order to find the first one whose threshold exceeds the time range
        for (var _i = 0, LABEL_FORMAT_ORDER_1 = LABEL_FORMAT_ORDER; _i < LABEL_FORMAT_ORDER_1.length; _i++) {
            var format = LABEL_FORMAT_ORDER_1[_i];
            var threshold = this.labelThresholdsProperty[format];
            if (threshold !== undefined && timeRangeSeconds <= threshold) {
                return format;
            }
        }
        // Fallback to Months if no threshold matches
        return ETradeChartLabelFormat.Months;
    };
    /**
     * Main smart label formatting logic that determines when to display wide vs precise labels.
     * This method can be overridden to customize the overall label selection strategy.
     *
     * @param format - The label format range (Nanoseconds, Microseconds, MilliSeconds, Seconds, Minutes, Days, Months)
     * @param valueInSeconds - The current data value converted to Unix seconds with dateOffset applied
     * @param prevValueInSeconds - The previous label's value in Unix seconds (undefined for first label)
     * @param prevPrevValueInSeconds - The label before the previous one in Unix seconds (used for month formatting)
     * @param originalRawValue - The current raw tick value, preserving sub-second precision
     * @returns The formatted label string (either wide or precise format)
     *
     * @remarks
     * The method decides between wide and precise formats based on:
     * 1. Whether this is the first label (controlled by `showWiderDateOnFirstLabel`)
     * 2. Whether the wide-formatted value has changed from the previous label
     * 3. Special logic for month boundaries
     *
     * Wide labels provide date/time context (e.g., "1/1/2026 12:59:59"), while precise labels
     * show incremental values (e.g., "00.000004000" or "4000ns").
     */
    SmartDateLabelProvider.prototype.formatSmartLabel = function (format, valueInSeconds, prevValueInSeconds, prevPrevValueInSeconds, originalRawValue) {
        var showWider = !this.firstLabel || this.showWiderDateOnFirstLabel;
        this.firstLabel = false;
        var wideDate = this.formatDateWide(format, valueInSeconds);
        var prevWideDate = prevValueInSeconds !== undefined
            ? this.formatDateWide(format, prevValueInSeconds)
            : undefined;
        var isNewDate = prevWideDate === undefined || wideDate !== prevWideDate;
        if (format !== ETradeChartLabelFormat.Months) {
            if (isNewDate && showWider) {
                return wideDate;
            }
            return this.formatDatePrecise(format, valueInSeconds, originalRawValue);
        }
        else {
            if (isNewDate && showWider) {
                return wideDate;
            }
            var prevPrevWideDate = prevPrevValueInSeconds !== undefined && prevValueInSeconds !== undefined
                ? this.formatDateWide(format, prevPrevValueInSeconds)
                : undefined;
            var prevPrevNewYear = prevPrevWideDate === undefined || prevWideDate !== prevPrevWideDate;
            var newMonth = prevPrevNewYear ||
                (0, date_1.formatUnixDateToHumanStringMMM)(valueInSeconds) !==
                    (0, date_1.formatUnixDateToHumanStringMMM)(prevValueInSeconds);
            if (newMonth) {
                return (0, date_1.formatUnixDateToHumanStringMMM)(valueInSeconds);
            }
            return this.formatDatePrecise(format, valueInSeconds, originalRawValue);
        }
    };
    SmartDateLabelProvider.prototype.getTicksPerSecond = function () {
        return this.datePrecisionProperty;
    };
    SmartDateLabelProvider.prototype.getTicksWithinSecond = function (rawTicks) {
        var tps = this.getTicksPerSecond();
        if (!tps)
            return 0;
        var wholeSeconds = Math.floor(rawTicks / tps);
        return rawTicks - wholeSeconds * tps;
    };
    SmartDateLabelProvider.prototype.getMillisecondsWithinSecond = function (rawTicks) {
        var tps = this.getTicksPerSecond();
        if (!tps)
            return 0;
        var ticksWithinSecond = this.getTicksWithinSecond(rawTicks);
        return Math.floor((ticksWithinSecond * 1000) / tps);
    };
    SmartDateLabelProvider.prototype.getMicrosecondsWithinSecond = function (rawTicks) {
        var tps = this.getTicksPerSecond();
        if (!tps)
            return 0;
        var ticksWithinSecond = this.getTicksWithinSecond(rawTicks);
        return Math.floor((ticksWithinSecond * 1000000) / tps);
    };
    SmartDateLabelProvider.prototype.getNanosecondsWithinSecond = function (rawTicks) {
        var tps = this.getTicksPerSecond();
        if (!tps)
            return 0;
        var ticksWithinSecond = this.getTicksWithinSecond(rawTicks);
        return Math.floor((ticksWithinSecond * 1000000000) / tps);
    };
    return SmartDateLabelProvider;
}(LabelProviderBase2D_1.LabelProviderBase2D));
exports.SmartDateLabelProvider = SmartDateLabelProvider;
