"use strict";
/**
 * @license
 * Copyright 2019 Balena Ltd.
 *
 * 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 });
exports.BlockMap = void 0;
const crypto_1 = require("crypto");
const xml_js_1 = require("xml-js");
const parse_1 = require("./parse");
const range_1 = require("./range");
function xmlTag(tag, text) {
    return xml_js_1.js2xml({ [tag]: { _text: text } }, { compact: true });
}
class BlockMap {
    constructor(options = {}) {
        this.version = options.version || '2.0';
        this.imageSize = options.imageSize || 0;
        this.blockSize = options.blockSize || 4096;
        this.blocksCount = options.blocksCount || 0;
        this.mappedBlocksCount = options.mappedBlocksCount || 0;
        this.checksum = options.checksum;
        this.checksumType = options.checksumType || 'sha256';
        this.ranges = (options.ranges || []).map(range_1.Range.from);
    }
    /**
     * Calculate the bmap file's checksum and inject it
     */
    injectChecksum(bmap) {
        const checksum = this.checksum || '';
        const zerofill = xmlTag('BmapFileChecksum', checksum.replace(/./g, '0'));
        const value = bmap.replace(xmlTag('BmapFileChecksum', checksum), zerofill);
        const digest = crypto_1.createHash(this.checksumType).update(value).digest('hex');
        return value.replace(zerofill, xmlTag('BmapFileChecksum', digest));
    }
    /** Create a block map from its JSON representation */
    static fromJSON(data) {
        const options = typeof data === 'string' ? JSON.parse(data) : data;
        return new BlockMap(options);
    }
    /** Stringify a block map into .bmap format */
    toString() {
        const ranges2 = this.ranges.map((range) => {
            const blockRange = range.start !== range.end ? range.start + '-' + range.end : range.start;
            return {
                _attributes: { chksum: range.checksum },
                _text: blockRange,
            };
        });
        const data2 = {
            _declaration: {
                _attributes: {
                    version: '1.0',
                    encoding: 'UTF-8',
                },
            },
            bmap: {
                _attributes: { version: '2.0' },
                ImageSize: { _text: this.imageSize },
                BlockSize: { _text: this.blockSize },
                BlocksCount: { _text: this.blocksCount },
                MappedBlocksCount: { _text: this.mappedBlocksCount },
                ChecksumType: { _text: this.checksumType },
                BmapFileChecksum: { _text: this.checksum },
                BlockMap: { Range: ranges2 },
            },
        };
        const bmap2 = xml_js_1.js2xml(data2, { compact: true, spaces: 2 }) + '\n';
        return this.injectChecksum(bmap2);
    }
    /** Parse a .bmap file */
    static parse(value, verify = true) {
        return new BlockMap(parse_1.parse(value, verify));
    }
}
exports.BlockMap = BlockMap;
/** Supported .bmap format versions */
BlockMap.versions = ['1.2', '1.3', '1.4', '2.0'];
//# sourceMappingURL=blockmap.js.map