import { makeObservable, observable, toJS } from "mobx";

import {
    ClassInfo,
    EezObject,
    IMessage,
    MessageType,
    PropertyType,
    registerClass,
    setKey
} from "project-editor/core/object";

import { humanize } from "eez-studio-shared/string";

import { ProjectEditor } from "project-editor/project-editor-interface";
import {
    EezValueObject,
    getAncestorOfType,
    Message
} from "project-editor/store";
import { findBitmap, findFont } from "project-editor/project/project";

import type { Page } from "project-editor/features/page/page";

import type { LVGLWidget } from "project-editor/lvgl/widgets";
import type { LVGLPageRuntime } from "project-editor/lvgl/page-runtime";
import type { LVGLBuild } from "project-editor/lvgl/build";
import { LVGL_STYLE_PROP_CODES } from "project-editor/lvgl/lvgl-constants";
import {
    BUILT_IN_FONTS,
    grid_column_dsc_array_property_info,
    grid_row_dsc_array_property_info,
    lvglPropertiesMap,
    LVGLPropertyInfo,
    text_font_property_info
} from "project-editor/lvgl/style-catalog";
import {
    getSelectorBuildCode,
    getSelectorCode
} from "project-editor/lvgl/style-helper";
import { ColorFormat } from "project-editor/features/style/color-format";
import type { LVGLStyle } from "./style";

////////////////////////////////////////////////////////////////////////////////

type Definition = {
    [part: string]: {
        [state: string]: {
            [prop: string]: any;
        };
    };
};

export class LVGLStylesDefinition extends EezObject {
    definition: Definition;

    static classInfo: ClassInfo = {
        properties: [
            {
                name: "definition",
                type: PropertyType.Any,
                visitProperty: (style: LVGLStylesDefinition) => {
                    const valueObjects: EezValueObject[] = [];

                    Object.keys(style.definition).forEach(part => {
                        Object.keys(style.definition[part]).forEach(state => {
                            Object.keys(style.definition[part][state]).forEach(
                                propertyName => {
                                    const propertyInfo =
                                        lvglPropertiesMap.get(propertyName);
                                    if (!propertyInfo) {
                                        return;
                                    }

                                    const valueObject = EezValueObject.create(
                                        style,
                                        propertyInfo,
                                        style.definition[part][state][
                                            propertyName
                                        ]
                                    );

                                    setKey(
                                        valueObject,
                                        `definition.${part}.${state}.${propertyName}`
                                    );

                                    valueObjects.push(valueObject);
                                }
                            );
                        });
                    });

                    return valueObjects;
                }
            }
        ],
        defaultValue: {},

        beforeLoadHook(object, jsObject) {
            if (jsObject.definition) {
                Object.keys(jsObject.definition).forEach(part => {
                    Object.keys(jsObject.definition[part]).forEach(state => {
                        Object.keys(jsObject.definition[part][state]).forEach(
                            propertyName => {
                                if (
                                    propertyName == "grid_column_align" ||
                                    propertyName == "grid_row_align" ||
                                    propertyName == "grid_cell_x_align" ||
                                    propertyName == "grid_cell_y_align"
                                ) {
                                    const value =
                                        jsObject.definition[part][state][
                                            propertyName
                                        ];
                                    if (
                                        value == "EVENLY" ||
                                        value == "AROUND" ||
                                        value == "BETWEEN"
                                    ) {
                                        jsObject.definition[part][state][
                                            propertyName
                                        ] = "SPACE_" + value;
                                    }
                                }
                            }
                        );
                    });
                });
            }
        }
    };

    override makeEditable() {
        super.makeEditable();

        makeObservable(this, {
            definition: observable
        });
    }

    getPropertyValue(
        propertyInfo: LVGLPropertyInfo,
        part: string,
        state: string
    ) {
        if (!this.definition) {
            return undefined;
        }

        const partStyles = this.definition[part];
        if (!partStyles) {
            return undefined;
        }

        const stateStyles = partStyles[state];
        if (!stateStyles) {
            return undefined;
        }

        return stateStyles[propertyInfo.name];
    }

    addPropertyToDefinition(
        propertyInfo: LVGLPropertyInfo,
        part: string,
        state: string,
        value: any
    ) {
        let def = this.definition;

        function add(
            def: Definition | undefined,
            propertyInfo: LVGLPropertyInfo,
            part: string,
            state: string,
            value: any
        ) {
            return {
                ...(def || {}),
                [part]: {
                    ...(def || {})[part],
                    [state]: {
                        ...((def || {})[part] || {})[state],
                        [propertyInfo.name]: value
                    }
                }
            };
        }

        if (propertyInfo.name == "layout" && value == "GRID") {
            if (
                def?.[part]?.[state]?.[grid_row_dsc_array_property_info.name] ==
                undefined
            ) {
                def = add(
                    def,
                    grid_row_dsc_array_property_info,
                    part,
                    state,
                    ""
                );
            }

            if (
                def?.[part]?.[state]?.[
                    grid_column_dsc_array_property_info.name
                ] == undefined
            ) {
                def = add(
                    def,
                    grid_column_dsc_array_property_info,
                    part,
                    state,
                    ""
                );
            }
        }

        return add(def, propertyInfo, part, state, value);
    }

    static combineDefinitions(
        definition1: Definition,
        definition2: Definition
    ) {
        let result = toJS(definition1);

        Object.keys(definition2).forEach(part => {
            Object.keys(definition2[part]).forEach(state => {
                Object.keys(definition2[part][state]).forEach(propertyName => {
                    result = {
                        ...(result || {}),
                        [part]: {
                            ...(result || {})[part],
                            [state]: {
                                ...((result || {})[part] || {})[state],
                                [propertyName]:
                                    definition2[part][state][propertyName]
                            }
                        }
                    };
                });
            });
        });

        return result;
    }

    static removePropertyFromDefinitionByName(
        definition: Definition | undefined,
        propertyName: string,
        part: string,
        state: string
    ) {
        let def = definition;
        let copy = {
            ...(def || {}),
            [part]: {
                ...(def || {})[part],
                [state]: {
                    ...((def || {})[part] || {})[state]
                }
            }
        };

        delete copy[part][state][propertyName];

        if (Object.keys(copy[part][state]).length == 0) {
            delete copy[part][state];
        }

        if (Object.keys(copy[part]).length == 0) {
            delete copy[part];
        }

        if (Object.keys(copy).length == 0) {
            return undefined;
        }

        return copy;
    }

    removePropertyFromDefinition(
        propertyInfo: LVGLPropertyInfo,
        part: string,
        state: string
    ) {
        return LVGLStylesDefinition.removePropertyFromDefinitionByName(
            this.definition,
            propertyInfo.name,
            part,
            state
        );
    }

    removeModifications(
        modifications: {
            part: string;
            state: string;
            propertyName: string;
        }[]
    ) {
        let newDefinition: Definition | undefined = this.definition;
        for (const modification of modifications) {
            newDefinition =
                LVGLStylesDefinition.removePropertyFromDefinitionByName(
                    newDefinition,
                    modification.propertyName,
                    modification.part,
                    modification.state
                );
        }
        return newDefinition;
    }

    check(messages: IMessage[]) {
        if (this.definition) {
            const projectStore = ProjectEditor.getProjectStore(this);

            Object.keys(this.definition).forEach(part => {
                Object.keys(this.definition[part]).forEach(state => {
                    Object.keys(this.definition[part][state]).forEach(
                        propertyName => {
                            const propertyInfo =
                                lvglPropertiesMap.get(propertyName);

                            if (!propertyInfo) {
                                return;
                            }

                            if (propertyInfo.type == PropertyType.ThemedColor) {
                                const color =
                                    this.definition[part][state][propertyName];

                                if (color) {
                                    if (!ColorFormat.isValid(color, projectStore.project)) {
                                        const valueObject =
                                            EezValueObject.create(
                                                this,
                                                propertyInfo,
                                                ["definition", part, state, propertyName]
                                            );

                                        setKey(
                                            valueObject,
                                            `definition.${part}.${state}.${propertyName}`
                                        );

                                        messages.push(
                                            new Message(
                                                MessageType.ERROR,
                                                `invalid color`,
                                                valueObject
                                            )
                                        );
                                    }
                                }
                            }

                            if (
                                propertyInfo.type ==
                                    PropertyType.ObjectReference &&
                                propertyInfo.referencedObjectCollectionPath ==
                                    "bitmaps"
                            ) {
                                const value =
                                    this.definition[part][state][propertyName];

                                const bitmap = findBitmap(
                                    ProjectEditor.getProject(this),
                                    value
                                );

                                if (!bitmap) {
                                    const valueObject = EezValueObject.create(
                                        this,
                                        propertyInfo,
                                        value
                                    );

                                    setKey(
                                        valueObject,
                                        `definition.${part}.${state}.${propertyName}`
                                    );

                                    messages.push(
                                        new Message(
                                            MessageType.ERROR,
                                            `Bitmap not found for style property ${part} - ${state} - ${
                                                propertyInfo.displayName ||
                                                humanize(propertyInfo.name)
                                            }`,
                                            valueObject
                                        )
                                    );
                                }
                            } else if (
                                propertyInfo.lvglStyleProp.code ==
                                LVGL_STYLE_PROP_CODES.LV_STYLE_TEXT_FONT
                            ) {
                                const value =
                                    this.definition[part][state][propertyName];

                                const font = findFont(
                                    ProjectEditor.getProject(this),
                                    value
                                );

                                if (
                                    !font &&
                                    BUILT_IN_FONTS.indexOf(value) == -1
                                ) {
                                    const valueObject = EezValueObject.create(
                                        this,
                                        propertyInfo,
                                        value
                                    );

                                    setKey(
                                        valueObject,
                                        `definition.${part}.${state}.${propertyName}`
                                    );

                                    messages.push(
                                        new Message(
                                            MessageType.ERROR,
                                            `Font not found for style property ${part} - ${state} - ${
                                                propertyInfo.displayName ||
                                                humanize(propertyInfo.name)
                                            }`,
                                            valueObject
                                        )
                                    );
                                }
                            }
                        }
                    );
                });
            });
        }
    }

    lvglCreate(
        runtime: LVGLPageRuntime,
        widget: LVGLWidget | Page,
        obj: number
    ) {
        if (!this.definition) {
            return;
        }

        const projectStore = ProjectEditor.getProjectStore(widget);
        const lvglVersion = projectStore.project.settings.general.lvglVersion;

        Object.keys(this.definition).forEach(part => {
            Object.keys(this.definition[part]).forEach(state => {
                const selectorCode = getSelectorCode(this, part, state);
                Object.keys(this.definition[part][state]).forEach(
                    propertyName => {
                        const propertyInfo =
                            lvglPropertiesMap.get(propertyName);
                        if (
                            !propertyInfo ||
                            propertyInfo.lvglStyleProp.code[lvglVersion] ==
                                undefined
                        ) {
                            return;
                        }

                        const value =
                            this.definition[part][state][propertyName];

                        if (propertyInfo.type == PropertyType.ThemedColor) {
                            runtime.lvglSetAndUpdateColor(
                                value,
                                (wasm, colorNum) => {
                                    wasm._lvglObjSetLocalStylePropColor(
                                        obj,
                                        runtime.getLvglStylePropCode(
                                            propertyInfo.lvglStyleProp.code
                                        ),
                                        colorNum,
                                        selectorCode
                                    );
                                }
                            );
                        } else if (
                            propertyInfo.type == PropertyType.Number ||
                            propertyInfo.type == PropertyType.Enum
                        ) {
                            if (propertyInfo == text_font_property_info) {
                                const index = BUILT_IN_FONTS.indexOf(value);
                                if (index != -1) {
                                    runtime.wasm._lvglObjSetLocalStylePropBuiltInFont(
                                        obj,
                                        runtime.getLvglStylePropCode(
                                            propertyInfo.lvglStyleProp.code
                                        ),
                                        index,
                                        selectorCode
                                    );
                                } else {
                                    const font = findFont(
                                        ProjectEditor.getProject(this),
                                        value
                                    );

                                    if (font) {
                                        const fontPtr =
                                            runtime.getFontPtr(font);
                                        if (fontPtr) {
                                            runtime.wasm._lvglObjSetLocalStylePropPtr(
                                                obj,
                                                runtime.getLvglStylePropCode(
                                                    propertyInfo.lvglStyleProp
                                                        .code
                                                ),
                                                fontPtr,
                                                selectorCode
                                            );
                                        }
                                    }
                                }
                            } else {
                                const numValue = propertyInfo.lvglStyleProp
                                    .valueToNum
                                    ? propertyInfo.lvglStyleProp.valueToNum(
                                          value,
                                          projectStore
                                      )
                                    : value;

                                runtime.wasm._lvglObjSetLocalStylePropNum(
                                    obj,
                                    runtime.getLvglStylePropCode(
                                        propertyInfo.lvglStyleProp.code
                                    ),
                                    numValue,
                                    selectorCode
                                );
                            }
                        } else if (
                            propertyInfo.type ==
                            PropertyType.NumberArrayAsString
                        ) {
                            const arrValue: number[] = propertyInfo
                                .lvglStyleProp.valueToNum
                                ? propertyInfo.lvglStyleProp.valueToNum(
                                      value,
                                      projectStore
                                  )
                                : value;

                            runtime.wasm._lvglObjSetLocalStylePropPtr(
                                obj,
                                runtime.getLvglStylePropCode(
                                    propertyInfo.lvglStyleProp.code
                                ),
                                propertyInfo.lvglStyleProp.isInt16Array &&
                                    propertyInfo.lvglStyleProp.isInt16Array(projectStore)
                                    ? runtime.allocateInt16Array(arrValue, true)
                                    : runtime.allocateInt32Array(
                                          arrValue,
                                          true
                                      ),
                                selectorCode
                            );
                        } else if (propertyInfo.type == PropertyType.Boolean) {
                            const numValue = value ? 1 : 0;

                            runtime.wasm._lvglObjSetLocalStylePropNum(
                                obj,
                                runtime.getLvglStylePropCode(
                                    propertyInfo.lvglStyleProp.code
                                ),
                                numValue,
                                selectorCode
                            );
                        } else if (
                            propertyInfo.type == PropertyType.ObjectReference &&
                            propertyInfo.referencedObjectCollectionPath ==
                                "bitmaps"
                        ) {
                            const bitmap = findBitmap(
                                ProjectEditor.getProject(this),
                                value
                            );
                            if (bitmap && bitmap.image) {
                                const bitmapPtr = runtime.getBitmapPtr(bitmap);
                                if (bitmapPtr) {
                                    runtime.wasm._lvglObjSetLocalStylePropPtr(
                                        obj,
                                        runtime.getLvglStylePropCode(
                                            propertyInfo.lvglStyleProp.code
                                        ),
                                        bitmapPtr,
                                        selectorCode
                                    );
                                }
                            }
                        } else if (propertyInfo.type == PropertyType.String) {
                            if (value) {
                                // For anim property
                                let { setDelay, setRepeatDelay, setRepeatCount, delay, repeatDelay, repeatCount } = extractAnimProperties(value);

                                if (setDelay || setRepeatDelay || setRepeatCount) {
                                    const animPtr = runtime.wasm._lvglCreateAnim(setDelay, delay, setRepeatDelay, repeatDelay, setRepeatCount, repeatCount);
                                    runtime.pointers.push(animPtr);
                                    runtime.wasm._lvglObjSetLocalStylePropPtr(
                                        obj,
                                        runtime.getLvglStylePropCode(
                                            propertyInfo.lvglStyleProp.code
                                        ),
                                        animPtr,
                                        selectorCode
                                    );
                                }
                            }
                        }
                    }
                );
            });
        });
    }

    lvglBuild(build: LVGLBuild) {
        if (!this.definition) {
            return;
        }

        Object.keys(this.definition).forEach(part => {
            Object.keys(this.definition[part]).forEach(state => {
                const selectorCode = getSelectorBuildCode(part, state);
                Object.keys(this.definition[part][state]).forEach(
                    propertyName => {
                        const propertyInfo =
                            lvglPropertiesMap.get(propertyName);
                        if (!propertyInfo) {
                            return;
                        }

                        const value =
                            this.definition[part][state][propertyName];

                        if (propertyInfo.type == PropertyType.ThemedColor) {
                            build.buildColor(
                                this,
                                this.definition[part][state][propertyName],
                                () => {
                                    return build.getLvglObjectAccessor(
                                        getAncestorOfType<LVGLWidget>(
                                            this,
                                            ProjectEditor.LVGLWidgetClass
                                                .classInfo
                                        )!
                                    );
                                },
                                (color: string) => {
                                    build.line(
                                        `lv_obj_set_style_${build.getStylePropName(
                                            propertyInfo.name
                                        )}(obj, ${color}, ${selectorCode});`
                                    );
                                },
                                (color: string, obj) => {
                                    if (
                                        build.project.settings.build
                                            .screensLifetimeSupport
                                    ) {
                                        build.line(
                                            `if (${obj}) lv_obj_set_style_${build.getStylePropName(
                                                propertyInfo.name
                                            )}(${obj}, ${color}, ${selectorCode});`
                                        );
                                    } else {
                                        build.line(
                                            `lv_obj_set_style_${build.getStylePropName(
                                                propertyInfo.name
                                            )}(${obj}, ${color}, ${selectorCode});`
                                        );
                                    }
                                }
                            );
                        } else if (
                            propertyInfo.type == PropertyType.Number ||
                            propertyInfo.type == PropertyType.Enum
                        ) {
                            if (propertyInfo == text_font_property_info) {
                                const index = BUILT_IN_FONTS.indexOf(value);
                                if (index != -1) {
                                    build.line(
                                        `lv_obj_set_style_${build.getStylePropName(
                                            propertyInfo.name
                                        )}(obj, &lv_font_${(
                                            value as string
                                        ).toLowerCase()}, ${selectorCode});`
                                    );
                                } else {
                                    const font = findFont(
                                        ProjectEditor.getProject(this),
                                        value
                                    );
                                    if (font) {
                                        build.line(
                                            `lv_obj_set_style_${build.getStylePropName(
                                                propertyInfo.name
                                            )}(obj, ${build.getFontAccessor(
                                                font
                                            )}, ${selectorCode});`
                                        );
                                    }
                                }
                            } else {
                                const numValue = propertyInfo.lvglStyleProp
                                    .valueBuild
                                    ? propertyInfo.lvglStyleProp.valueBuild(
                                          value
                                      )
                                    : value;

                                build.line(
                                    `lv_obj_set_style_${build.getStylePropName(
                                        propertyInfo.name
                                    )}(obj, ${numValue}, ${selectorCode});`
                                );
                            }
                        } else if (
                            propertyInfo.type ==
                            PropertyType.NumberArrayAsString
                        ) {
                            let dsc = propertyInfo.lvglStyleProp.valueBuild
                                ? propertyInfo.lvglStyleProp.valueBuild(value)
                                : "";

                            build.blockStart("{");
                            build.line(`static lv_coord_t dsc[] = {${dsc}};`);

                            build.line(
                                `lv_obj_set_style_${build.getStylePropName(
                                    propertyInfo.name
                                )}(obj, dsc, ${selectorCode});`
                            );

                            build.blockEnd("}");
                        } else if (propertyInfo.type == PropertyType.Boolean) {
                            const numValue = value ? "true" : "false";

                            build.line(
                                `lv_obj_set_style_${build.getStylePropName(
                                    propertyInfo.name
                                )}(obj, ${numValue}, ${selectorCode});`
                            );
                        } else if (
                            propertyInfo.type == PropertyType.ObjectReference &&
                            propertyInfo.referencedObjectCollectionPath ==
                                "bitmaps"
                        ) {
                            build.line(
                                `lv_obj_set_style_${build.getStylePropName(
                                    propertyInfo.name
                                )}(obj, ${build.getImageAccessor(
                                    value
                                )}, ${selectorCode});`
                            );
                        } else if (propertyInfo.type == PropertyType.String) {
                            if (value) {
                                // For anim property
                                let { setDelay, setRepeatDelay, setRepeatCount, delay, repeatDelay, repeatCount } = extractAnimProperties(value);

                                if (
                                    setDelay ||
                                    setRepeatDelay ||
                                    setRepeatCount
                                ) {
                                    build.line(
                                        `lv_obj_set_style_anim(obj, ${build.createAnimation(setDelay, setRepeatDelay, setRepeatCount, delay, repeatDelay, repeatCount)}, ${selectorCode});`
                                    );
                                }
                            }
                        }
                    }
                );
            });
        });
    }

    lvglBuildStyle(
        build: LVGLBuild,
        lvglStyle: LVGLStyle,
        part: string,
        state: string
    ) {
        Object.keys(this.definition?.[part]?.[state] ?? {}).forEach(
            propertyName => {
                const propertyInfo = lvglPropertiesMap.get(propertyName);
                if (!propertyInfo) {
                    return;
                }

                const value = this.definition[part][state][propertyName];

                if (propertyInfo.type == PropertyType.ThemedColor) {
                    build.buildColor(
                        this,
                        this.definition[part][state][propertyName],
                        () => {},
                        color => {
                            build.line(
                                `lv_style_set_${build.getStylePropName(
                                    propertyInfo.name
                                )}(style, ${color});`
                            );
                        },
                        color => {
                            build.line(
                                `lv_style_set_${build.getStylePropName(
                                    propertyInfo.name
                                )}(${build.getGetStyleFunctionName(
                                    lvglStyle,
                                    part,
                                    state
                                )}(), ${color});`
                            );

                            const lvglStyles = getChildStyles(lvglStyle, part, state, propertyName);
                            for (const childLvglStyle of lvglStyles) {
                                build.line(
                                    `lv_style_set_${build.getStylePropName(
                                        propertyInfo.name
                                    )}(${build.getGetStyleFunctionName(
                                        childLvglStyle,
                                        part,
                                        state
                                    )}(), ${color});`
                                );
                            }
                        }
                    );
                } else if (
                    propertyInfo.type == PropertyType.Number ||
                    propertyInfo.type == PropertyType.Enum
                ) {
                    if (propertyInfo == text_font_property_info) {
                        const index = BUILT_IN_FONTS.indexOf(value);
                        if (index != -1) {
                            build.line(
                                `lv_style_set_${build.getStylePropName(
                                    propertyInfo.name
                                )}(style, &lv_font_${(
                                    value as string
                                ).toLowerCase()});`
                            );
                        } else {
                            const font = findFont(
                                ProjectEditor.getProject(this),
                                value
                            );
                            if (font) {
                                build.line(
                                    `lv_style_set_${build.getStylePropName(
                                        propertyInfo.name
                                    )}(style, ${build.getFontAccessor(font)});`
                                );
                            }
                        }
                    } else {
                        const numValue = propertyInfo.lvglStyleProp.valueBuild
                            ? propertyInfo.lvglStyleProp.valueBuild(value)
                            : value;

                        build.line(
                            `lv_style_set_${build.getStylePropName(
                                propertyInfo.name
                            )}(style, ${numValue});`
                        );
                    }
                } else if (
                    propertyInfo.type == PropertyType.NumberArrayAsString
                ) {
                    let dsc = propertyInfo.lvglStyleProp.valueBuild
                        ? propertyInfo.lvglStyleProp.valueBuild(value)
                        : "";

                    build.blockStart("{");
                    build.line(`static lv_coord_t dsc[] = {${dsc}};`);

                    build.line(
                        `lv_style_set_${build.getStylePropName(
                            propertyInfo.name
                        )}(style, dsc);`
                    );

                    build.blockEnd("}");
                } else if (propertyInfo.type == PropertyType.Boolean) {
                    const numValue = value ? "true" : "false";

                    build.line(
                        `lv_style_set_${build.getStylePropName(
                            propertyInfo.name
                        )}(style, ${numValue});`
                    );
                } else if (
                    propertyInfo.type == PropertyType.ObjectReference &&
                    propertyInfo.referencedObjectCollectionPath == "bitmaps"
                ) {
                    build.line(
                        `lv_style_set_${build.getStylePropName(
                            propertyInfo.name
                        )}(style, ${build.getImageAccessor(value)});`
                    );
                } else if (propertyInfo.type == PropertyType.String) {
                    if (value) {
                        // For anim property
                        let { setDelay, setRepeatDelay, setRepeatCount, delay, repeatDelay, repeatCount } = extractAnimProperties(value);

                        if (
                            setDelay ||
                            setRepeatDelay ||
                            setRepeatCount
                        ) {
                            build.line(
                                `lv_style_set_anim(style, ${build.createAnimation(setDelay, setRepeatDelay, setRepeatCount, delay, repeatDelay, repeatCount)});`
                            );
                        }
                    }
                }
            }
        );
    }

    get hasModifications() {
        return this.definition && Object.keys(this.definition).length > 0;
    }

    resetAllModifications() {
        ProjectEditor.getProjectStore(this).updateObject(this, {
            definition: undefined
        });
    }
}

registerClass("LVGLStylesDefinition", LVGLStylesDefinition);


export function extractAnimProperties(value: any) {
    let setDelay = false;
    let delay = 0;

    let setRepeatDelay = false;
    let repeatDelay = 0;

    let setRepeatCount = false;
    let repeatCount = 0;

    const props = value.split(",");
    for (let i = 0; i < props.length; i++) {
        let [propName, propValueStr] = props[i].split("=");
        if (!propName) {
            continue;
        }
        propName = propName.trim();
        if (!propValueStr) {
            continue;
        }
        propValueStr = propValueStr.trim();
        if (propName == "delay") {
            let propValue = Number(propValueStr);
            if (Number.isInteger(propValue)) {
                setDelay = true;
                delay = propValue;
            }
        } else if (propName == "repeat_delay") {
            let propValue = Number(propValueStr);
            if (Number.isInteger(propValue)) {
                setRepeatDelay = true;
                repeatDelay = propValue;
            }
        } else if (propName == "repeat_count") {
            let propValue = Number(propValueStr);
            if (Number.isInteger(propValue)) {
                setRepeatCount = true;
                repeatCount = propValue;
            }
        }
    }
    return { setDelay, setRepeatDelay, setRepeatCount, delay, repeatDelay, repeatCount };
}

////////////////////////////////////////////////////////////////////////////////

function getChildStyles(lvglStyle: LVGLStyle, part: string, state: string, propertyName: string): LVGLStyle[] {
    const lvglStyles = [];

    for (const childLvglStyle of lvglStyle.childStyles) {
        if (childLvglStyle.definition.definition?.[part]?.[state]?.[propertyName] == undefined) {
            lvglStyles.push(childLvglStyle);
        }
    }

    for (const childLvglStyle of lvglStyle.childStyles) {
        lvglStyles.push(...getChildStyles(childLvglStyle, part, state, propertyName));
    }

    return lvglStyles;
}
