"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.idFromText2 = exports.idToText2 = exports.idFromText = exports.idToText = exports.SubPersistence = exports.MemoryPersistence = void 0;
const utils_1 = require("@darlean/utils");
class MemoryPersistable {
    constructor(persistence, partitionKey, sortKey, value) {
        this._changed = false;
        this.persistence = persistence;
        this.partitionKey = partitionKey;
        this.sortKey = sortKey;
        this.value = value;
    }
    async load() {
        const result = await this.persistence.loadImpl(this.partitionKey, this.sortKey);
        if (result[0] !== undefined) {
            this.value = result[0];
        }
        this.version = result[1];
        this._changed = false;
        return result[0];
    }
    async store(force) {
        if (!force) {
            if (!this._changed) {
                return;
            }
        }
        if (this._changed) {
            if (this.version) {
                const next = parseInt(this.version || '0') + 1;
                this.version = next.toString().padStart(20, '0');
            }
            else {
                const next = Date.now();
                this.version = next.toString().padStart(20, '0');
            }
        }
        await this.persistence.storeImpl(this.partitionKey, this.sortKey, this.value, this.version);
        this._changed = false;
    }
    change(value) {
        if (value !== undefined) {
            this.value = value;
        }
        this._changed = true;
    }
    clear() {
        this.value = undefined;
        this._changed = true;
    }
    changed() {
        return this._changed;
    }
}
class MemoryPersistence {
    constructor() {
        this.values = new Map();
    }
    persistable(partitionKey, sortKey, value) {
        return new MemoryPersistable(this, partitionKey, sortKey, value);
    }
    async load(partitionKey, sortKey) {
        const p = this.persistable(partitionKey, sortKey, undefined);
        await p.load();
        return p;
    }
    async loadImpl(partitionKey, sortKey) {
        const pkey = idToText(partitionKey || []);
        const p = this.values.get(pkey);
        if (p) {
            const skey = idToText(sortKey || []);
            return [p.get(skey), undefined];
        }
        return [undefined, undefined];
    }
    async storeImpl(partitionKey, sortKey, value, _version) {
        const pkey = idToText(partitionKey || []);
        let p = this.values.get(pkey);
        if (!p) {
            p = new Map();
            this.values.set(pkey, p);
        }
        const skey = idToText(sortKey || []);
        p.set(skey, value);
    }
    sub(partitionKey, sortKey) {
        return new SubPersistence(this, partitionKey, sortKey);
    }
    clear() {
        this.values.clear();
    }
}
exports.MemoryPersistence = MemoryPersistence;
class SubPersistence {
    constructor(superPersistence, basePartitionKey, baseSortKey) {
        this.superPersistence = superPersistence;
        this.basePartitionKey = basePartitionKey || [];
        this.baseSortKey = baseSortKey || [];
    }
    persistable(partitionKey, sortKey, value) {
        const keys = this.deriveKeys(partitionKey, sortKey);
        return this.superPersistence.persistable(keys.pk, keys.sk, value);
    }
    async load(partitionKey, sortKey) {
        const p = this.persistable(partitionKey, sortKey, undefined);
        await p.load();
        return p;
    }
    sub(partitionKey, sortKey) {
        const keys = this.deriveKeys(partitionKey, sortKey);
        return new SubPersistence(this, keys.pk, keys.sk);
    }
    deriveKeys(partitionKey, sortKey) {
        if (partitionKey?.length ?? 0 > 0) {
            if (this.baseSortKey.length > 0) {
                throw new Error(`Sub partition key only allowed when there is no base sort key`);
            }
            return { pk: [...this.basePartitionKey, ...(partitionKey ?? [])], sk: sortKey ?? [] };
        }
        else {
            return { pk: this.basePartitionKey, sk: [...this.baseSortKey, ...(sortKey ?? [])] };
        }
    }
}
exports.SubPersistence = SubPersistence;
function idToText(id) {
    const parts = id.map((v) => {
        v = (0, utils_1.replaceAll)(v, '\u0001', '\u0001\u0001');
        v = (0, utils_1.replaceAll)(v, '\u0000', '\u0001\u0000');
        return v;
    });
    return parts.join('\u0000\u0000');
}
exports.idToText = idToText;
function idFromText(text) {
    const parts = text.split('\u0000\u0000');
    return parts.map((v) => {
        v = (0, utils_1.replaceAll)(v, '\u0001\u0000', '\u0000');
        v = (0, utils_1.replaceAll)(v, '\u0001\u0001', '\u0001');
        return v;
    });
}
exports.idFromText = idFromText;
function idToText2(id) {
    const content = id.join('');
    const lengths = id.map((v) => v.length).join('@');
    return content + '#' + lengths;
}
exports.idToText2 = idToText2;
function idFromText2(text) {
    const idx = text.lastIndexOf('#');
    const content = text.substring(0, idx);
    const lengths = text.substring(idx + 1).split('@');
    const result = [];
    let offset = 0;
    for (const length of lengths) {
        const len = parseInt(length);
        result.push(content.substring(offset, offset + len));
        offset += len;
    }
    return result;
}
exports.idFromText2 = idFromText2;
