/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import * as fs from "fs";
import { FontType } from "@itwin/core-common";
import { _faceProps, _getData, _implementationProhibited, _key } from "./Symbols";
import { compareNumbersOrUndefined } from "@itwin/core-bentley";
import { IModelNative } from "./NativePlatform";
class FontFileImpl {
    [_implementationProhibited] = undefined;
    faces;
    get isEmbeddable() { return true; }
    [_key];
    [_faceProps];
    constructor(faces) {
        this.faces = faces.map((face) => {
            return {
                familyName: face.familyName,
                isBold: face.faceName.startsWith("bold"),
                isItalic: face.faceName.endsWith("italic"),
            };
        });
        this[_faceProps] = faces;
        // Sort the face props in canonical order so we can compare FontFiles for equivalent contents.
        this[_faceProps].sort((a, b) => a.familyName.localeCompare(b.familyName) || a.faceName.localeCompare(b.faceName) || 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[_key] = JSON.stringify(this[_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 FontType.TrueType; }
    get isEmbeddable() { return this.#embeddable; }
    [_getData]() {
        return fs.readFileSync(this.#fileName);
    }
}
/** Holds the binary representation of a SHX or RSC font in memory. */
export class CadFontFile extends FontFileImpl {
    #data;
    #type;
    constructor(data, type, faces) {
        super(faces);
        this.#data = data;
        this.#type = type;
    }
    get type() { return this.#type; }
    [_getData]() { return this.#data; }
}
/** Points to a font file in any format embedded in an iModel. */
export 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; }
    [_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;
    }
}
export 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, FontType.Shx, [{
            faceName: "regular",
            familyName: args.familyName,
            type: FontType.Shx,
        }]);
}
export function rscFontFileFromBlob(args) {
    if (args.familyName.length === 0) {
        throw new Error("Font family name cannot be empty");
    }
    if (!IModelNative.platform.isRscFontData(args.blob)) {
        throw new Error("Failed to read font file");
    }
    return new CadFontFile(args.blob, FontType.Rsc, [{
            faceName: "regular",
            familyName: args.familyName,
            type: FontType.Rsc,
            encoding: args.encoding,
        }]);
}
export function trueTypeFontFileFromFileName(fileName) {
    const metadata = 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