"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");
var AsyncFromSyncOrderedIterable_1, OrderedHierarchyIterableImpl_1, AsyncOrderedHierarchyIterableImpl_1;
"use strict";
const assert = require("./assert");
const decorators_1 = require("./decorators");
const utils_1 = require("./utils");
const guards_1 = require("./guards");
const types_1 = require("../types");
const 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;
let ArrayLikeIterable = class ArrayLikeIterable {
    constructor(source) {
        assert.mustBeArrayLike(source, "source");
        this._source = source;
    }
    *[Symbol.iterator]() {
        const source = this._source;
        for (let i = 0; i < source.length; ++i) {
            yield source[i];
        }
    }
};
ArrayLikeIterable = tslib_1.__decorate([
    decorators_1.ToStringTag("ArrayLikeIterable")
], ArrayLikeIterable);
let AsyncFromSyncIterable = class AsyncFromSyncIterable {
    constructor(source) {
        assert.mustBeIterable(source, "source");
        this._source = source;
    }
    [Symbol.asyncIterator]() {
        return tslib_1.__asyncGenerator(this, arguments, function* _a() {
            yield tslib_1.__await(yield* tslib_1.__asyncDelegator(tslib_1.__asyncValues(this._source)));
        });
    }
};
AsyncFromSyncIterable = tslib_1.__decorate([
    decorators_1.ToStringTag("Async-from-sync Iterable")
], AsyncFromSyncIterable);
let AsyncFromSyncHierarchyIterable = class AsyncFromSyncHierarchyIterable extends AsyncFromSyncIterable {
    constructor(source) {
        assert.mustBeHierarchyIterable(source, "source");
        super(source);
    }
    [types_1.Hierarchical.hierarchy]() {
        return utils_1.GetHierarchy(this._source);
    }
};
AsyncFromSyncHierarchyIterable = tslib_1.__decorate([
    decorators_1.ToStringTag("Async-from-sync HierarchyIterable")
], AsyncFromSyncHierarchyIterable);
let AsyncFromSyncOrderedIterable = AsyncFromSyncOrderedIterable_1 = class AsyncFromSyncOrderedIterable extends AsyncFromSyncIterable {
    constructor(source) {
        assert.mustBeOrderedIterable(source, "source");
        super(source);
    }
    [types_1.AsyncOrderedIterable.thenByAsync](keySelector, comparison, descending) {
        return new AsyncFromSyncOrderedIterable_1(utils_1.ThenBy(this._source, keySelector, comparison, descending));
    }
};
AsyncFromSyncOrderedIterable = AsyncFromSyncOrderedIterable_1 = tslib_1.__decorate([
    decorators_1.ToStringTag("Async-from-sync OrderedIterable")
], AsyncFromSyncOrderedIterable);
let AsyncFromSyncOrderedHierarchyIterable = class AsyncFromSyncOrderedHierarchyIterable extends AsyncFromSyncOrderedIterable {
    constructor(source) {
        assert.mustBeOrderedHierarchyIterable(source, "source");
        super(source);
    }
    [types_1.Hierarchical.hierarchy]() {
        return utils_1.GetHierarchy(this._source);
    }
};
AsyncFromSyncOrderedHierarchyIterable = tslib_1.__decorate([
    decorators_1.ToStringTag("Async-from-sync OrderedHierarchyIterable")
], AsyncFromSyncOrderedHierarchyIterable);
let HierarchyIterableImpl = class HierarchyIterableImpl {
    constructor(source, hierarchy) {
        assert.mustBeIterable(source, "source");
        assert.mustBeHierarchyProvider(hierarchy, "hierarchy");
        this._source = source;
        this._hierarchy = hierarchy;
    }
    [Symbol.iterator]() {
        return utils_1.GetIterator(this._source);
    }
    [types_1.Hierarchical.hierarchy]() {
        return this._hierarchy;
    }
};
HierarchyIterableImpl = tslib_1.__decorate([
    decorators_1.ToStringTag("HierarchyIterable")
], HierarchyIterableImpl);
let OrderedHierarchyIterableImpl = OrderedHierarchyIterableImpl_1 = class OrderedHierarchyIterableImpl extends HierarchyIterableImpl {
    constructor(source, hierarchy) {
        assert.mustBeOrderedIterable(source, "source");
        super(source, hierarchy);
    }
    [types_1.OrderedIterable.thenBy](keySelector, comparison, descending) {
        return new OrderedHierarchyIterableImpl_1(utils_1.ThenBy(this._source, keySelector, comparison, descending), this._hierarchy);
    }
};
OrderedHierarchyIterableImpl = OrderedHierarchyIterableImpl_1 = tslib_1.__decorate([
    decorators_1.ToStringTag("OrderedHierarchyIterable")
], OrderedHierarchyIterableImpl);
let AsyncHierarchyIterableImpl = class AsyncHierarchyIterableImpl {
    constructor(source, hierarchy) {
        assert.mustBeAsyncIterable(source, "source");
        assert.mustBeHierarchyProvider(hierarchy, "hierarchy");
        this._source = source;
        this._hierarchy = hierarchy;
    }
    [Symbol.asyncIterator]() {
        return utils_1.GetAsyncIterator(this._source);
    }
    [types_1.Hierarchical.hierarchy]() {
        return this._hierarchy;
    }
};
AsyncHierarchyIterableImpl = tslib_1.__decorate([
    decorators_1.ToStringTag("AsyncHierarchyIterable")
], AsyncHierarchyIterableImpl);
let AsyncOrderedHierarchyIterableImpl = AsyncOrderedHierarchyIterableImpl_1 = class AsyncOrderedHierarchyIterableImpl extends AsyncHierarchyIterableImpl {
    constructor(source, hierarchy) {
        assert.mustBeAsyncOrderedIterable(source, "source");
        super(source, hierarchy);
    }
    [types_1.AsyncOrderedIterable.thenByAsync](keySelector, comparison, descending) {
        return new AsyncOrderedHierarchyIterableImpl_1(utils_1.ThenByAsync(this._source, keySelector, comparison, descending), this._hierarchy);
    }
};
AsyncOrderedHierarchyIterableImpl = AsyncOrderedHierarchyIterableImpl_1 = tslib_1.__decorate([
    decorators_1.ToStringTag("AsyncOrderedHierarchyIterable")
], AsyncOrderedHierarchyIterableImpl);
/** @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;
let GroupingImpl = class GroupingImpl {
    /**
     * Creates a new Grouping for the specified key.
     *
     * @param key The key for the group.
     * @param values The elements in the group.
     */
    constructor(key, values) {
        assert.mustBeQueryable(values, "items");
        this.key = key;
        this.values = values;
    }
    get [types_1.Grouping.key]() { return this.key; }
    [Symbol.iterator]() {
        return utils_1.GetIterator(this.values);
    }
};
GroupingImpl = tslib_1.__decorate([
    decorators_1.ToStringTag("Grouping")
], GroupingImpl);
let HierarchyGroupingImpl = class HierarchyGroupingImpl extends GroupingImpl {
    constructor(key, items) {
        assert.mustBeHierarchyIterable(items, "items");
        super(key, items);
    }
    [types_1.Hierarchical.hierarchy]() {
        return utils_1.GetHierarchy(this.values);
    }
};
HierarchyGroupingImpl = tslib_1.__decorate([
    decorators_1.ToStringTag("HierarchyGrouping")
], HierarchyGroupingImpl);
/** @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.
 */
let PageImpl = class PageImpl {
    /**
     * 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.
     */
    constructor(page, offset, items) {
        assert.mustBePositiveInteger(page, "page");
        assert.mustBePositiveInteger(offset, "offset");
        assert.mustBeIterable(items, "items");
        this.page = page;
        this.offset = offset;
        this._items = items;
    }
    get [types_1.Page.page]() { return this.page; }
    get [types_1.Page.offset]() { return this.offset; }
    [Symbol.iterator]() {
        return utils_1.GetIterator(this._items);
    }
};
PageImpl = tslib_1.__decorate([
    decorators_1.ToStringTag("Page")
], PageImpl);
let HierarchyPageImpl = class HierarchyPageImpl extends PageImpl {
    constructor(page, offset, items) {
        assert.mustBeHierarchyIterable(items, "items");
        super(page, offset, items);
    }
    [types_1.Hierarchical.hierarchy]() {
        return utils_1.GetHierarchy(this._items);
    }
};
HierarchyPageImpl = tslib_1.__decorate([
    decorators_1.ToStringTag("HierarchyPage")
], HierarchyPageImpl);
//# sourceMappingURL=conversion.js.map