var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { combineLatest, Subject } from 'rxjs';
import { first, map, startWith } from 'rxjs/operators';
import { TapDataError } from '../tap-data-error';
export class AbstractBundleDataStream {
    constructor(_variables // private _variables: EditableDataStreamInterface<any, Uint8Array>[] // converter: EncoderDecoder<DataType, Uint8Array>
    ) {
        this._variables = _variables;
    }
    get variables() {
        return Object.values(this._variables);
    }
    readRaw() {
        return __awaiter(this, void 0, void 0, function* () {
            const raw = yield this.readRawInner();
            this.notifyRawValue(raw);
            return raw;
        });
    }
    // abstract read(): Promise<DataType>;
    read() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.readRaw();
            return this.valueSnapshot;
        });
    }
    write(value) {
        return __awaiter(this, void 0, void 0, function* () {
            // if (typeof value !== 'object') {
            //     throw TapDataError.illegalParameter();
            // }
            for (const key in value) {
                yield this.variable(key).writeRaw(value[key]);
            }
        });
    }
    variable(id) {
        if (!(id in this._variables)) {
            throw new Error(`Variable "${id}" not found in bundle "${this.id.toString()}"`);
        }
        return this._variables[id];
    }
    get rawValues() {
        const variables = Object.values(this._variables);
        return combineLatest(variables.map((v) => v.rawValues.pipe(startWith(undefined)))).pipe(map((values) => {
            return values.reduce((accumulator, v, index) => {
                accumulator[variables[index].id] = v; // TODO
                return accumulator;
            }, {});
        }));
    }
    get rawValueSnaphot() {
        const variables = Object.values(this._variables);
        return variables.reduce((accumulator, v, index) => {
            accumulator[variables[index].id] = v.rawValueSnaphot;
            return accumulator;
        }, {});
    }
    get valueSnapshot() {
        const variables = Object.values(this._variables);
        return variables.reduce((accumulator, v, index) => {
            accumulator[variables[index].id] = v.valueSnapshot;
            return accumulator;
        }, {});
    }
    get values() {
        const variables = Object.values(this._variables);
        return combineLatest(variables.map((v) => v.values.pipe(startWith(undefined)))).pipe(map((values) => {
            return values.reduce((accumulator, v, index) => {
                accumulator[variables[index].id] = v;
                return accumulator;
            }, {});
        }));
    }
    notifyRawValue(v) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            for (const id in v) {
                const value = v[id];
                if (value !== undefined) {
                    (_a = this._variables[id]) === null || _a === void 0 ? void 0 : _a.notifyRawValue(value);
                }
            }
        });
    }
    findVariable(id) {
        return id in this._variables ? this._variables[id] : undefined;
    }
    hasVariable(id) {
        return !!this.findVariable(id);
    }
    writeRaw(values) {
        return __awaiter(this, void 0, void 0, function* () {
            for (const key in values) {
                const value = values[key];
                if (value !== undefined) {
                    yield this.variable(key).writeRaw(value);
                }
            }
        });
    }
}
export class AbstractEditableDataStream {
    constructor() {
        // static fromCustom(arg0: CustomVariableConfig) {
        //     return new Variable<T>(config, );
        // }
        // public static fromConfig<T>(config: VariableConfig) {
        //     return new Variable<T>(config, );
        // }
        // public static fromMemory(config: MemoryInfoConfig) {
        //     return new Variable<T>(config, );
        // }
        this.rawDataStream = new Subject(); // = new Subject<RawType>();
        // private selfReadStream = new Subject<RawType>();
        this.values = this.rawDataStream.pipe(map((v) => this.decodeValue(v)));
        // if (dataStream) {
        //     this.dataStream = merge(
        //         dataStream,
        //         this.selfReadStream
        //     );
        // }
        // else {
        //     this.dataStream = this.selfReadStream;
        // }
        // this.dataStream = this.dataStream
        //     .pipe(
        //         tap(v => this.lastRawValue = v)
        //     );
        // // Do we need to subscribe ?
        // this.dataStream.subscribe();
    }
    get lastRawValue() {
        return this._lastRawValue;
    }
    get rawValueSnaphot() {
        return this.lastRawValue;
    }
    get valueSnapshot() {
        if (this.lastRawValue === undefined) {
            return undefined;
        }
        return this.decodeValue(this.lastRawValue);
    }
    get rawValues() {
        return this.rawDataStream;
    }
    //  {
    //     const value = await this.rawReader(this.context);
    //     this.notifyRawValue(value);
    //     return value;
    // }
    notifyRawValue(newValue) {
        return __awaiter(this, void 0, void 0, function* () {
            this._lastRawValue = newValue;
            this.rawDataStream.next(newValue);
        });
    }
    readRaw() {
        return __awaiter(this, void 0, void 0, function* () {
            const value = yield this.readRawInner();
            this.notifyRawValue(value);
            return value;
        });
    }
    read() {
        return __awaiter(this, void 0, void 0, function* () {
            const p = this.values.pipe(first()).toPromise();
            yield this.readRaw();
            return p;
        });
    }
    write(value) {
        return __awaiter(this, void 0, void 0, function* () {
            // if (!this.rawWritter) {
            //     throw new Error(`Cannot write value for ${this.id}`);
            // }
            const encoded = this.encodeValue(value);
            return this.writeRaw(encoded);
        });
    }
    encodeValue(value) {
        try {
            return this.converter.encode(value);
        }
        catch (err) {
            throw TapDataError.unexpectedEncodedValueError(this, value, err);
        }
    }
    decodeValue(data) {
        try {
            return this.converter.decode(data);
        }
        catch (err) {
            throw TapDataError.unexpectedVariableDataRead(this, data, err);
        }
    }
}
//# sourceMappingURL=data:application/json;base64, 