"use strict";
/*
 * Tencent is pleased to support the open source community by making
 * Hippy available.
 *
 * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.CssDomainAdapter = exports.cssMiddleWareManager = void 0;
const tslib_1 = require("tslib");
const color_normalize_1 = tslib_1.__importDefault(require("color-normalize"));
const enum_chrome_mapping_1 = require("@hippy/devtools-protocol/dist/types/enum-chrome-mapping");
exports.cssMiddleWareManager = {
    downwardMiddleWareListMap: {
        [enum_chrome_mapping_1.ChromeCommand.CSSGetMatchedStylesForNode]: ({ msg, sendToDevtools }) => {
            // narrow down type
            const commandRes = msg;
            commandRes.result.inlineStyle = CssDomainAdapter.conversionInlineStyle(commandRes.result.inlineStyle);
            return sendToDevtools(commandRes);
        },
        [enum_chrome_mapping_1.ChromeCommand.CSSGetComputedStyleForNode]: ({ msg, sendToDevtools }) => {
            const commandRes = msg;
            commandRes.result.computedStyle = CssDomainAdapter.conversionComputedStyle(commandRes.result.computedStyle);
            return sendToDevtools(commandRes);
        },
        [enum_chrome_mapping_1.ChromeCommand.CSSSetStyleTexts]: ({ msg, sendToDevtools }) => {
            const commandRes = msg;
            commandRes.result.styles = commandRes.result.styles.map((style) => CssDomainAdapter.conversionInlineStyle(style));
            return sendToDevtools(commandRes);
        },
    },
    upwardMiddleWareListMap: {
        [enum_chrome_mapping_1.ChromeCommand.CSSSetStyleTexts]: ({ msg, sendToApp }) => {
            const req = msg;
            req.params.edits = req.params.edits.map((data) => {
                const textList = data.text
                    .trim()
                    .split(';')
                    .reduce((ret, styleItem) => {
                    if (!styleItem.trim())
                        return ret;
                    const styleItems = styleItem.split(':');
                    const [name] = styleItems;
                    let [, ...values] = styleItems;
                    if (!CssDomainAdapter.shouldSkipStyle(name)) {
                        values[0] = values[0].trim();
                        if (name.toLowerCase().includes('color') && !/^\d+$/.test(values[0])) {
                            const rgba = CssDomainAdapter.transformRGBA(values[0]);
                            values = [String(CssDomainAdapter.rgbaToInt(rgba))];
                        }
                        ret.push(`${name}: ${values.join(':').trim()}`);
                    }
                    return ret;
                }, []);
                const totalCSSText = textList.join(';');
                return {
                    ...data,
                    range: {
                        ...data.range,
                        endColumn: totalCSSText.length,
                    },
                    text: totalCSSText,
                };
            });
            return sendToApp(req);
        },
    },
};
class CssDomainAdapter {
    static intToRGBA(int32Color) {
        const int = int32Color << 0;
        // Converts 0xaarrggbb into 0xrrggbbaa
        const int32 = ((int << 8) | (int >>> 24)) >>> 0;
        const int8 = new Uint8Array(new Uint32Array([int32]).buffer).reverse();
        const r = int8[0];
        const g = int8[1];
        const b = int8[2];
        const a = Math.round((int8[3] / 255) * 100) / 100;
        return `rgba(${r}, ${g}, ${b}, ${a})`;
    }
    static rgbaToInt(stringColor) {
        const uint8 = (0, color_normalize_1.default)(stringColor, 'uint8');
        const int = Buffer.from(uint8).readUInt32BE(0);
        // Converts 0xrrggbbaa into 0xaarrggbb
        return ((int << 24) | (int >>> 8)) >>> 0;
    }
    static shouldSkipStyle(styleName) {
        return CssDomainAdapter.skipStyleList.some((name) => name.toString().trim().toLowerCase() === styleName.toString().trim().toLowerCase());
    }
    static conversionInlineStyle(style) {
        if (!style)
            return {};
        let totalCSSText = '';
        style.cssProperties = (style.cssProperties || []).reduce((ret, item) => {
            if (CssDomainAdapter.shouldSkipStyle(item.name))
                return ret;
            const cssText = `${item.name}: ${item.value}`;
            if (item.name.toLowerCase().includes('color')) {
                item.value = CssDomainAdapter.intToRGBA(parseInt(item.value, 10));
            }
            item.range = {
                ...item.range,
                startColumn: totalCSSText.length,
                endColumn: totalCSSText.length + cssText.length + 1,
            };
            totalCSSText += `${cssText}; `;
            ret.push(item);
            return ret;
        }, []);
        style.cssText = totalCSSText;
        style.range = {
            ...style.range,
            endColumn: totalCSSText.length,
        };
        return style;
    }
    static conversionComputedStyle(style) {
        if (!style)
            return [];
        return style.reduce((ret, item) => {
            if (!CssDomainAdapter.shouldSkipStyle(item.name)) {
                if (item.name.toLowerCase().includes('color')) {
                    item.value = CssDomainAdapter.intToRGBA(parseInt(item.value, 10));
                }
                ret.push(item);
            }
            return ret;
        }, []);
    }
    /**
     * input:
     *   rgb(165 21 21)
     *   rgb(183 12 12 / 95%)
     *   rgb(100% 0% 0% / 50%)
     *   rgba(0 0 255 / 50%)
     *   rgba(2, 0, 0, 0)
     *   rgba(100%, 0%, 0%, 50%)
     *
     * output: rgba(r, g, b, a)
     *         r, g, b, a are int number
     */
    static transformRGBA(colorText) {
        return colorText.trim().replace(/^rgba?\(([^()]+)\)$/i, (s, p1) => {
            let r;
            let g;
            let b;
            let a;
            if (p1.includes('/')) {
                const [rgb, alpha] = p1.split(/\s*\/\s*/);
                a = alpha;
                [r, g, b] = rgb.split(' ');
            }
            else {
                const spliter = p1.includes(',') ? ',' : ' ';
                [r, g, b, a] = p1.split(spliter);
            }
            a || (a = '1');
            [r, g, b] = [r, g, b].map((value) => {
                if (value.toString().includes('%')) {
                    return Math.floor((parseInt(value, 10) / 100) * 255).toString();
                }
                return value.trim();
            });
            if (a.toString().includes('%')) {
                a = (parseInt(a, 10) / 100).toString();
            }
            else {
                a = a.trim();
            }
            return `rgba(${r}, ${g}, ${b}, ${a})`;
        });
    }
}
exports.CssDomainAdapter = CssDomainAdapter;
CssDomainAdapter.skipStyleList = ['backgroundImage', 'transform', 'shadowOffset'];
