import { NormalizedStyle, TextContent, NormalizedTextContent, NormalizedHighlight } from 'modern-idoc';
import { BoundingBox, Path2DDrawStyle, Path2D, Vector2, VectorLike, Path2DSet, Matrix3 } from 'modern-path2d';
import { Fonts, SFNT } from 'modern-font';

declare function parseColor(ctx: CanvasRenderingContext2D, source: string | CanvasGradient | CanvasPattern, box: BoundingBox): string | CanvasGradient | CanvasPattern;
declare function uploadColor(style: Partial<NormalizedStyle>, box: BoundingBox, ctx: CanvasRenderingContext2D): void;
interface LinearGradient {
    x0: number;
    y0: number;
    x1: number;
    y1: number;
    stops: {
        offset: number;
        color: string;
    }[];
}

interface DrawShapePathsOptions extends Partial<NormalizedStyle>, Omit<Partial<Path2DDrawStyle>, 'fill' | 'outline'> {
    ctx: CanvasRenderingContext2D;
    path: Path2D;
    fontSize: number;
    clipRect?: BoundingBox;
}
declare function drawPath(options: DrawShapePathsOptions): void;

declare function setupView(ctx: CanvasRenderingContext2D, pixelRatio: number, boundingBox: BoundingBox): void;

declare class Fragment {
    content: string;
    style: Partial<NormalizedStyle>;
    parent: Paragraph;
    inlineBox: BoundingBox;
    characters: Character[];
    computedStyle: NormalizedStyle;
    get computedContent(): string;
    constructor(content: string, style: Partial<NormalizedStyle> | undefined, parent: Paragraph);
    updateComputedStyle(): this;
    initCharacters(): this;
}

declare class Character {
    content: string;
    index: number;
    parent: Fragment;
    path: Path2D;
    lineBox: BoundingBox;
    inlineBox: BoundingBox;
    glyphBox?: BoundingBox;
    advanceWidth: number;
    advanceHeight: number;
    underlinePosition: number;
    underlineThickness: number;
    strikeoutPosition: number;
    strikeoutSize: number;
    ascender: number;
    descender: number;
    typoAscender: number;
    typoDescender: number;
    typoLineGap: number;
    winAscent: number;
    winDescent: number;
    xHeight: number;
    capHeight: number;
    baseline: number;
    centerDiviation: number;
    fontStyle?: 'bold' | 'italic';
    get compatibleGlyphBox(): BoundingBox;
    get center(): Vector2;
    get computedStyle(): NormalizedStyle;
    get isVertical(): boolean;
    get fontSize(): number;
    get fontHeight(): number;
    constructor(content: string, index: number, parent: Fragment);
    protected _getFontSFNT(fonts?: Fonts): SFNT | undefined;
    updateGlyph(sfnt?: SFNT | undefined): this;
    update(fonts?: Fonts): this;
    protected _italic(path: Path2D, startPoint?: VectorLike): void;
    getGlyphMinMax(min?: Vector2, max?: Vector2, withStyle?: boolean): {
        min: Vector2;
        max: Vector2;
    } | undefined;
    getGlyphBoundingBox(withStyle?: boolean): BoundingBox | undefined;
    drawTo(ctx: CanvasRenderingContext2D, config?: Partial<NormalizedStyle>): void;
}

declare class Paragraph {
    style: Partial<NormalizedStyle>;
    parentStyle: NormalizedStyle;
    lineBox: BoundingBox;
    fragments: Fragment[];
    computedStyle: NormalizedStyle;
    constructor(style: Partial<NormalizedStyle>, parentStyle: NormalizedStyle);
    updateComputedStyle(): this;
    addFragment(content: string, style?: Partial<NormalizedStyle>): Fragment;
}

interface TextPlugin {
    name: string;
    pathSet?: Path2DSet;
    getBoundingBox?: (text: Text$1) => BoundingBox | undefined;
    update?: (text: Text$1) => void;
    updateOrder?: number;
    render?: (ctx: CanvasRenderingContext2D, text: Text$1) => void;
    renderOrder?: number;
    load?: (text: Text$1) => Promise<void>;
}
interface TextOptions {
    debug?: boolean;
    style?: Partial<NormalizedStyle>;
    content?: TextContent;
    effects?: Partial<NormalizedStyle>[];
    measureDOM?: HTMLElement;
    fonts?: Fonts;
    plugins?: TextPlugin[];
}

type EventListenerValue<T = any> = (ev: T) => void;
type EventListenerOptions = boolean | AddEventListenerOptions;
interface EventListener<T = any> {
    value: EventListenerValue<T>;
    options?: EventListenerOptions;
}
declare class EventEmitter<T extends Record<string, any> = Record<string, any>> {
    eventListeners: Map<keyof T, EventListener<any> | EventListener<any>[]>;
    addEventListener<K extends keyof T>(event: K, listener: EventListenerValue<T[K]>, options?: EventListenerOptions): this;
    removeEventListener<K extends keyof T>(event: K, listener: EventListenerValue<T[K]>, options?: EventListenerOptions): this;
    removeAllListeners(): this;
    hasEventListener(event: string): boolean;
    dispatchEvent<K extends keyof T>(event: K, arg: T[K]): boolean;
    on<K extends keyof T>(event: K, listener: EventListenerValue<T[K]>, options?: EventListenerOptions): this;
    once<K extends keyof T>(event: K, listener: EventListenerValue<T[K]>): this;
    off<K extends keyof T>(event: K, listener: EventListenerValue<T[K]>, options?: EventListenerOptions): this;
    emit<K extends keyof T>(event: K, arg: T[K]): void;
}

interface MeasuredParagraph {
    paragraphIndex: number;
    left: number;
    top: number;
    width: number;
    height: number;
}
interface MeasuredFragment {
    paragraphIndex: number;
    fragmentIndex: number;
    left: number;
    top: number;
    width: number;
    height: number;
}
interface MeasuredCharacter {
    paragraphIndex: number;
    fragmentIndex: number;
    characterIndex: number;
    newParagraphIndex: number;
    content: string;
    left: number;
    top: number;
    width: number;
    height: number;
    textHeight: number;
    textWidth: number;
}
interface measureDOMResult {
    paragraphs: Paragraph[];
    boundingBox: BoundingBox;
}
declare class Measurer {
    static notZeroStyles: Set<string>;
    static pxStyles: Set<string>;
    protected _toDOMStyle(style: Record<string, any>): Record<string, any>;
    /**
     * <section style="...">
     *   <ul>
     *     <li style="...">
     *       <span style="...">...</span>
     *       <span>...</span>
     *     </li>
     *   </ul>
     * </section>
     */
    createDOM(paragraphs: Paragraph[], rootStyle: NormalizedStyle): HTMLElement;
    measureDOMText(text: Text): {
        content: string;
        top: number;
        left: number;
        width: number;
        height: number;
    }[];
    measureDOM(dom: HTMLElement): {
        paragraphs: MeasuredParagraph[];
        fragments: MeasuredFragment[];
        characters: MeasuredCharacter[];
    };
    measureParagraphDOM(paragraphs: Paragraph[], dom: HTMLElement): measureDOMResult;
    measure(paragraphs: Paragraph[], rootStyle: NormalizedStyle, dom?: HTMLElement): measureDOMResult;
}

interface TextRenderOptions {
    view: HTMLCanvasElement;
    pixelRatio?: number;
    onContext?: (context: CanvasRenderingContext2D) => void;
}
interface MeasureResult {
    paragraphs: Paragraph[];
    lineBox: BoundingBox;
    rawGlyphBox: BoundingBox;
    glyphBox: BoundingBox;
    pathBox: BoundingBox;
    boundingBox: BoundingBox;
}
declare const textDefaultStyle: NormalizedStyle;
interface TextEventMap {
    update: {
        text: Text$1;
    };
    measure: {
        text: Text$1;
        result: MeasureResult;
    };
    render: {
        text: Text$1;
        view: HTMLCanvasElement;
        pixelRatio: number;
    };
}
declare class Text$1 extends EventEmitter<TextEventMap> {
    debug: boolean;
    content: NormalizedTextContent;
    style: Partial<NormalizedStyle>;
    effects?: Partial<NormalizedStyle>[];
    measureDOM?: HTMLElement;
    needsUpdate: boolean;
    computedStyle: NormalizedStyle;
    paragraphs: Paragraph[];
    lineBox: BoundingBox;
    rawGlyphBox: BoundingBox;
    glyphBox: BoundingBox;
    pathBox: BoundingBox;
    boundingBox: BoundingBox;
    measurer: Measurer;
    plugins: Map<string, TextPlugin>;
    fonts?: Fonts;
    get fontSize(): number;
    get isVertical(): boolean;
    get characters(): Character[];
    constructor(options?: TextOptions);
    set(options?: TextOptions): void;
    use(plugin: TextPlugin): this;
    forEachCharacter(handle: (character: Character, ctx: {
        paragraphIndex: number;
        fragmentIndex: number;
        characterIndex: number;
    }) => void): this;
    load(): Promise<void>;
    updateParagraphs(): this;
    createDOM(): HTMLElement;
    measure(dom?: HTMLElement | undefined): MeasureResult;
    getGlyphBox(): BoundingBox;
    updatePathBox(): this;
    updateBoundingBox(): this;
    requestUpdate(): this;
    update(dom?: HTMLElement | undefined): this;
    render(options: TextRenderOptions): void;
    toString(): string;
}

declare function uploadColors(ctx: CanvasRenderingContext2D, text: Text$1): void;

declare function definePlugin(options: TextPlugin): TextPlugin;

declare function measureText(options: TextOptions, load: true): Promise<MeasureResult>;
declare function measureText(options: TextOptions): MeasureResult;

type RenderTextOptions = TextOptions & TextRenderOptions;
declare function renderText(options: RenderTextOptions, load: true): Promise<void>;
declare function renderText(options: RenderTextOptions): void;

declare function background(): TextPlugin;

declare function getHighlightStyle(style: NormalizedStyle): NormalizedHighlight;
declare function highlight(): TextPlugin;

declare function listStyle(): TextPlugin;

declare function outline(): TextPlugin;

declare function render(): TextPlugin;
declare function getTransform2D(text: Text$1, style: Partial<NormalizedStyle>): Matrix3;

declare function textDecoration(): TextPlugin;

interface SVGLoader {
    loaded: Map<string, string>;
    needsLoad: (source: string) => boolean;
    load: (svg: string) => Promise<void>;
}
declare function createSVGLoader(): SVGLoader;

interface SVGParser {
    parsed: Map<string, {
        dom: SVGElement;
        pathSet: Path2DSet;
    }>;
    parse: (svg: string) => {
        dom: SVGElement;
        pathSet: Path2DSet;
    };
}
declare function createSVGParser(loader: SVGLoader): SVGParser;

interface ValueContext {
    total: number;
    fontSize: number;
}
declare function parseValueNumber(value: string | number, ctx: ValueContext): number;
declare function parseColormap(colormap: 'none' | Record<string, string>): Record<string, string>;
declare function isEqualObject(obj1: Record<string, any>, obj2: Record<string, any>): boolean;
declare function isEqualValue(val1: any, val2: any): boolean;
declare function hexToRgb(hex: string): string | null;
declare function filterEmpty(val: Record<string, any> | undefined): Record<string, any> | undefined;

interface SelectableCharacter {
    color: string;
    left: number;
    top: number;
    width: number;
    height: number;
    content: string;
    isFirst?: boolean;
    isLast?: boolean;
    isLastSelected?: boolean;
    isCrlf?: boolean;
}
declare class TextEditor extends HTMLElement {
    static observedAttributes: string[];
    static register(): void;
    left: number;
    top: number;
    width: number;
    height: number;
    pixelRatio: number;
    text: Text$1;
    composition: boolean;
    selection: number[];
    prevSelection: number[];
    protected _oldText: string;
    $preview: HTMLCanvasElement;
    $textInput: HTMLTextAreaElement;
    $cursor: HTMLElement;
    $cursorInput: HTMLElement;
    get selectionMinMax(): {
        min: number;
        max: number;
    };
    get selectedCharacters(): SelectableCharacter[];
    get selectableCharacters(): SelectableCharacter[];
    get cursorPosition(): {
        left: number;
        top: number;
        width: number;
        height: number;
        color: string;
    };
    constructor();
    update(options: TextOptions): void;
    getTextValue(): string;
    getContentValue(content: NormalizedTextContent, newString?: string, oldString?: string): NormalizedTextContent;
    setTextInput(newText: string): void;
    onInput(): void;
    protected _timer?: any;
    onKeydown(e: KeyboardEvent): void;
    onFocus(e: Event): void;
    onBlur(): void;
    findNearest(options: {
        x: number;
        y: number;
        xWeight?: number;
        yWeight?: number;
    }): number;
    updateSelection(): void;
    updateDOMSelection(): void;
    onMousedown(e: MouseEvent): void;
    render(): void;
    attributeChangedCallback(name: string, oldValue: any, newValue: any): void;
}

export { Character, Fragment, Measurer, Paragraph, Text$1 as Text, TextEditor, background, createSVGLoader, createSVGParser, definePlugin, drawPath, filterEmpty, getHighlightStyle, getTransform2D, hexToRgb, highlight, isEqualObject, isEqualValue, listStyle, measureText, outline, parseColor, parseColormap, parseValueNumber, render, renderText, setupView, textDecoration, textDefaultStyle, uploadColor, uploadColors };
export type { DrawShapePathsOptions, LinearGradient, MeasureResult, MeasuredCharacter, MeasuredFragment, MeasuredParagraph, RenderTextOptions, SVGLoader, SVGParser, SelectableCharacter, TextEventMap, TextOptions, TextPlugin, TextRenderOptions, measureDOMResult };
