/** All valid namespaces in HTML. */
export enum NS {
    HTML = 'http://www.w3.org/1999/xhtml',
    MATHML = 'http://www.w3.org/1998/Math/MathML',
    SVG = 'http://www.w3.org/2000/svg',
    XLINK = 'http://www.w3.org/1999/xlink',
    XML = 'http://www.w3.org/XML/1998/namespace',
    XMLNS = 'http://www.w3.org/2000/xmlns/',
}

export enum ATTRS {
    TYPE = 'type',
    ACTION = 'action',
    ENCODING = 'encoding',
    PROMPT = 'prompt',
    NAME = 'name',
    COLOR = 'color',
    FACE = 'face',
    SIZE = 'size',
}

/**
 * The mode of the document.
 *
 * @see {@link https://dom.spec.whatwg.org/#concept-document-limited-quirks}
 */
export enum DOCUMENT_MODE {
    NO_QUIRKS = 'no-quirks',
    QUIRKS = 'quirks',
    LIMITED_QUIRKS = 'limited-quirks',
}

export enum TAG_NAMES {
    A = 'a',
    ADDRESS = 'address',
    ANNOTATION_XML = 'annotation-xml',
    APPLET = 'applet',
    AREA = 'area',
    ARTICLE = 'article',
    ASIDE = 'aside',

    B = 'b',
    BASE = 'base',
    BASEFONT = 'basefont',
    BGSOUND = 'bgsound',
    BIG = 'big',
    BLOCKQUOTE = 'blockquote',
    BODY = 'body',
    BR = 'br',
    BUTTON = 'button',

    CAPTION = 'caption',
    CENTER = 'center',
    CODE = 'code',
    COL = 'col',
    COLGROUP = 'colgroup',

    DD = 'dd',
    DESC = 'desc',
    DETAILS = 'details',
    DIALOG = 'dialog',
    DIR = 'dir',
    DIV = 'div',
    DL = 'dl',
    DT = 'dt',

    EM = 'em',
    EMBED = 'embed',

    FIELDSET = 'fieldset',
    FIGCAPTION = 'figcaption',
    FIGURE = 'figure',
    FONT = 'font',
    FOOTER = 'footer',
    FOREIGN_OBJECT = 'foreignObject',
    FORM = 'form',
    FRAME = 'frame',
    FRAMESET = 'frameset',

    H1 = 'h1',
    H2 = 'h2',
    H3 = 'h3',
    H4 = 'h4',
    H5 = 'h5',
    H6 = 'h6',
    HEAD = 'head',
    HEADER = 'header',
    HGROUP = 'hgroup',
    HR = 'hr',
    HTML = 'html',

    I = 'i',
    IMG = 'img',
    IMAGE = 'image',
    INPUT = 'input',
    IFRAME = 'iframe',

    KEYGEN = 'keygen',

    LABEL = 'label',
    LI = 'li',
    LINK = 'link',
    LISTING = 'listing',

    MAIN = 'main',
    MALIGNMARK = 'malignmark',
    MARQUEE = 'marquee',
    MATH = 'math',
    MENU = 'menu',
    META = 'meta',
    MGLYPH = 'mglyph',
    MI = 'mi',
    MO = 'mo',
    MN = 'mn',
    MS = 'ms',
    MTEXT = 'mtext',

    NAV = 'nav',
    NOBR = 'nobr',
    NOFRAMES = 'noframes',
    NOEMBED = 'noembed',
    NOSCRIPT = 'noscript',

    OBJECT = 'object',
    OL = 'ol',
    OPTGROUP = 'optgroup',
    OPTION = 'option',

    P = 'p',
    PARAM = 'param',
    PLAINTEXT = 'plaintext',
    PRE = 'pre',

    RB = 'rb',
    RP = 'rp',
    RT = 'rt',
    RTC = 'rtc',
    RUBY = 'ruby',

    S = 's',
    SCRIPT = 'script',
    SECTION = 'section',
    SELECT = 'select',
    SOURCE = 'source',
    SMALL = 'small',
    SPAN = 'span',
    STRIKE = 'strike',
    STRONG = 'strong',
    STYLE = 'style',
    SUB = 'sub',
    SUMMARY = 'summary',
    SUP = 'sup',

    TABLE = 'table',
    TBODY = 'tbody',
    TEMPLATE = 'template',
    TEXTAREA = 'textarea',
    TFOOT = 'tfoot',
    TD = 'td',
    TH = 'th',
    THEAD = 'thead',
    TITLE = 'title',
    TR = 'tr',
    TRACK = 'track',
    TT = 'tt',

    U = 'u',
    UL = 'ul',

    SVG = 'svg',

    VAR = 'var',

    WBR = 'wbr',

    XMP = 'xmp',
}

/**
 * Tag IDs are numeric IDs for known tag names.
 *
 * We use tag IDs to improve the performance of tag name comparisons.
 */
export enum TAG_ID {
    UNKNOWN,

    A,
    ADDRESS,
    ANNOTATION_XML,
    APPLET,
    AREA,
    ARTICLE,
    ASIDE,

    B,
    BASE,
    BASEFONT,
    BGSOUND,
    BIG,
    BLOCKQUOTE,
    BODY,
    BR,
    BUTTON,

    CAPTION,
    CENTER,
    CODE,
    COL,
    COLGROUP,

    DD,
    DESC,
    DETAILS,
    DIALOG,
    DIR,
    DIV,
    DL,
    DT,

    EM,
    EMBED,

    FIELDSET,
    FIGCAPTION,
    FIGURE,
    FONT,
    FOOTER,
    FOREIGN_OBJECT,
    FORM,
    FRAME,
    FRAMESET,

    H1,
    H2,
    H3,
    H4,
    H5,
    H6,
    HEAD,
    HEADER,
    HGROUP,
    HR,
    HTML,

    I,
    IMG,
    IMAGE,
    INPUT,
    IFRAME,

    KEYGEN,

    LABEL,
    LI,
    LINK,
    LISTING,

    MAIN,
    MALIGNMARK,
    MARQUEE,
    MATH,
    MENU,
    META,
    MGLYPH,
    MI,
    MO,
    MN,
    MS,
    MTEXT,

    NAV,
    NOBR,
    NOFRAMES,
    NOEMBED,
    NOSCRIPT,

    OBJECT,
    OL,
    OPTGROUP,
    OPTION,

    P,
    PARAM,
    PLAINTEXT,
    PRE,

    RB,
    RP,
    RT,
    RTC,
    RUBY,

    S,
    SCRIPT,
    SECTION,
    SELECT,
    SOURCE,
    SMALL,
    SPAN,
    STRIKE,
    STRONG,
    STYLE,
    SUB,
    SUMMARY,
    SUP,

    TABLE,
    TBODY,
    TEMPLATE,
    TEXTAREA,
    TFOOT,
    TD,
    TH,
    THEAD,
    TITLE,
    TR,
    TRACK,
    TT,

    U,
    UL,

    SVG,

    VAR,

    WBR,

    XMP,
}

const TAG_NAME_TO_ID = new Map<string, TAG_ID>([
    [TAG_NAMES.A, TAG_ID.A],
    [TAG_NAMES.ADDRESS, TAG_ID.ADDRESS],
    [TAG_NAMES.ANNOTATION_XML, TAG_ID.ANNOTATION_XML],
    [TAG_NAMES.APPLET, TAG_ID.APPLET],
    [TAG_NAMES.AREA, TAG_ID.AREA],
    [TAG_NAMES.ARTICLE, TAG_ID.ARTICLE],
    [TAG_NAMES.ASIDE, TAG_ID.ASIDE],
    [TAG_NAMES.B, TAG_ID.B],
    [TAG_NAMES.BASE, TAG_ID.BASE],
    [TAG_NAMES.BASEFONT, TAG_ID.BASEFONT],
    [TAG_NAMES.BGSOUND, TAG_ID.BGSOUND],
    [TAG_NAMES.BIG, TAG_ID.BIG],
    [TAG_NAMES.BLOCKQUOTE, TAG_ID.BLOCKQUOTE],
    [TAG_NAMES.BODY, TAG_ID.BODY],
    [TAG_NAMES.BR, TAG_ID.BR],
    [TAG_NAMES.BUTTON, TAG_ID.BUTTON],
    [TAG_NAMES.CAPTION, TAG_ID.CAPTION],
    [TAG_NAMES.CENTER, TAG_ID.CENTER],
    [TAG_NAMES.CODE, TAG_ID.CODE],
    [TAG_NAMES.COL, TAG_ID.COL],
    [TAG_NAMES.COLGROUP, TAG_ID.COLGROUP],
    [TAG_NAMES.DD, TAG_ID.DD],
    [TAG_NAMES.DESC, TAG_ID.DESC],
    [TAG_NAMES.DETAILS, TAG_ID.DETAILS],
    [TAG_NAMES.DIALOG, TAG_ID.DIALOG],
    [TAG_NAMES.DIR, TAG_ID.DIR],
    [TAG_NAMES.DIV, TAG_ID.DIV],
    [TAG_NAMES.DL, TAG_ID.DL],
    [TAG_NAMES.DT, TAG_ID.DT],
    [TAG_NAMES.EM, TAG_ID.EM],
    [TAG_NAMES.EMBED, TAG_ID.EMBED],
    [TAG_NAMES.FIELDSET, TAG_ID.FIELDSET],
    [TAG_NAMES.FIGCAPTION, TAG_ID.FIGCAPTION],
    [TAG_NAMES.FIGURE, TAG_ID.FIGURE],
    [TAG_NAMES.FONT, TAG_ID.FONT],
    [TAG_NAMES.FOOTER, TAG_ID.FOOTER],
    [TAG_NAMES.FOREIGN_OBJECT, TAG_ID.FOREIGN_OBJECT],
    [TAG_NAMES.FORM, TAG_ID.FORM],
    [TAG_NAMES.FRAME, TAG_ID.FRAME],
    [TAG_NAMES.FRAMESET, TAG_ID.FRAMESET],
    [TAG_NAMES.H1, TAG_ID.H1],
    [TAG_NAMES.H2, TAG_ID.H2],
    [TAG_NAMES.H3, TAG_ID.H3],
    [TAG_NAMES.H4, TAG_ID.H4],
    [TAG_NAMES.H5, TAG_ID.H5],
    [TAG_NAMES.H6, TAG_ID.H6],
    [TAG_NAMES.HEAD, TAG_ID.HEAD],
    [TAG_NAMES.HEADER, TAG_ID.HEADER],
    [TAG_NAMES.HGROUP, TAG_ID.HGROUP],
    [TAG_NAMES.HR, TAG_ID.HR],
    [TAG_NAMES.HTML, TAG_ID.HTML],
    [TAG_NAMES.I, TAG_ID.I],
    [TAG_NAMES.IMG, TAG_ID.IMG],
    [TAG_NAMES.IMAGE, TAG_ID.IMAGE],
    [TAG_NAMES.INPUT, TAG_ID.INPUT],
    [TAG_NAMES.IFRAME, TAG_ID.IFRAME],
    [TAG_NAMES.KEYGEN, TAG_ID.KEYGEN],
    [TAG_NAMES.LABEL, TAG_ID.LABEL],
    [TAG_NAMES.LI, TAG_ID.LI],
    [TAG_NAMES.LINK, TAG_ID.LINK],
    [TAG_NAMES.LISTING, TAG_ID.LISTING],
    [TAG_NAMES.MAIN, TAG_ID.MAIN],
    [TAG_NAMES.MALIGNMARK, TAG_ID.MALIGNMARK],
    [TAG_NAMES.MARQUEE, TAG_ID.MARQUEE],
    [TAG_NAMES.MATH, TAG_ID.MATH],
    [TAG_NAMES.MENU, TAG_ID.MENU],
    [TAG_NAMES.META, TAG_ID.META],
    [TAG_NAMES.MGLYPH, TAG_ID.MGLYPH],
    [TAG_NAMES.MI, TAG_ID.MI],
    [TAG_NAMES.MO, TAG_ID.MO],
    [TAG_NAMES.MN, TAG_ID.MN],
    [TAG_NAMES.MS, TAG_ID.MS],
    [TAG_NAMES.MTEXT, TAG_ID.MTEXT],
    [TAG_NAMES.NAV, TAG_ID.NAV],
    [TAG_NAMES.NOBR, TAG_ID.NOBR],
    [TAG_NAMES.NOFRAMES, TAG_ID.NOFRAMES],
    [TAG_NAMES.NOEMBED, TAG_ID.NOEMBED],
    [TAG_NAMES.NOSCRIPT, TAG_ID.NOSCRIPT],
    [TAG_NAMES.OBJECT, TAG_ID.OBJECT],
    [TAG_NAMES.OL, TAG_ID.OL],
    [TAG_NAMES.OPTGROUP, TAG_ID.OPTGROUP],
    [TAG_NAMES.OPTION, TAG_ID.OPTION],
    [TAG_NAMES.P, TAG_ID.P],
    [TAG_NAMES.PARAM, TAG_ID.PARAM],
    [TAG_NAMES.PLAINTEXT, TAG_ID.PLAINTEXT],
    [TAG_NAMES.PRE, TAG_ID.PRE],
    [TAG_NAMES.RB, TAG_ID.RB],
    [TAG_NAMES.RP, TAG_ID.RP],
    [TAG_NAMES.RT, TAG_ID.RT],
    [TAG_NAMES.RTC, TAG_ID.RTC],
    [TAG_NAMES.RUBY, TAG_ID.RUBY],
    [TAG_NAMES.S, TAG_ID.S],
    [TAG_NAMES.SCRIPT, TAG_ID.SCRIPT],
    [TAG_NAMES.SECTION, TAG_ID.SECTION],
    [TAG_NAMES.SELECT, TAG_ID.SELECT],
    [TAG_NAMES.SOURCE, TAG_ID.SOURCE],
    [TAG_NAMES.SMALL, TAG_ID.SMALL],
    [TAG_NAMES.SPAN, TAG_ID.SPAN],
    [TAG_NAMES.STRIKE, TAG_ID.STRIKE],
    [TAG_NAMES.STRONG, TAG_ID.STRONG],
    [TAG_NAMES.STYLE, TAG_ID.STYLE],
    [TAG_NAMES.SUB, TAG_ID.SUB],
    [TAG_NAMES.SUMMARY, TAG_ID.SUMMARY],
    [TAG_NAMES.SUP, TAG_ID.SUP],
    [TAG_NAMES.TABLE, TAG_ID.TABLE],
    [TAG_NAMES.TBODY, TAG_ID.TBODY],
    [TAG_NAMES.TEMPLATE, TAG_ID.TEMPLATE],
    [TAG_NAMES.TEXTAREA, TAG_ID.TEXTAREA],
    [TAG_NAMES.TFOOT, TAG_ID.TFOOT],
    [TAG_NAMES.TD, TAG_ID.TD],
    [TAG_NAMES.TH, TAG_ID.TH],
    [TAG_NAMES.THEAD, TAG_ID.THEAD],
    [TAG_NAMES.TITLE, TAG_ID.TITLE],
    [TAG_NAMES.TR, TAG_ID.TR],
    [TAG_NAMES.TRACK, TAG_ID.TRACK],
    [TAG_NAMES.TT, TAG_ID.TT],
    [TAG_NAMES.U, TAG_ID.U],
    [TAG_NAMES.UL, TAG_ID.UL],
    [TAG_NAMES.SVG, TAG_ID.SVG],
    [TAG_NAMES.VAR, TAG_ID.VAR],
    [TAG_NAMES.WBR, TAG_ID.WBR],
    [TAG_NAMES.XMP, TAG_ID.XMP],
]);

export function getTagID(tagName: string): TAG_ID {
    return TAG_NAME_TO_ID.get(tagName) ?? TAG_ID.UNKNOWN;
}

const $ = TAG_ID;

export const SPECIAL_ELEMENTS: Record<NS, Set<TAG_ID>> = {
    [NS.HTML]: new Set([
        $.ADDRESS,
        $.APPLET,
        $.AREA,
        $.ARTICLE,
        $.ASIDE,
        $.BASE,
        $.BASEFONT,
        $.BGSOUND,
        $.BLOCKQUOTE,
        $.BODY,
        $.BR,
        $.BUTTON,
        $.CAPTION,
        $.CENTER,
        $.COL,
        $.COLGROUP,
        $.DD,
        $.DETAILS,
        $.DIR,
        $.DIV,
        $.DL,
        $.DT,
        $.EMBED,
        $.FIELDSET,
        $.FIGCAPTION,
        $.FIGURE,
        $.FOOTER,
        $.FORM,
        $.FRAME,
        $.FRAMESET,
        $.H1,
        $.H2,
        $.H3,
        $.H4,
        $.H5,
        $.H6,
        $.HEAD,
        $.HEADER,
        $.HGROUP,
        $.HR,
        $.HTML,
        $.IFRAME,
        $.IMG,
        $.INPUT,
        $.LI,
        $.LINK,
        $.LISTING,
        $.MAIN,
        $.MARQUEE,
        $.MENU,
        $.META,
        $.NAV,
        $.NOEMBED,
        $.NOFRAMES,
        $.NOSCRIPT,
        $.OBJECT,
        $.OL,
        $.P,
        $.PARAM,
        $.PLAINTEXT,
        $.PRE,
        $.SCRIPT,
        $.SECTION,
        $.SELECT,
        $.SOURCE,
        $.STYLE,
        $.SUMMARY,
        $.TABLE,
        $.TBODY,
        $.TD,
        $.TEMPLATE,
        $.TEXTAREA,
        $.TFOOT,
        $.TH,
        $.THEAD,
        $.TITLE,
        $.TR,
        $.TRACK,
        $.UL,
        $.WBR,
        $.XMP,
    ]),
    [NS.MATHML]: new Set([$.MI, $.MO, $.MN, $.MS, $.MTEXT, $.ANNOTATION_XML]),
    [NS.SVG]: new Set([$.TITLE, $.FOREIGN_OBJECT, $.DESC]),
    [NS.XLINK]: new Set(),
    [NS.XML]: new Set(),
    [NS.XMLNS]: new Set(),
};

export function isNumberedHeader(tn: TAG_ID): boolean {
    return tn === $.H1 || tn === $.H2 || tn === $.H3 || tn === $.H4 || tn === $.H5 || tn === $.H6;
}

const UNESCAPED_TEXT = new Set<string>([
    TAG_NAMES.STYLE,
    TAG_NAMES.SCRIPT,
    TAG_NAMES.XMP,
    TAG_NAMES.IFRAME,
    TAG_NAMES.NOEMBED,
    TAG_NAMES.NOFRAMES,
    TAG_NAMES.PLAINTEXT,
]);

export function hasUnescapedText(tn: string, scriptingEnabled: boolean): boolean {
    return UNESCAPED_TEXT.has(tn) || (scriptingEnabled && tn === TAG_NAMES.NOSCRIPT);
}
