"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 });
const tslib_1 = require("tslib");
const types_1 = require("../types");
const conversion_1 = require("./conversion");
const guards_1 = require("./guards");
const decorators_1 = require("./decorators");
const types_2 = require("./types");
const collections_1 = require("equatable/collections");
/** @internal */
function GetIterator(source) {
    const iterator = source[Symbol.iterator];
    if (typeof iterator === "function") {
        return iterator.call(source);
    }
    throw new TypeError();
}
exports.GetIterator = GetIterator;
/** @internal */
function GetAsyncIterator(source) {
    const asyncIterator = guards_1.IsAsyncIterable(source) ? source[Symbol.asyncIterator] : undefined;
    if (typeof asyncIterator === "function") {
        return asyncIterator.call(source);
    }
    const 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;
let AsyncFromSyncIterator = class AsyncFromSyncIterator {
    constructor(iterator) {
        this._iterator = iterator;
    }
    async next(value) {
        const { done, value: resultValue } = this._iterator.next(value);
        return { done, value: await resultValue };
    }
    async return(value) {
        const returnMethod = this._iterator.return;
        if (returnMethod === undefined) {
            return { done: true, value: value };
        }
        const { done, value: resultValue } = returnMethod.call(this._iterator, value);
        return { done, value: await resultValue };
    }
    async throw(value) {
        const throwMethod = this._iterator.throw;
        if (throwMethod === undefined) {
            throw value;
        }
        const { done, value: resultValue } = throwMethod.call(this._iterator, value);
        return { done, value: await resultValue };
    }
};
AsyncFromSyncIterator = tslib_1.__decorate([
    decorators_1.ToStringTag("Async-from-sync Iterator")
], AsyncFromSyncIterator);
/** @internal */
function GetHierarchy(value) {
    const hierarchy = value[types_1.Hierarchical.hierarchy];
    if (typeof hierarchy === "function") {
        return hierarchy.call(value);
    }
    throw new TypeError();
}
exports.GetHierarchy = GetHierarchy;
/** @internal */ function GetSource(query) {
    const 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) {
    const 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) {
        const close = iterator.return;
        if (typeof close === "function") {
            return close.call(iterator);
        }
    }
}
exports.IteratorClose = IteratorClose;
/** @internal */
function AsyncIteratorClose(iterator) {
    if (iterator !== undefined && iterator !== null) {
        const close = iterator.return;
        if (typeof close === "function") {
            return close.call(iterator);
        }
    }
}
exports.AsyncIteratorClose = AsyncIteratorClose;
/** @internal */ function ThenBy(value, keySelector, comparer, descending) {
    const 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) {
    const 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 };
}
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) {
    const map = keyEqualer ? new collections_1.HashMap(keyEqualer) : new Map();
    for (const item of conversion_1.ToIterable(source)) {
        let key = keySelector(item);
        let element = elementSelector(item);
        let grouping = map.get(key);
        if (grouping == null) {
            grouping = [];
            map.set(key, grouping);
        }
        grouping.push(element);
    }
    return map;
}
exports.CreateGroupings = CreateGroupings;
/** @internal */ async function CreateGroupingsAsync(source, keySelector, elementSelector, keyEqualer) {
    var e_1, _a;
    const map = keyEqualer ? new collections_1.HashMap(keyEqualer) : new Map();
    try {
        for (var _b = tslib_1.__asyncValues(conversion_1.ToPossiblyAsyncIterable(source)), _c; _c = await _b.next(), !_c.done;) {
            const item = _c.value;
            let key = keySelector(item);
            let element = await elementSelector(item);
            let 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)) await _a.call(_b);
        }
        finally { if (e_1) throw e_1.error; }
    }
    return map;
}
exports.CreateGroupingsAsync = CreateGroupingsAsync;
/** @internal */
function SelectGroupingKey(grouping) {
    return grouping[types_1.Grouping.key];
}
exports.SelectGroupingKey = SelectGroupingKey;
/** @internal */
function TryAdd(set, value) {
    const 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
    };
}
exports.MakeDescriptor = MakeDescriptor;
//# sourceMappingURL=utils.js.map