"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.writeSfntTtcFromTableSlices = writeSfntTtcFromTableSlices;
exports.writeSfntTtc = writeSfntTtc;
const bin_util_1 = require("@ot-builder/bin-util");
const primitive_1 = require("@ot-builder/primitive");
const collector_1 = require("../otf/collector");
function writeSfntTtcFromTableSlices(sfntList) {
    const store = new Map();
    const records = [];
    let fFoundDSIG = false;
    for (const sfnt of sfntList) {
        const entry = { sfntVersion: sfnt.version, tableRecords: [] };
        for (const [tag, table] of sfnt.tables) {
            if (tag === "DSIG") {
                // A sub-font has `DSIG` table, which could not be directly included in TTC
                fFoundDSIG = true;
            }
            else {
                entry.tableRecords.push((0, collector_1.collectTableData)(tag, table, store));
            }
        }
        entry.tableRecords.sort((a, b) => (a.tag < b.tag ? -1 : a.tag > b.tag ? 1 : 0));
        records.push(entry);
    }
    (0, collector_1.allocateBlobOffsets)(store);
    const ttcHeaderSize = getTtcHeaderSize(fFoundDSIG, sfntList.length);
    let totalHeaderSize = ttcHeaderSize;
    let currentOffsetTableOffset = ttcHeaderSize;
    for (const sr of records)
        totalHeaderSize += getOffsetTableSize(sr.tableRecords.length);
    const bw = new bin_util_1.BufferWriter();
    bw.uint32(tagToUInt32("ttcf"));
    bw.uint16(fFoundDSIG ? 2 : 1);
    bw.uint16(0);
    bw.uint32(sfntList.length);
    for (let fid = 0; fid < records.length; fid++) {
        const rec = records[fid];
        bw.seek(getTtcTablePtrOffset(fid));
        bw.uint32(currentOffsetTableOffset);
        bw.seek(currentOffsetTableOffset);
        const numTable = rec.tableRecords.length;
        const searchRange = Math.pow(2, Math.floor(Math.log(numTable) / Math.LN2)) * 16;
        const entrySelector = Math.floor(Math.log(numTable) / Math.LN2);
        const rangeShift = numTable * 16 - searchRange;
        bw.uint32(rec.sfntVersion);
        bw.uint16(numTable);
        bw.uint16(searchRange);
        bw.uint16(entrySelector);
        bw.uint16(rangeShift);
        currentOffsetTableOffset += getOffsetTableSize(rec.tableRecords.length);
        for (let k = 0; k < rec.tableRecords.length; k++) {
            const table = rec.tableRecords[k];
            bw.uint32(tagToUInt32(table.tag));
            bw.uint32(table.blob.checksum);
            bw.uint32(totalHeaderSize + table.blob.offset + table.start);
            bw.uint32(table.length);
        }
    }
    for (const blob of store.values()) {
        bw.seek(totalHeaderSize + blob.offset);
        bw.bytes(blob.content);
    }
    if (fFoundDSIG) {
        const dsigOffset = bw.length;
        // DSIG entry
        bw.seek(getTtcTablePtrOffset(sfntList.length));
        bw.uint32(tagToUInt32("DSIG"));
        bw.uint32(8);
        bw.uint32(dsigOffset);
        // DSIG data
        bw.seek(dsigOffset);
        bw.uint32(0x00000001);
        bw.uint32(0x00000000);
    }
    return bw.toBuffer();
}
function writeSfntTtc(sfntList) {
    const dss = [];
    for (const sfnt of sfntList) {
        const ds = { version: sfnt.version, tables: new Map() };
        for (const [tag, table] of sfnt.tables)
            ds.tables.set(tag, (0, collector_1.BufferToSlice)(table));
        dss.push(ds);
    }
    return writeSfntTtcFromTableSlices(dss);
}
// Util functions
function getTtcTablePtrOffset(numFonts) {
    return primitive_1.UInt32.size * 2 + primitive_1.UInt16.size * 2 + primitive_1.UInt32.size * numFonts;
}
function getTtcHeaderSize(fSigned, numFonts) {
    let size = getTtcTablePtrOffset(numFonts);
    if (fSigned)
        size += primitive_1.UInt32.size * 3;
    return size;
}
function getOffsetTableSize(numTable) {
    const headerSize = primitive_1.UInt32.size + primitive_1.UInt16.size * 4;
    const recordSize = primitive_1.Tag.size + primitive_1.UInt32.size * 3;
    return headerSize + numTable * recordSize;
}
function tagToUInt32(x) {
    return ((x.charCodeAt(0) & 0xff) * 256 * 256 * 256 +
        (x.charCodeAt(1) & 0xff) * 256 * 256 +
        (x.charCodeAt(2) & 0xff) * 256 +
        (x.charCodeAt(3) & 0xff));
}
//# sourceMappingURL=write.js.map