"use strict";
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
// Copied from https://github.com/microsoft/vscode/blob/724c307bf35646ac549a8533a255c51b63fea5c7/src/vs/base/common/comparers.ts
// We cannot customize the monaco loader for Theia: https://github.com/eclipse-theia/theia/issues/8220
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;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.compareByPrefix = exports.compareAnything = exports.comparePaths = exports.compareFileExtensionsNumeric = exports.compareFileExtensions = exports.noIntlCompareFileNames = exports.compareFileNamesNumeric = exports.compareFileNames = void 0;
var os_1 = require("@theia/core/lib/common/os");
var sep = (os_1.isWindows ? '\\' : '/');
var runWhenIdle;
(function () {
    if (typeof requestIdleCallback !== 'function' || typeof cancelIdleCallback !== 'function') {
        var dummyIdle_1 = Object.freeze({
            didTimeout: true,
            timeRemaining: function () { return 15; }
        });
        runWhenIdle = function (runner) {
            var handle = setTimeout(function () { return runner(dummyIdle_1); });
            var disposed = false;
            return {
                dispose: function () {
                    if (disposed) {
                        return;
                    }
                    disposed = true;
                    clearTimeout(handle);
                }
            };
        };
    }
    else {
        runWhenIdle = function (runner, timeout) {
            var handle = requestIdleCallback(runner, typeof timeout === 'number' ? { timeout: timeout } : undefined);
            var disposed = false;
            return {
                dispose: function () {
                    if (disposed) {
                        return;
                    }
                    disposed = true;
                    cancelIdleCallback(handle);
                }
            };
        };
    }
})();
/**
 * An implementation of the "idle-until-urgent"-strategy as introduced
 * here: https://philipwalton.com/articles/idle-until-urgent/
 */
var IdleValue = /** @class */ (function () {
    function IdleValue(executor) {
        var _this = this;
        this._didRun = false;
        this._executor = function () {
            try {
                _this._value = executor();
            }
            catch (err) {
                _this._error = err;
            }
            finally {
                _this._didRun = true;
            }
        };
        this._handle = runWhenIdle(function () { return _this._executor(); });
    }
    IdleValue.prototype.dispose = function () {
        this._handle.dispose();
    };
    Object.defineProperty(IdleValue.prototype, "value", {
        get: function () {
            if (!this._didRun) {
                this._handle.dispose();
                this._executor();
            }
            if (this._error) {
                throw this._error;
            }
            return this._value;
        },
        enumerable: false,
        configurable: true
    });
    return IdleValue;
}());
// When comparing large numbers of strings, such as in sorting large arrays, is better for
// performance to create an Intl.Collator object and use the function provided by its compare
// property than it is to use String.prototype.localeCompare()
// A collator with numeric sorting enabled, and no sensitivity to case or to accents
var intlFileNameCollatorBaseNumeric = new IdleValue(function () {
    var collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
    return {
        collator: collator,
        collatorIsNumeric: collator.resolvedOptions().numeric
    };
});
// A collator with numeric sorting enabled.
var intlFileNameCollatorNumeric = new IdleValue(function () {
    var collator = new Intl.Collator(undefined, { numeric: true });
    return {
        collator: collator
    };
});
// A collator with numeric sorting enabled, and sensitivity to accents and diacritics but not case.
var intlFileNameCollatorNumericCaseInsenstive = new IdleValue(function () {
    var collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'accent' });
    return {
        collator: collator
    };
});
function compareFileNames(one, other, caseSensitive) {
    if (caseSensitive === void 0) { caseSensitive = false; }
    var a = one || '';
    var b = other || '';
    var result = intlFileNameCollatorBaseNumeric.value.collator.compare(a, b);
    // Using the numeric option in the collator will
    // make compare(`foo1`, `foo01`) === 0. We must disambiguate.
    if (intlFileNameCollatorBaseNumeric.value.collatorIsNumeric && result === 0 && a !== b) {
        return a < b ? -1 : 1;
    }
    return result;
}
exports.compareFileNames = compareFileNames;
/** Compares filenames by name then extension, sorting numbers numerically instead of alphabetically. */
function compareFileNamesNumeric(one, other) {
    var _a = __read(extractNameAndExtension(one, true), 2), oneName = _a[0], oneExtension = _a[1];
    var _b = __read(extractNameAndExtension(other, true), 2), otherName = _b[0], otherExtension = _b[1];
    var collatorNumeric = intlFileNameCollatorNumeric.value.collator;
    var collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsenstive.value.collator;
    var result;
    // Check for name differences, comparing numbers numerically instead of alphabetically.
    result = compareAndDisambiguateByLength(collatorNumeric, oneName, otherName);
    if (result !== 0) {
        return result;
    }
    // Check for case insensitive extension differences, comparing numbers numerically instead of alphabetically.
    result = compareAndDisambiguateByLength(collatorNumericCaseInsensitive, oneExtension, otherExtension);
    if (result !== 0) {
        return result;
    }
    // Disambiguate the extension case if needed.
    if (oneExtension !== otherExtension) {
        return collatorNumeric.compare(oneExtension, otherExtension);
    }
    return 0;
}
exports.compareFileNamesNumeric = compareFileNamesNumeric;
var FileNameMatch = /^(.*?)(\.([^.]*))?$/;
function noIntlCompareFileNames(one, other, caseSensitive) {
    if (caseSensitive === void 0) { caseSensitive = false; }
    if (!caseSensitive) {
        one = one && one.toLowerCase();
        other = other && other.toLowerCase();
    }
    var _a = __read(extractNameAndExtension(one), 2), oneName = _a[0], oneExtension = _a[1];
    var _b = __read(extractNameAndExtension(other), 2), otherName = _b[0], otherExtension = _b[1];
    if (oneName !== otherName) {
        return oneName < otherName ? -1 : 1;
    }
    if (oneExtension === otherExtension) {
        return 0;
    }
    return oneExtension < otherExtension ? -1 : 1;
}
exports.noIntlCompareFileNames = noIntlCompareFileNames;
function compareFileExtensions(one, other) {
    var _a = __read(extractNameAndExtension(one), 2), oneName = _a[0], oneExtension = _a[1];
    var _b = __read(extractNameAndExtension(other), 2), otherName = _b[0], otherExtension = _b[1];
    var result = intlFileNameCollatorBaseNumeric.value.collator.compare(oneExtension, otherExtension);
    if (result === 0) {
        // Using the numeric option in the collator will
        // make compare(`foo1`, `foo01`) === 0. We must disambiguate.
        if (intlFileNameCollatorBaseNumeric.value.collatorIsNumeric && oneExtension !== otherExtension) {
            return oneExtension < otherExtension ? -1 : 1;
        }
        // Extensions are equal, compare filenames
        result = intlFileNameCollatorBaseNumeric.value.collator.compare(oneName, otherName);
        if (intlFileNameCollatorBaseNumeric.value.collatorIsNumeric && result === 0 && oneName !== otherName) {
            return oneName < otherName ? -1 : 1;
        }
    }
    return result;
}
exports.compareFileExtensions = compareFileExtensions;
/** Compares filenames by extenson, then by name. Sorts numbers numerically, not alphabetically. */
function compareFileExtensionsNumeric(one, other) {
    var _a = __read(extractNameAndExtension(one, true), 2), oneName = _a[0], oneExtension = _a[1];
    var _b = __read(extractNameAndExtension(other, true), 2), otherName = _b[0], otherExtension = _b[1];
    var collatorNumeric = intlFileNameCollatorNumeric.value.collator;
    var collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsenstive.value.collator;
    var result;
    // Check for extension differences, ignoring differences in case and comparing numbers numerically.
    result = compareAndDisambiguateByLength(collatorNumericCaseInsensitive, oneExtension, otherExtension);
    if (result !== 0) {
        return result;
    }
    // Compare names.
    result = compareAndDisambiguateByLength(collatorNumeric, oneName, otherName);
    if (result !== 0) {
        return result;
    }
    // Disambiguate extension case if needed.
    if (oneExtension !== otherExtension) {
        return collatorNumeric.compare(oneExtension, otherExtension);
    }
    return 0;
}
exports.compareFileExtensionsNumeric = compareFileExtensionsNumeric;
/** Extracts the name and extension from a full filename, with optional special handling for dotfiles */
function extractNameAndExtension(str, dotfilesAsNames) {
    if (dotfilesAsNames === void 0) { dotfilesAsNames = false; }
    var match = str ? FileNameMatch.exec(str) : [];
    var result = [(match && match[1]) || '', (match && match[3]) || ''];
    // if the dotfilesAsNames option is selected, treat an empty filename with an extension,
    // or a filename that starts with a dot, as a dotfile name
    if (dotfilesAsNames && (!result[0] && result[1] || result[0] && result[0].charAt(0) === '.')) {
        result = [result[0] + '.' + result[1], ''];
    }
    return result;
}
function compareAndDisambiguateByLength(collator, one, other) {
    // Check for differences
    var result = collator.compare(one, other);
    if (result !== 0) {
        return result;
    }
    // In a numeric comparison, `foo1` and `foo01` will compare as equivalent.
    // Disambiguate by sorting the shorter string first.
    if (one.length !== other.length) {
        return one.length < other.length ? -1 : 1;
    }
    return 0;
}
function comparePathComponents(one, other, caseSensitive) {
    if (caseSensitive === void 0) { caseSensitive = false; }
    if (!caseSensitive) {
        one = one && one.toLowerCase();
        other = other && other.toLowerCase();
    }
    if (one === other) {
        return 0;
    }
    return one < other ? -1 : 1;
}
function comparePaths(one, other, caseSensitive) {
    if (caseSensitive === void 0) { caseSensitive = false; }
    var oneParts = one.split(sep);
    var otherParts = other.split(sep);
    var lastOne = oneParts.length - 1;
    var lastOther = otherParts.length - 1;
    var endOne, endOther;
    for (var i = 0;; i++) {
        endOne = lastOne === i;
        endOther = lastOther === i;
        if (endOne && endOther) {
            return compareFileNames(oneParts[i], otherParts[i], caseSensitive);
        }
        else if (endOne) {
            return -1;
        }
        else if (endOther) {
            return 1;
        }
        var result = comparePathComponents(oneParts[i], otherParts[i], caseSensitive);
        if (result !== 0) {
            return result;
        }
    }
}
exports.comparePaths = comparePaths;
function compareAnything(one, other, lookFor) {
    var elementAName = one.toLowerCase();
    var elementBName = other.toLowerCase();
    // Sort prefix matches over non prefix matches
    var prefixCompare = compareByPrefix(one, other, lookFor);
    if (prefixCompare) {
        return prefixCompare;
    }
    // Sort suffix matches over non suffix matches
    var elementASuffixMatch = elementAName.endsWith(lookFor);
    var elementBSuffixMatch = elementBName.endsWith(lookFor);
    if (elementASuffixMatch !== elementBSuffixMatch) {
        return elementASuffixMatch ? -1 : 1;
    }
    // Understand file names
    var r = compareFileNames(elementAName, elementBName);
    if (r !== 0) {
        return r;
    }
    // Compare by name
    return elementAName.localeCompare(elementBName);
}
exports.compareAnything = compareAnything;
function compareByPrefix(one, other, lookFor) {
    var elementAName = one.toLowerCase();
    var elementBName = other.toLowerCase();
    // Sort prefix matches over non prefix matches
    var elementAPrefixMatch = elementAName.startsWith(lookFor);
    var elementBPrefixMatch = elementBName.startsWith(lookFor);
    if (elementAPrefixMatch !== elementBPrefixMatch) {
        return elementAPrefixMatch ? -1 : 1;
    }
    // Same prefix: Sort shorter matches to the top to have those on top that match more precisely
    // tslint:disable-next-line: one-line
    else if (elementAPrefixMatch && elementBPrefixMatch) {
        if (elementAName.length < elementBName.length) {
            return -1;
        }
        if (elementAName.length > elementBName.length) {
            return 1;
        }
    }
    return 0;
}
exports.compareByPrefix = compareByPrefix;
//# sourceMappingURL=comparers.js.map