"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 assert = require("./assert");
var decorators_1 = require("./decorators");
var utils_1 = require("./utils");
var guards_1 = require("./guards");
var types_1 = require("../types");
var flow_1 = require("./flow");
/** @internal */ function ToIterable(value) {
    if (guards_1.IsIterable(value))
        return value;
    if (guards_1.IsArrayLike(value))
        return new ArrayLikeIterable(value);
    throw new TypeError();
}
exports.ToIterable = ToIterable;
/** @internal */ function ToAsyncIterable(value) {
    if (guards_1.IsAsyncIterable(value))
        return value;
    if (guards_1.IsOrderedHierarchyIterable(value))
        return new AsyncFromSyncOrderedHierarchyIterable(value);
    if (guards_1.IsOrderedIterable(value))
        return new AsyncFromSyncOrderedIterable(value);
    if (guards_1.IsHierarchyIterable(value))
        return new AsyncFromSyncHierarchyIterable(value);
    if (guards_1.IsIterable(value))
        return new AsyncFromSyncIterable(value);
    if (guards_1.IsArrayLike(value))
        return new AsyncFromSyncIterable(new ArrayLikeIterable(value));
    throw new TypeError();
}
exports.ToAsyncIterable = ToAsyncIterable;
/** @internal */ function ToAsyncHierarchyIterable(value) {
    if (guards_1.IsAsyncHierarchyIterable(value))
        return value;
    if (guards_1.IsHierarchyIterable(value))
        return ToAsyncIterable(value);
    throw new TypeError();
}
exports.ToAsyncHierarchyIterable = ToAsyncHierarchyIterable;
/** @internal */ function ToAsyncOrderedIterable(value) {
    if (guards_1.IsAsyncOrderedIterable(value))
        return value;
    if (guards_1.IsOrderedIterable(value))
        return ToAsyncIterable(value);
    throw new TypeError();
}
exports.ToAsyncOrderedIterable = ToAsyncOrderedIterable;
/** @internal */ function ToAsyncOrderedHierarchyIterable(value) {
    if (guards_1.IsAsyncOrderedHierarchyIterable(value))
        return value;
    if (guards_1.IsOrderedHierarchyIterable(value))
        return ToAsyncIterable(value);
    throw new TypeError();
}
exports.ToAsyncOrderedHierarchyIterable = ToAsyncOrderedHierarchyIterable;
/** @internal */ function ToPossiblyAsyncIterable(value) {
    if (guards_1.IsAsyncIterable(value))
        return value;
    if (guards_1.IsIterable(value))
        return value;
    if (guards_1.IsArrayLike(value))
        return new ArrayLikeIterable(value);
    throw new TypeError();
}
exports.ToPossiblyAsyncIterable = ToPossiblyAsyncIterable;
/** @internal */ function MakeHierarchyIterable(value, hierarchy) {
    if (guards_1.IsOrderedIterable(value))
        return new OrderedHierarchyIterableImpl(value, hierarchy);
    if (guards_1.IsGrouping(value))
        return new HierarchyGroupingImpl(value.key, new HierarchyIterableImpl(value, hierarchy));
    if (guards_1.IsIterable(value))
        return new HierarchyIterableImpl(value, hierarchy);
    if (guards_1.IsArrayLike(value))
        return new HierarchyIterableImpl(new ArrayLikeIterable(value), hierarchy);
    throw new TypeError();
}
exports.MakeHierarchyIterable = MakeHierarchyIterable;
/** @internal */ function MakeOrderedHierarchyIterable(value, hierarchy) {
    if (guards_1.IsOrderedIterable(value))
        return MakeHierarchyIterable(value, hierarchy);
    throw new TypeError();
}
exports.MakeOrderedHierarchyIterable = MakeOrderedHierarchyIterable;
/** @internal */ function MakeAsyncHierarchyIterable(value, hierarchy) {
    if (guards_1.IsAsyncOrderedIterable(value))
        return new AsyncOrderedHierarchyIterableImpl(value, hierarchy);
    if (guards_1.IsAsyncIterable(value))
        return new AsyncHierarchyIterableImpl(value, hierarchy);
    if (guards_1.IsOrderedIterable(value))
        return new AsyncOrderedHierarchyIterableImpl(new AsyncFromSyncOrderedIterable(value), hierarchy);
    if (guards_1.IsIterable(value))
        return new AsyncHierarchyIterableImpl(new AsyncFromSyncIterable(value), hierarchy);
    if (guards_1.IsArrayLike(value))
        return new AsyncHierarchyIterableImpl(new AsyncFromSyncIterable(new ArrayLikeIterable(value)), hierarchy);
    throw new TypeError();
}
exports.MakeAsyncHierarchyIterable = MakeAsyncHierarchyIterable;
var ArrayLikeIterable = /** @class */ (function () {
    function ArrayLikeIterable(source) {
        assert.mustBeArrayLike(source, "source");
        this._source = source;
    }
    ArrayLikeIterable.prototype[Symbol.iterator] = function () {
        var source, i;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    source = this._source;
                    i = 0;
                    _a.label = 1;
                case 1:
                    if (!(i < source.length)) return [3 /*break*/, 4];
                    return [4 /*yield*/, source[i]];
                case 2:
                    _a.sent();
                    _a.label = 3;
                case 3:
                    ++i;
                    return [3 /*break*/, 1];
                case 4: return [2 /*return*/];
            }
        });
    };
    ArrayLikeIterable = tslib_1.__decorate([
        decorators_1.ToStringTag("ArrayLikeIterable")
    ], ArrayLikeIterable);
    return ArrayLikeIterable;
}());
var AsyncFromSyncIterable = /** @class */ (function () {
    function AsyncFromSyncIterable(source) {
        assert.mustBeIterable(source, "source");
        this._source = source;
    }
    AsyncFromSyncIterable.prototype[Symbol.asyncIterator] = function () {
        return tslib_1.__asyncGenerator(this, arguments, function _a() {
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [5 /*yield**/, tslib_1.__values(tslib_1.__asyncDelegator(tslib_1.__asyncValues(this._source)))];
                    case 1: return [4 /*yield*/, tslib_1.__await.apply(void 0, [_a.sent()])];
                    case 2:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    AsyncFromSyncIterable = tslib_1.__decorate([
        decorators_1.ToStringTag("Async-from-sync Iterable")
    ], AsyncFromSyncIterable);
    return AsyncFromSyncIterable;
}());
var AsyncFromSyncHierarchyIterable = /** @class */ (function (_super) {
    tslib_1.__extends(AsyncFromSyncHierarchyIterable, _super);
    function AsyncFromSyncHierarchyIterable(source) {
        var _this = this;
        assert.mustBeHierarchyIterable(source, "source");
        _this = _super.call(this, source) || this;
        return _this;
    }
    AsyncFromSyncHierarchyIterable.prototype[types_1.Hierarchical.hierarchy] = function () {
        return utils_1.GetHierarchy(this._source);
    };
    AsyncFromSyncHierarchyIterable = tslib_1.__decorate([
        decorators_1.ToStringTag("Async-from-sync HierarchyIterable")
    ], AsyncFromSyncHierarchyIterable);
    return AsyncFromSyncHierarchyIterable;
}(AsyncFromSyncIterable));
var AsyncFromSyncOrderedIterable = /** @class */ (function (_super) {
    tslib_1.__extends(AsyncFromSyncOrderedIterable, _super);
    function AsyncFromSyncOrderedIterable(source) {
        var _this = this;
        assert.mustBeOrderedIterable(source, "source");
        _this = _super.call(this, source) || this;
        return _this;
    }
    AsyncFromSyncOrderedIterable_1 = AsyncFromSyncOrderedIterable;
    AsyncFromSyncOrderedIterable.prototype[types_1.AsyncOrderedIterable.thenByAsync] = function (keySelector, comparison, descending) {
        return new AsyncFromSyncOrderedIterable_1(utils_1.ThenBy(this._source, keySelector, comparison, descending));
    };
    var AsyncFromSyncOrderedIterable_1;
    AsyncFromSyncOrderedIterable = AsyncFromSyncOrderedIterable_1 = tslib_1.__decorate([
        decorators_1.ToStringTag("Async-from-sync OrderedIterable")
    ], AsyncFromSyncOrderedIterable);
    return AsyncFromSyncOrderedIterable;
}(AsyncFromSyncIterable));
var AsyncFromSyncOrderedHierarchyIterable = /** @class */ (function (_super) {
    tslib_1.__extends(AsyncFromSyncOrderedHierarchyIterable, _super);
    function AsyncFromSyncOrderedHierarchyIterable(source) {
        var _this = this;
        assert.mustBeOrderedHierarchyIterable(source, "source");
        _this = _super.call(this, source) || this;
        return _this;
    }
    AsyncFromSyncOrderedHierarchyIterable.prototype[types_1.Hierarchical.hierarchy] = function () {
        return utils_1.GetHierarchy(this._source);
    };
    AsyncFromSyncOrderedHierarchyIterable = tslib_1.__decorate([
        decorators_1.ToStringTag("Async-from-sync OrderedHierarchyIterable")
    ], AsyncFromSyncOrderedHierarchyIterable);
    return AsyncFromSyncOrderedHierarchyIterable;
}(AsyncFromSyncOrderedIterable));
var HierarchyIterableImpl = /** @class */ (function () {
    function HierarchyIterableImpl(source, hierarchy) {
        assert.mustBeIterable(source, "source");
        assert.mustBeHierarchyProvider(hierarchy, "hierarchy");
        this._source = source;
        this._hierarchy = hierarchy;
    }
    HierarchyIterableImpl.prototype[Symbol.iterator] = function () {
        return utils_1.GetIterator(this._source);
    };
    HierarchyIterableImpl.prototype[types_1.Hierarchical.hierarchy] = function () {
        return this._hierarchy;
    };
    HierarchyIterableImpl = tslib_1.__decorate([
        decorators_1.ToStringTag("HierarchyIterable")
    ], HierarchyIterableImpl);
    return HierarchyIterableImpl;
}());
var OrderedHierarchyIterableImpl = /** @class */ (function (_super) {
    tslib_1.__extends(OrderedHierarchyIterableImpl, _super);
    function OrderedHierarchyIterableImpl(source, hierarchy) {
        var _this = this;
        assert.mustBeOrderedIterable(source, "source");
        _this = _super.call(this, source, hierarchy) || this;
        return _this;
    }
    OrderedHierarchyIterableImpl_1 = OrderedHierarchyIterableImpl;
    OrderedHierarchyIterableImpl.prototype[types_1.OrderedIterable.thenBy] = function (keySelector, comparison, descending) {
        return new OrderedHierarchyIterableImpl_1(utils_1.ThenBy(this._source, keySelector, comparison, descending), this._hierarchy);
    };
    var OrderedHierarchyIterableImpl_1;
    OrderedHierarchyIterableImpl = OrderedHierarchyIterableImpl_1 = tslib_1.__decorate([
        decorators_1.ToStringTag("OrderedHierarchyIterable")
    ], OrderedHierarchyIterableImpl);
    return OrderedHierarchyIterableImpl;
}(HierarchyIterableImpl));
var AsyncHierarchyIterableImpl = /** @class */ (function () {
    function AsyncHierarchyIterableImpl(source, hierarchy) {
        assert.mustBeAsyncIterable(source, "source");
        assert.mustBeHierarchyProvider(hierarchy, "hierarchy");
        this._source = source;
        this._hierarchy = hierarchy;
    }
    AsyncHierarchyIterableImpl.prototype[Symbol.asyncIterator] = function () {
        return utils_1.GetAsyncIterator(this._source);
    };
    AsyncHierarchyIterableImpl.prototype[types_1.Hierarchical.hierarchy] = function () {
        return this._hierarchy;
    };
    AsyncHierarchyIterableImpl = tslib_1.__decorate([
        decorators_1.ToStringTag("AsyncHierarchyIterable")
    ], AsyncHierarchyIterableImpl);
    return AsyncHierarchyIterableImpl;
}());
var AsyncOrderedHierarchyIterableImpl = /** @class */ (function (_super) {
    tslib_1.__extends(AsyncOrderedHierarchyIterableImpl, _super);
    function AsyncOrderedHierarchyIterableImpl(source, hierarchy) {
        var _this = this;
        assert.mustBeAsyncOrderedIterable(source, "source");
        _this = _super.call(this, source, hierarchy) || this;
        return _this;
    }
    AsyncOrderedHierarchyIterableImpl_1 = AsyncOrderedHierarchyIterableImpl;
    AsyncOrderedHierarchyIterableImpl.prototype[types_1.AsyncOrderedIterable.thenByAsync] = function (keySelector, comparison, descending) {
        return new AsyncOrderedHierarchyIterableImpl_1(utils_1.ThenByAsync(this._source, keySelector, comparison, descending), this._hierarchy);
    };
    var AsyncOrderedHierarchyIterableImpl_1;
    AsyncOrderedHierarchyIterableImpl = AsyncOrderedHierarchyIterableImpl_1 = tslib_1.__decorate([
        decorators_1.ToStringTag("AsyncOrderedHierarchyIterable")
    ], AsyncOrderedHierarchyIterableImpl);
    return AsyncOrderedHierarchyIterableImpl;
}(AsyncHierarchyIterableImpl));
/** @internal */ function ToGroupingWithFlow(key, elements, source) {
    return guards_1.IsPossiblyAsyncHierarchyIterable(source)
        // TODO: fixme vvv
        // @ts-ignore
        ? CreateHierarchyGrouping(key, flow_1.FlowHierarchy(elements, source))
        : CreateGrouping(key, elements);
}
exports.ToGroupingWithFlow = ToGroupingWithFlow;
// /** @internal */ export function CreateGrouping<K, VNode, V extends VNode>(key: K, elements: HierarchyIterable<VNode, V>): HierarchyGrouping<K, VNode, V>;
// /** @internal */ export function CreateGrouping<K, V>(key: K, elements: Queryable<V>): Grouping<K, V>;
/** @internal */ function CreateGrouping(key, elements) {
    return guards_1.IsHierarchyIterable(elements) ? new HierarchyGroupingImpl(key, elements) : new GroupingImpl(key, ToIterable(elements));
}
exports.CreateGrouping = CreateGrouping;
/** @internal */ function CreateHierarchyGrouping(key, elements) {
    return new HierarchyGroupingImpl(key, elements);
}
exports.CreateHierarchyGrouping = CreateHierarchyGrouping;
var GroupingImpl = /** @class */ (function () {
    /**
     * Creates a new Grouping for the specified key.
     *
     * @param key The key for the group.
     * @param values The elements in the group.
     */
    function GroupingImpl(key, values) {
        assert.mustBeQueryable(values, "items");
        this.key = key;
        this.values = values;
    }
    Object.defineProperty(GroupingImpl.prototype, types_1.Grouping.key, {
        get: function () { return this.key; },
        enumerable: true,
        configurable: true
    });
    GroupingImpl.prototype[Symbol.iterator] = function () {
        return utils_1.GetIterator(this.values);
    };
    GroupingImpl = tslib_1.__decorate([
        decorators_1.ToStringTag("Grouping")
    ], GroupingImpl);
    return GroupingImpl;
}());
var HierarchyGroupingImpl = /** @class */ (function (_super) {
    tslib_1.__extends(HierarchyGroupingImpl, _super);
    function HierarchyGroupingImpl(key, items) {
        var _this = this;
        assert.mustBeHierarchyIterable(items, "items");
        _this = _super.call(this, key, items) || this;
        return _this;
    }
    HierarchyGroupingImpl.prototype[types_1.Hierarchical.hierarchy] = function () {
        return utils_1.GetHierarchy(this.values);
    };
    HierarchyGroupingImpl = tslib_1.__decorate([
        decorators_1.ToStringTag("HierarchyGrouping")
    ], HierarchyGroupingImpl);
    return HierarchyGroupingImpl;
}(GroupingImpl));
/** @internal */ function CreatePage(page, offset, items) {
    return guards_1.IsHierarchyIterable(items) ? new HierarchyPageImpl(page, offset, items) : new PageImpl(page, offset, ToIterable(items));
}
exports.CreatePage = CreatePage;
/** @internal */ function CreateHierarchyPage(page, offset, items) {
    return new HierarchyPageImpl(page, offset, items);
}
exports.CreateHierarchyPage = CreateHierarchyPage;
/**
 * Represents a page of results.
 */
var PageImpl = /** @class */ (function () {
    /**
     * Creates a new Page for the provided elements.
     *
     * @param page The page number (zero-based).
     * @param offset The offset in the source at which the page begins.
     * @param items The elements in the page.
     */
    function PageImpl(page, offset, items) {
        assert.mustBePositiveInteger(page, "page");
        assert.mustBePositiveInteger(offset, "offset");
        assert.mustBeIterable(items, "items");
        this.page = page;
        this.offset = offset;
        this._items = items;
    }
    Object.defineProperty(PageImpl.prototype, types_1.Page.page, {
        get: function () { return this.page; },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PageImpl.prototype, types_1.Page.offset, {
        get: function () { return this.offset; },
        enumerable: true,
        configurable: true
    });
    PageImpl.prototype[Symbol.iterator] = function () {
        return utils_1.GetIterator(this._items);
    };
    PageImpl = tslib_1.__decorate([
        decorators_1.ToStringTag("Page")
    ], PageImpl);
    return PageImpl;
}());
var HierarchyPageImpl = /** @class */ (function (_super) {
    tslib_1.__extends(HierarchyPageImpl, _super);
    function HierarchyPageImpl(page, offset, items) {
        var _this = this;
        assert.mustBeHierarchyIterable(items, "items");
        _this = _super.call(this, page, offset, items) || this;
        return _this;
    }
    HierarchyPageImpl.prototype[types_1.Hierarchical.hierarchy] = function () {
        return utils_1.GetHierarchy(this._items);
    };
    HierarchyPageImpl = tslib_1.__decorate([
        decorators_1.ToStringTag("HierarchyPage")
    ], HierarchyPageImpl);
    return HierarchyPageImpl;
}(PageImpl));
//# sourceMappingURL=conversion.js.map