/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module iModels
 */
import { expectDefined } from "@itwin/core-bentley";
import { BlobOptionsBuilder, DbQueryError, DbRequestKind, } from "./ConcurrentQuery";
/** @beta */
export class Uint8Chunks {
    _chunks = [];
    append(chunk) {
        this._chunks.push(chunk);
    }
    at(idx) { return this._chunks[idx]; }
    get length() { return this._chunks.length; }
    [Symbol.iterator]() {
        return this._chunks[Symbol.iterator];
    }
    combine() {
        const totalChunkLength = this._chunks.reduce((acc, v) => acc + v.length, 0);
        const combineChunk = new Uint8Array(totalChunkLength);
        let offset = 0;
        for (const array of this._chunks) {
            combineChunk.set(array, offset);
            offset += array.length;
        }
        return combineChunk;
    }
}
/** @beta */
export class BlobReader {
    _executor;
    className;
    accessString;
    instanceId;
    _chunks = new Uint8Chunks();
    _lengthToRead = -1;
    _options = new BlobOptionsBuilder().getOptions();
    constructor(_executor, className, accessString, instanceId, options) {
        this._executor = _executor;
        this.className = className;
        this.accessString = accessString;
        this.instanceId = instanceId;
        this.reset(options);
    }
    reset(options) {
        if (options) {
            this._options = options;
        }
        this._chunks = new Uint8Chunks();
        this._lengthToRead = expectDefined(this.range.count);
    }
    get range() { return expectDefined(this._options.range); }
    async step() {
        if (this._lengthToRead === this._chunks.length) {
            return false;
        }
        const request = {
            kind: DbRequestKind.BlobIO,
            className: this.className,
            accessString: this.accessString,
            instanceId: this.instanceId,
            ...this._options,
        };
        request.range = { offset: this._chunks.length, count: this.range ? this._lengthToRead - this._chunks.length : 0 };
        const resp = await this._executor.execute(request);
        DbQueryError.throwIfError(resp, request);
        if (this._lengthToRead === -1) {
            this._lengthToRead = resp.rawBlobSize;
        }
        if (resp.data && resp.data.length > 0) {
            this._chunks.append(resp.data);
        }
        return true;
    }
    async readToEnd() {
        while (await this.step()) { }
        return this._chunks.combine();
    }
    get current() {
        if (this._chunks.length === 0) {
            throw new Error("there is no current buffer");
        }
        return this._chunks.at(this._chunks.length);
    }
    get chunks() { return this._chunks; }
}
//# sourceMappingURL=BlobReader.js.map