"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.EmbeddedFontFile = exports.CadFontFile = void 0;
exports.shxFontFileFromBlob = shxFontFileFromBlob;
exports.rscFontFileFromBlob = rscFontFileFromBlob;
exports.trueTypeFontFileFromFileName = trueTypeFontFileFromFileName;
const fs = require("fs");
const core_common_1 = require("@itwin/core-common");
const Symbols_1 = require("./Symbols");
const core_bentley_1 = require("@itwin/core-bentley");
const NativePlatform_1 = require("./NativePlatform");
class FontFileImpl {
    [Symbols_1._implementationProhibited] = undefined;
    faces;
    get isEmbeddable() { return true; }
    [Symbols_1._key];
    [Symbols_1._faceProps];
    constructor(faces) {
        this.faces = faces.map((face) => {
            return {
                familyName: face.familyName,
                isBold: face.faceName.startsWith("bold"),
                isItalic: face.faceName.endsWith("italic"),
            };
        });
        this[Symbols_1._faceProps] = faces;
        // Sort the face props in canonical order so we can compare FontFiles for equivalent contents.
        this[Symbols_1._faceProps].sort((a, b) => a.familyName.localeCompare(b.familyName) || a.faceName.localeCompare(b.faceName) || (0, core_bentley_1.compareNumbersOrUndefined)(a.subId, b.subId));
        // Stringify the face props so that the key properties (and no other properties) appear in a canonical order. for trivial comparisons.
        this[Symbols_1._key] = JSON.stringify(this[Symbols_1._faceProps], ["familyName", "faceName", "type", "subId"]);
    }
}
/** Points to an OpenType font file on disk. */
class TrueTypeFontFile extends FontFileImpl {
    #fileName;
    #embeddable;
    constructor(fileName, embeddable, faces) {
        super(faces);
        this.#fileName = fileName;
        this.#embeddable = embeddable;
    }
    get type() { return core_common_1.FontType.TrueType; }
    get isEmbeddable() { return this.#embeddable; }
    [Symbols_1._getData]() {
        return fs.readFileSync(this.#fileName);
    }
}
/** Holds the binary representation of a SHX or RSC font in memory. */
class CadFontFile extends FontFileImpl {
    #data;
    #type;
    constructor(data, type, faces) {
        super(faces);
        this.#data = data;
        this.#type = type;
    }
    get type() { return this.#type; }
    [Symbols_1._getData]() { return this.#data; }
}
exports.CadFontFile = CadFontFile;
/** Points to a font file in any format embedded in an iModel. */
class EmbeddedFontFile extends FontFileImpl {
    // The value of the Id column for the row in the be_Prop table that embeds this font's data.
    #db;
    #id;
    #type;
    constructor(db, id, type, faces) {
        super(faces);
        this.#db = db;
        this.#id = id;
        this.#type = type;
    }
    get type() { return this.#type; }
    [Symbols_1._getData]() {
        const data = this.#db.queryFilePropertyBlob({
            namespace: "dgn_Font",
            name: "EmbeddedFaceData",
            id: this.#id,
        });
        if (!data) {
            throw new Error("Embedded font not found");
        }
        return data;
    }
}
exports.EmbeddedFontFile = EmbeddedFontFile;
function shxFontFileFromBlob(args) {
    if (args.familyName.length === 0) {
        throw new Error("Font family name cannot be empty");
    }
    // An SHX file with fewer than 40 bytes isn't valid.
    const minShxSize = 40;
    const shxHeaders = [
        "AutoCAD-86 unifont 1.0",
        "AutoCAD-86 shapes 1.0",
        "AutoCAD-86 shapes 1.1",
    ].map((shxHeader) => Array.from(shxHeader))
        .map((chars) => new Uint8Array(chars.map((ch) => ch.charCodeAt(0))));
    // See https://github.com/iTwin/imodel-native/blob/91f509c2175dc49ce1efcf5a906c9a9aa193451d/iModelCore/iModelPlatform/DgnCore/ShxFont.cpp#L44
    function validateShx(blob) {
        if (blob.length >= minShxSize) {
            for (const header of shxHeaders) {
                if (header.every((char, index) => char === blob[index])) {
                    return;
                }
            }
        }
        throw new Error("Failed to read font file");
    }
    validateShx(args.blob);
    return new CadFontFile(args.blob, core_common_1.FontType.Shx, [{
            faceName: "regular",
            familyName: args.familyName,
            type: core_common_1.FontType.Shx,
        }]);
}
function rscFontFileFromBlob(args) {
    if (args.familyName.length === 0) {
        throw new Error("Font family name cannot be empty");
    }
    if (!NativePlatform_1.IModelNative.platform.isRscFontData(args.blob)) {
        throw new Error("Failed to read font file");
    }
    return new CadFontFile(args.blob, core_common_1.FontType.Rsc, [{
            faceName: "regular",
            familyName: args.familyName,
            type: core_common_1.FontType.Rsc,
            encoding: args.encoding,
        }]);
}
function trueTypeFontFileFromFileName(fileName) {
    const metadata = NativePlatform_1.IModelNative.platform.getTrueTypeFontMetadata(fileName);
    if (metadata.faces.length === 0) {
        // The input was almost certainly not a TrueType font file.
        throw new Error("Failed to read font file");
    }
    return new TrueTypeFontFile(fileName, metadata.embeddable, metadata.faces);
}
//# sourceMappingURL=FontFileImpl.js.map