"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractFromRawStyle = exports._extractStyle = exports.extractStyle = exports.measureChildren = void 0;
const isFrameRelative_1 = require("../isFrameRelative");
const svg_1 = require("../util/svg");
const DEFAULT_FONT_SIZE_1 = require("./DEFAULT_FONT_SIZE");
const extractTrait_1 = require("./extractTrait");
const isTextLike_1 = require("./isTextLike");
const rawExtractStyle_1 = require("./rawExtractStyle");
const reflectComponentBaseTrait_1 = require("./reflectComponentBaseTrait");
const geometry_1 = require("./util/geometry");
const getFontSize_1 = require("./util/style/getFontSize");
function measureChildren(root, component, style, fallbackTrait, measureText, fitContent, getLeafStyle = (parent_trait, leaf_path, leaf_comp) => extractStyle(root, leaf_comp, parent_trait, measureText, fitContent)) {
    const { $system } = component;
    const { api: { layout: { reflectChildrenTrait }, }, } = $system;
    const parentChildren = component.$parentChildren;
    const base = parentChildren.reduce((acc, child) => {
        const childBase = child.getRootBase();
        let child_path = [];
        let c = child;
        let p = child.$parent;
        while (p) {
            let z = component;
            let drop = false;
            while (z) {
                if (c.getSubComponentId(component.$parent)) {
                    drop = true;
                    break;
                }
                z = z.$parent;
            }
            if (drop) {
                break;
            }
            const subComponentId = p.getSubComponentId(c);
            child_path.unshift(subComponentId);
            c = p;
            p = p.$parent;
        }
        return [
            ...acc,
            ...childBase.map(([leaf_path, leaf_comp]) => [
                [...child_path, ...leaf_path],
                leaf_comp,
            ]),
        ];
    }, []);
    const base_style = base.map(([leaf_path, leaf_comp]) => {
        return getLeafStyle(fallbackTrait, leaf_path, leaf_comp);
    });
    const relative_base_style = base_style.filter(({ position }) => {
        return position !== 'fixed' && position !== 'absolute';
    }, []);
    const trait = (0, extractTrait_1.extractTrait)(component, measureText);
    const reflected_children_trait = reflectChildrenTrait(trait, style, relative_base_style, [], (path) => {
        return (0, reflectComponentBaseTrait_1.expandSlot)(root, component, '', path, {}, (leaf_id, leaf_comp) => {
            return getLeafStyle(fallbackTrait, leaf_id.split('/'), leaf_comp);
        });
    });
    const size = (0, geometry_1.rectsBoundingRect)(reflected_children_trait);
    return size;
}
exports.measureChildren = measureChildren;
function extractStyle(root, component, fallbackTrait, measureText, fitContent = false, getLeafStyle = (parent_trait, leaf_path, leaf_comp) => extractStyle(root, leaf_comp, parent_trait, measureText, fitContent)) {
    const { $node } = component;
    return _extractStyle(root, component, $node, fallbackTrait, measureText, fitContent, getLeafStyle);
}
exports.extractStyle = extractStyle;
function _extractStyle(root, component, element, fallbackTrait, measureText, fitContent = false, getLeafStyle = (parent_trait, leaf_path, leaf_comp) => extractStyle(root, leaf_comp, parent_trait, measureText, fitContent)) {
    var _a;
    const style = (0, rawExtractStyle_1.rawExtractStyle)(element);
    const fitWidth = style['width'] === 'fit-content';
    const fitHeight = style['height'] === 'fit-content';
    if (element instanceof Text) {
        const fontSize = component.getFontSize();
        const { textContent } = component.$element;
        const { width, height } = measureText(textContent, fontSize);
        return {
            width: `${width}px`,
            height: `${height}px`,
        };
    }
    if (element instanceof HTMLDivElement &&
        element.getAttribute('contenteditable') === 'true' &&
        (fitWidth || fitHeight)) {
        const fontSize = component.getFontSize();
        const { textContent } = component.$element;
        const { width, height } = measureText(textContent, fontSize);
        if (fitWidth) {
            style['width'] = `${width}px`;
        }
        if (fitHeight) {
            style['height'] = `${height}px`;
        }
    }
    if (style['display'] === 'contents') {
        return {
            width: '100%',
            height: '100%',
        };
    }
    if (element instanceof HTMLCanvasElement) {
        const treatProp = (name) => {
            const prop = component.getProp(name);
            if (prop !== undefined) {
                if (typeof prop === 'string') {
                    if ((0, isFrameRelative_1.isFrameRelativeValue)(prop)) {
                        const prop_num = prop.substring(0, prop.length - 2);
                        style[name] = `${prop_num}%`;
                    }
                    else {
                        // TODO
                    }
                }
                else {
                    style[name] = `${prop}px`;
                }
            }
            else {
                style[name] = `${element[name]}px`;
            }
        };
        treatProp('width');
        treatProp('height');
    }
    if (element instanceof HTMLInputElement) {
        if (element.type === 'text' ||
            element.type === 'number' ||
            element.type === 'password') {
            if (style.height === 'fit-content') {
                const { value } = element;
                const fontSize = element.style.fontSize;
                const fontSizeNum = (_a = (0, getFontSize_1.parseFontSize)(fontSize)) !== null && _a !== void 0 ? _a : DEFAULT_FONT_SIZE_1.DEFAULT_FONT_SIZE;
                const { height } = measureText(value, fontSizeNum);
                style.height = `${height}px`;
            }
        }
        if (element.type === 'range') {
            style.height = '18px';
        }
    }
    else if (element instanceof HTMLSelectElement) {
        style.height = '18px';
    }
    if (element instanceof SVGPathElement) {
        const d = element.getAttribute('d');
        const bb = (0, svg_1.getPathBoundingBox)(d);
        style['width'] = `${bb.width}px`;
        style['height'] = `${bb.height}px`;
        // TODO
    }
    if (element instanceof SVGRectElement) {
        style['width'] = `${element.width.animVal.value}px`;
        style['height'] = `${element.height.animVal.value}px`;
        // TODO
    }
    if (element instanceof SVGCircleElement) {
        const r = element.r.animVal.value;
        const width = 2 * r;
        const height = width;
        style['width'] = `${width}px`;
        style['height'] = `${height}px`;
        // TODO
    }
    return style;
}
exports._extractStyle = _extractStyle;
function extractFromRawStyle(root, component, element, style, fallbackTrait, measureText, fitContent = false, getLeafStyle = (parent_trait, leaf_path, leaf_comp) => extractStyle(root, leaf_comp, parent_trait, measureText, fitContent)) {
    var _a;
    const fitWidth = style['width'] === 'fit-content';
    const fitHeight = style['height'] === 'fit-content';
    if (element instanceof Text) {
        const fontSize = component.getFontSize();
        const { textContent } = component.$element;
        const { width, height } = measureText(textContent, fontSize);
        return {
            width: `${width}px`,
            height: `${height}px`,
        };
    }
    if ((0, isTextLike_1.isContentEditable)(element) && (fitWidth || fitHeight)) {
        const fontSize = component.getFontSize();
        const { textContent } = component.$element;
        const { width, height } = measureText(textContent, fontSize);
        if (fitWidth) {
            style['width'] = `${width}px`;
        }
        if (fitHeight) {
            style['height'] = `${height}px`;
        }
    }
    if (style['display'] === 'contents') {
        return {
            width: '100%',
            height: '100%',
        };
    }
    if (element instanceof HTMLCanvasElement) {
        const treatProp = (name) => {
            const prop = component.getProp(name);
            if (prop !== undefined) {
                if (typeof prop === 'string') {
                    if ((0, isFrameRelative_1.isFrameRelativeValue)(prop)) {
                        const prop_num = prop.substring(0, prop.length - 2);
                        style[name] = `${prop_num}%`;
                    }
                    else {
                        // TODO
                    }
                }
                else {
                    style[name] = `${prop}px`;
                }
            }
            else {
                style[name] = `${element[name]}px`;
            }
        };
        treatProp('width');
        treatProp('height');
    }
    if (element instanceof HTMLInputElement) {
        if (element.type === 'text' ||
            element.type === 'number' ||
            element.type === 'password') {
            if (style.height === 'fit-content') {
                const { value } = element;
                const fontSize = element.style.fontSize;
                const fontSizeNum = (_a = (0, getFontSize_1.parseFontSize)(fontSize)) !== null && _a !== void 0 ? _a : DEFAULT_FONT_SIZE_1.DEFAULT_FONT_SIZE;
                const { height } = measureText(value, fontSizeNum);
                style.height = `${height}px`;
            }
        }
        if (element.type === 'range') {
            style.height = '18px';
        }
    }
    else if (element instanceof HTMLSelectElement) {
        style.height = '18px';
    }
    if (element instanceof SVGPathElement) {
        const d = element.getAttribute('d');
        const bb = (0, svg_1.getPathBoundingBox)(d);
        style['width'] = `${bb.width}px`;
        style['height'] = `${bb.height}px`;
        // TODO
    }
    if (element instanceof SVGRectElement) {
        style['width'] = `${element.width.animVal.value}px`;
        style['height'] = `${element.height.animVal.value}px`;
        // TODO
    }
    if (element instanceof SVGCircleElement) {
        const r = element.r.animVal.value;
        const width = 2 * r;
        const height = width;
        style['width'] = `${width}px`;
        style['height'] = `${height}px`;
        // TODO
    }
    if (fitContent) {
        if (fitWidth || fitHeight) {
            const { width, height } = measureChildren(root, component, style, fallbackTrait, measureText, fitContent, getLeafStyle);
            if (fitWidth) {
                style['width'] = `${width}px`;
            }
            if (fitHeight) {
                style['height'] = `${height}px`;
            }
        }
    }
    return style;
}
exports.extractFromRawStyle = extractFromRawStyle;
//# sourceMappingURL=extractStyle.js.map