"use strict";
/*!
  Copyright 2018 Ron Buckton (rbuckton@chronicles.org)

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var types_1 = require("../types");
var conversion_1 = require("./conversion");
var guards_1 = require("./guards");
var decorators_1 = require("./decorators");
var types_2 = require("./types");
var collections_1 = require("equatable/collections");
/** @internal */
function GetIterator(source) {
    var iterator = source[Symbol.iterator];
    if (typeof iterator === "function") {
        return iterator.call(source);
    }
    throw new TypeError();
}
exports.GetIterator = GetIterator;
/** @internal */
function GetAsyncIterator(source) {
    var asyncIterator = guards_1.IsAsyncIterable(source) ? source[Symbol.asyncIterator] : undefined;
    if (typeof asyncIterator === "function") {
        return asyncIterator.call(source);
    }
    var iterator = guards_1.IsIterable(source) ? source[Symbol.iterator] : undefined;
    if (typeof iterator === "function") {
        return new AsyncFromSyncIterator(iterator.call(source));
    }
    throw new TypeError();
}
exports.GetAsyncIterator = GetAsyncIterator;
var AsyncFromSyncIterator = /** @class */ (function () {
    function AsyncFromSyncIterator(iterator) {
        this._iterator = iterator;
    }
    AsyncFromSyncIterator.prototype.next = function (value) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var _a, done, resultValue, _b;
            return tslib_1.__generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        _a = this._iterator.next(value), done = _a.done, resultValue = _a.value;
                        _b = { done: done };
                        return [4 /*yield*/, resultValue];
                    case 1: return [2 /*return*/, (_b.value = _c.sent(), _b)];
                }
            });
        });
    };
    AsyncFromSyncIterator.prototype.return = function (value) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var returnMethod, _a, done, resultValue, _b;
            return tslib_1.__generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        returnMethod = this._iterator.return;
                        if (returnMethod === undefined) {
                            return [2 /*return*/, { done: true, value: value }];
                        }
                        _a = returnMethod.call(this._iterator, value), done = _a.done, resultValue = _a.value;
                        _b = { done: done };
                        return [4 /*yield*/, resultValue];
                    case 1: return [2 /*return*/, (_b.value = _c.sent(), _b)];
                }
            });
        });
    };
    AsyncFromSyncIterator.prototype.throw = function (value) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var throwMethod, _a, done, resultValue, _b;
            return tslib_1.__generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        throwMethod = this._iterator.throw;
                        if (throwMethod === undefined) {
                            throw value;
                        }
                        _a = throwMethod.call(this._iterator, value), done = _a.done, resultValue = _a.value;
                        _b = { done: done };
                        return [4 /*yield*/, resultValue];
                    case 1: return [2 /*return*/, (_b.value = _c.sent(), _b)];
                }
            });
        });
    };
    AsyncFromSyncIterator = tslib_1.__decorate([
        decorators_1.ToStringTag("Async-from-sync Iterator")
    ], AsyncFromSyncIterator);
    return AsyncFromSyncIterator;
}());
/** @internal */
function GetHierarchy(value) {
    var hierarchy = value[types_1.Hierarchical.hierarchy];
    if (typeof hierarchy === "function") {
        return hierarchy.call(value);
    }
    throw new TypeError();
}
exports.GetHierarchy = GetHierarchy;
/** @internal */ function GetSource(query) {
    var sourceMethod = guards_1.IsQuerySource(query) ? query[types_2.QuerySource.source] : undefined;
    if (typeof sourceMethod === "function") {
        return sourceMethod.call(query);
    }
    return query;
}
exports.GetSource = GetSource;
/** @internal */ function GetAsyncSource(query) {
    var sourceMethod = guards_1.IsAsyncQuerySource(query) ? query[types_2.AsyncQuerySource.source] : undefined;
    if (typeof sourceMethod === "function") {
        return sourceMethod.call(query);
    }
    return query;
}
exports.GetAsyncSource = GetAsyncSource;
/** @internal */
function IteratorClose(iterator) {
    if (iterator !== undefined && iterator !== null) {
        var close = iterator.return;
        if (typeof close === "function") {
            return close.call(iterator);
        }
    }
}
exports.IteratorClose = IteratorClose;
/** @internal */
function AsyncIteratorClose(iterator) {
    if (iterator !== undefined && iterator !== null) {
        var close = iterator.return;
        if (typeof close === "function") {
            return close.call(iterator);
        }
    }
}
exports.AsyncIteratorClose = AsyncIteratorClose;
/** @internal */ function ThenBy(value, keySelector, comparer, descending) {
    var thenBy = value[types_1.OrderedIterable.thenBy];
    if (typeof thenBy === "function") {
        return thenBy.call(value, keySelector, comparer, descending);
    }
    throw new TypeError();
}
exports.ThenBy = ThenBy;
/** @internal */ function ThenByAsync(value, keySelector, comparer, descending) {
    var thenBy = value[types_1.AsyncOrderedIterable.thenByAsync];
    if (typeof thenBy === "function") {
        return thenBy.call(value, keySelector, comparer, descending);
    }
    throw new TypeError();
}
exports.ThenByAsync = ThenByAsync;
/** @internal */
function NextResult(value) {
    return { done: false, value: value };
}
exports.NextResult = NextResult;
/** @internal */
function DoneResult() {
    return { done: true, value: undefined };
}
exports.DoneResult = DoneResult;
/** @internal */
function SameValue(x, y) {
    return (x === y) ? (x !== 0 || 1 / x === 1 / y) : (x !== x && y !== y);
}
exports.SameValue = SameValue;
/** @internal */
function SameValueZero(x, y) {
    return (x === y) || (x !== x && y !== y);
}
exports.SameValueZero = SameValueZero;
/** @internal */
function CreateGroupings(source, keySelector, elementSelector, keyEqualer) {
    var e_1, _a;
    var map = keyEqualer ? new collections_1.HashMap(keyEqualer) : new Map();
    try {
        for (var _b = tslib_1.__values(conversion_1.ToIterable(source)), _c = _b.next(); !_c.done; _c = _b.next()) {
            var item = _c.value;
            var key = keySelector(item);
            var element = elementSelector(item);
            var grouping = map.get(key);
            if (grouping == null) {
                grouping = [];
                map.set(key, grouping);
            }
            grouping.push(element);
        }
    }
    catch (e_1_1) { e_1 = { error: e_1_1 }; }
    finally {
        try {
            if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
        }
        finally { if (e_1) throw e_1.error; }
    }
    return map;
}
exports.CreateGroupings = CreateGroupings;
/** @internal */ function CreateGroupingsAsync(source, keySelector, elementSelector, keyEqualer) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var e_2, _a, map, _b, _c, item, key, element, grouping, e_2_1;
        return tslib_1.__generator(this, function (_d) {
            switch (_d.label) {
                case 0:
                    map = keyEqualer ? new collections_1.HashMap(keyEqualer) : new Map();
                    _d.label = 1;
                case 1:
                    _d.trys.push([1, 7, 8, 13]);
                    _b = tslib_1.__asyncValues(conversion_1.ToPossiblyAsyncIterable(source));
                    _d.label = 2;
                case 2: return [4 /*yield*/, _b.next()];
                case 3:
                    if (!(_c = _d.sent(), !_c.done)) return [3 /*break*/, 6];
                    item = _c.value;
                    key = keySelector(item);
                    return [4 /*yield*/, elementSelector(item)];
                case 4:
                    element = _d.sent();
                    grouping = map.get(key);
                    if (grouping == null) {
                        grouping = [];
                        map.set(key, grouping);
                    }
                    grouping.push(element);
                    _d.label = 5;
                case 5: return [3 /*break*/, 2];
                case 6: return [3 /*break*/, 13];
                case 7:
                    e_2_1 = _d.sent();
                    e_2 = { error: e_2_1 };
                    return [3 /*break*/, 13];
                case 8:
                    _d.trys.push([8, , 11, 12]);
                    if (!(_c && !_c.done && (_a = _b.return))) return [3 /*break*/, 10];
                    return [4 /*yield*/, _a.call(_b)];
                case 9:
                    _d.sent();
                    _d.label = 10;
                case 10: return [3 /*break*/, 12];
                case 11:
                    if (e_2) throw e_2.error;
                    return [7 /*endfinally*/];
                case 12: return [7 /*endfinally*/];
                case 13: return [2 /*return*/, map];
            }
        });
    });
}
exports.CreateGroupingsAsync = CreateGroupingsAsync;
/** @internal */
function SelectGroupingKey(grouping) {
    return grouping[types_1.Grouping.key];
}
exports.SelectGroupingKey = SelectGroupingKey;
/** @internal */
function TryAdd(set, value) {
    var size = set.size;
    set.add(value);
    return set.size > size;
}
exports.TryAdd = TryAdd;
/** @internal */
function MakeDescriptor(_key, value) {
    return {
        enumerable: true,
        configurable: true,
        writable: true,
        value: value
    };
}
exports.MakeDescriptor = MakeDescriptor;
//# sourceMappingURL=utils.js.map