/**
 * DevExtreme (cjs/__internal/viz/core/m_base_widget.js)
 * Version: 23.2.6 (build 24140-0112)
 * Build date: Sun May 19 2024
 *
 * Copyright (c) 2012 - 2024 Developer Express Inc. ALL RIGHTS RESERVED
 * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
 */
"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.default = void 0;
var _devices = _interopRequireDefault(require("../../../core/devices"));
var _dom_adapter = _interopRequireDefault(require("../../../core/dom_adapter"));
var _dom_component = _interopRequireDefault(require("../../../core/dom_component"));
var _renderer = _interopRequireDefault(require("../../../core/renderer"));
var _common = require("../../../core/utils/common");
var _deferred = require("../../../core/utils/deferred");
var _extend = require("../../../core/utils/extend");
var _iterator = require("../../../core/utils/iterator");
var _size = require("../../../core/utils/size");
var _type = require("../../../core/utils/type");
var _window = require("../../../core/utils/window");
var _events_engine = _interopRequireDefault(require("../../../events/core/events_engine"));
var _base_theme_manager = require("../../../viz/core/base_theme_manager");
var _base_widget = require("../../../viz/core/base_widget.utils");
var _errors_warnings = _interopRequireDefault(require("../../../viz/core/errors_warnings"));
var _helpers = require("../../../viz/core/helpers");
var _layout = _interopRequireDefault(require("../../../viz/core/layout"));
var _renderer2 = require("../../../viz/core/renderers/renderer");
var _utils = require("../../../viz/core/utils");
var _utils2 = require("../../../viz/utils");
var _m_charts = _interopRequireDefault(require("../../common/m_charts"));

function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    }
}
const {
    log: log
} = _errors_warnings.default;
const OPTION_RTL_ENABLED = "rtlEnabled";
const SIZED_ELEMENT_CLASS = "dx-sized-element";
const baseOptionMethod = _dom_component.default.prototype.option;

function getTrue() {
    return true
}

function getFalse() {
    return false
}

function defaultOnIncidentOccurred(e) {
    if (!e.component._eventsStrategy.hasEvent("incidentOccurred")) {
        log.apply(null, [e.target.id].concat(e.target.args || []))
    }
}

function pickPositiveValue(values) {
    return values.reduce((result, value) => value > 0 && !result ? value : result, 0)
}
const getEmptyComponent = function() {
    const emptyComponentConfig = {
        _initTemplates() {},
        ctor(element, options) {
            this.callBase(element, options);
            const sizedElement = _dom_adapter.default.createElement("div");
            const width = options && (0, _type.isNumeric)(options.width) ? "".concat(options.width, "px") : "100%";
            const height = options && (0, _type.isNumeric)(options.height) ? "".concat(options.height, "px") : "".concat(this._getDefaultSize().height, "px");
            _dom_adapter.default.setStyle(sizedElement, "width", width);
            _dom_adapter.default.setStyle(sizedElement, "height", height);
            _dom_adapter.default.setClass(sizedElement, "dx-sized-element", false);
            _dom_adapter.default.insertElement(element, sizedElement)
        }
    };
    const EmptyComponent = _dom_component.default.inherit(emptyComponentConfig);
    const originalInherit = EmptyComponent.inherit;
    EmptyComponent.inherit = function(config) {
        Object.keys(config).forEach(field => {
            if ((0, _type.isFunction)(config[field]) && "_" !== field.substr(0, 1) && "option" !== field || "_dispose" === field || "_optionChanged" === field) {
                config[field] = _common.noop
            }
        });
        return originalInherit.call(this, config)
    };
    return EmptyComponent
};

function callForEach(functions) {
    functions.forEach(c => c())
}
const isServerSide = !(0, _window.hasWindow)();

function sizeIsValid(value) {
    return (0, _type.isDefined)(value) && value > 0
}
const baseWidget = isServerSide ? getEmptyComponent() : _dom_component.default.inherit({
    _eventsMap: {
        onIncidentOccurred: {
            name: "incidentOccurred",
            actionSettings: {
                excludeValidators: ["disabled"]
            }
        },
        onDrawn: {
            name: "drawn",
            actionSettings: {
                excludeValidators: ["disabled"]
            }
        }
    },
    _getDefaultOptions() {
        return (0, _extend.extend)(this.callBase(), {
            onIncidentOccurred: defaultOnIncidentOccurred
        })
    },
    _useLinks: true,
    _init() {
        this._$element.children(".".concat("dx-sized-element")).remove();
        this._graphicObjects = {};
        this.callBase(...arguments);
        this._changesLocker = 0;
        this._optionChangedLocker = 0;
        this._asyncFirstDrawing = true;
        this._changes = (0, _helpers.changes)();
        this._suspendChanges();
        this._themeManager = this._createThemeManager();
        this._themeManager.setCallback(() => {
            this._requestChange(this._themeDependentChanges)
        });
        this._renderElementAttributes();
        this._initRenderer();
        const useLinks = this._useLinks;
        if (useLinks) {
            this._renderer.root.enableLinks().virtualLink("core").virtualLink("peripheral")
        }
        this._renderVisibilityChange();
        this._attachVisibilityChangeHandlers();
        this._toggleParentsScrollSubscription(this._isVisible());
        this._initEventTrigger();
        this._incidentOccurred = (0, _base_widget.createIncidentOccurred)(this.NAME, this._eventTrigger);
        this._layout = new _layout.default;
        if (useLinks) {
            this._renderer.root.linkAfter("core")
        }
        this._initPlugins();
        this._initCore();
        if (useLinks) {
            this._renderer.root.linkAfter()
        }
        this._change(this._initialChanges)
    },
    _createThemeManager() {
        return new _base_theme_manager.BaseThemeManager(this._getThemeManagerOptions())
    },
    _getThemeManagerOptions() {
        return {
            themeSection: this._themeSection,
            fontFields: this._fontFields
        }
    },
    _initialChanges: ["LAYOUT", "RESIZE_HANDLER", "THEME", "DISABLED"],
    _initPlugins() {
        (0, _iterator.each)(this._plugins, (_, plugin) => {
            plugin.init.call(this)
        })
    },
    _disposePlugins() {
        (0, _iterator.each)(this._plugins.slice().reverse(), (_, plugin) => {
            plugin.dispose.call(this)
        })
    },
    _change(codes) {
        this._changes.add(codes)
    },
    _suspendChanges() {
        this._changesLocker += 1
    },
    _resumeChanges() {
        if (0 === --this._changesLocker && this._changes.count() > 0 && !this._applyingChanges) {
            this._renderer.lock();
            this._applyingChanges = true;
            this._applyChanges();
            this._changes.reset();
            this._applyingChanges = false;
            this._changesApplied();
            this._renderer.unlock();
            if (this._optionsQueue) {
                this._applyQueuedOptions()
            }
            this.resolveItemsDeferred(this._legend ? [this._legend] : []);
            this._optionChangedLocker += 1;
            this._notify();
            this._optionChangedLocker -= 1
        }
    },
    resolveItemsDeferred(items) {
        this._resolveDeferred(this._getTemplatesItems(items))
    },
    _collectTemplatesFromItems: items => items.reduce((prev, i) => ({
        items: prev.items.concat(i.getTemplatesDef()),
        groups: prev.groups.concat(i.getTemplatesGroups())
    }), {
        items: [],
        groups: []
    }),
    _getTemplatesItems(items) {
        const elements = this._collectTemplatesFromItems(items);
        const extraItems = this._getExtraTemplatesItems();
        return {
            items: extraItems.items.concat(elements.items),
            groups: extraItems.groups.concat(elements.groups),
            launchRequest: [extraItems.launchRequest],
            doneRequest: [extraItems.doneRequest]
        }
    },
    _getExtraTemplatesItems: () => ({
        items: [],
        groups: [],
        launchRequest: () => {},
        doneRequest: () => {}
    }),
    _resolveDeferred(_ref) {
        let {
            items: items,
            launchRequest: launchRequest,
            doneRequest: doneRequest,
            groups: groups
        } = _ref;
        this._setGroupsVisibility(groups, "hidden");
        if (this._changesApplying) {
            this._changesApplying = false;
            callForEach(doneRequest);
            return
        }
        let syncRendering = true;
        _deferred.when.apply(this, items).done(() => {
            if (syncRendering) {
                this._setGroupsVisibility(groups, "visible");
                return
            }
            callForEach(launchRequest);
            this._changesApplying = true;
            const changes = ["LAYOUT", "FULL_RENDER"];
            if (this._asyncFirstDrawing) {
                changes.push("FORCE_FIRST_DRAWING");
                this._asyncFirstDrawing = false
            } else {
                changes.push("FORCE_DRAWING")
            }
            this._requestChange(changes);
            this._setGroupsVisibility(groups, "visible")
        });
        syncRendering = false
    },
    _setGroupsVisibility(groups, visibility) {
        groups.forEach(g => g.attr({
            visibility: visibility
        }))
    },
    _applyQueuedOptions() {
        const queue = this._optionsQueue;
        this._optionsQueue = null;
        this.beginUpdate();
        (0, _iterator.each)(queue, (_, action) => {
            action()
        });
        this.endUpdate()
    },
    _requestChange(codes) {
        this._suspendChanges();
        this._change(codes);
        this._resumeChanges()
    },
    _applyChanges() {
        const changes = this._changes;
        const order = this._totalChangesOrder;
        const changesOrderLength = order.length;
        for (let i = 0; i < changesOrderLength; i += 1) {
            if (changes.has(order[i])) {
                this["_change_".concat(order[i])]()
            }
        }
    },
    _optionChangesOrder: ["EVENTS", "THEME", "RENDERER", "RESIZE_HANDLER"],
    _layoutChangesOrder: ["ELEMENT_ATTR", "CONTAINER_SIZE", "LAYOUT"],
    _customChangesOrder: ["DISABLED"],
    _change_EVENTS() {
        this._eventTrigger.applyChanges()
    },
    _change_THEME() {
        this._setThemeAndRtl()
    },
    _change_RENDERER() {
        this._setRendererOptions()
    },
    _change_RESIZE_HANDLER() {
        this._setupResizeHandler()
    },
    _change_ELEMENT_ATTR() {
        this._renderElementAttributes();
        this._change(["CONTAINER_SIZE"])
    },
    _change_CONTAINER_SIZE() {
        this._updateSize()
    },
    _change_LAYOUT() {
        this._setContentSize()
    },
    _change_DISABLED() {
        const renderer = this._renderer;
        const {
            root: root
        } = renderer;
        if (this.option("disabled")) {
            this._initDisabledState = root.attr("pointer-events");
            root.attr({
                "pointer-events": "none",
                filter: renderer.getGrayScaleFilter().id
            })
        } else if ("none" === root.attr("pointer-events")) {
            root.attr({
                "pointer-events": (0, _type.isDefined)(this._initDisabledState) ? this._initDisabledState : null,
                filter: null
            })
        }
    },
    _themeDependentChanges: ["RENDERER"],
    _initRenderer() {
        const rawCanvas = this._calculateRawCanvas();
        this._canvas = (0, _utils2.floorCanvasDimensions)(rawCanvas);
        this._renderer = new _renderer2.Renderer({
            cssClass: "".concat(this._rootClassPrefix, " ").concat(this._rootClass),
            pathModified: this.option("pathModified"),
            container: this._$element[0]
        });
        this._renderer.resize(this._canvas.width, this._canvas.height)
    },
    _disposeRenderer() {
        this._renderer.dispose()
    },
    _disposeGraphicObjects() {
        Object.keys(this._graphicObjects).forEach(id => {
            this._graphicObjects[id].dispose()
        });
        this._graphicObjects = null
    },
    _getAnimationOptions: _common.noop,
    render() {
        this._requestChange(["CONTAINER_SIZE"]);
        const visible = this._isVisible();
        this._toggleParentsScrollSubscription(visible);
        !visible && this._stopCurrentHandling()
    },
    _toggleParentsScrollSubscription(subscribe) {
        let $parents = (0, _renderer.default)(this._renderer.root.element).parents();
        if ("generic" === _devices.default.real().platform) {
            $parents = $parents.add((0, _window.getWindow)())
        }
        this._proxiedTargetParentsScrollHandler = this._proxiedTargetParentsScrollHandler || function() {
            this._stopCurrentHandling()
        }.bind(this);
        _events_engine.default.off((0, _renderer.default)("").add(this._$prevRootParents), "scroll.viz_widgets", this._proxiedTargetParentsScrollHandler);
        if (subscribe) {
            _events_engine.default.on($parents, "scroll.viz_widgets", this._proxiedTargetParentsScrollHandler);
            this._$prevRootParents = $parents
        }
    },
    _stopCurrentHandling: _common.noop,
    _dispose() {
        if (this._disposed) {
            return
        }
        this.callBase(...arguments);
        this._toggleParentsScrollSubscription(false);
        this._removeResizeHandler();
        this._layout.dispose();
        this._eventTrigger.dispose();
        this._disposeCore();
        this._disposePlugins();
        this._disposeGraphicObjects();
        this._disposeRenderer();
        this._themeManager.dispose();
        this._themeManager = null;
        this._renderer = null;
        this._eventTrigger = null
    },
    _initEventTrigger() {
        this._eventTrigger = (0, _base_widget.createEventTrigger)(this._eventsMap, (name, actionSettings) => this._createActionByOption(name, actionSettings))
    },
    _calculateRawCanvas() {
        const size = this.option("size") || {};
        const margin = this.option("margin") || {};
        const defaultCanvas = this._getDefaultSize() || {};
        const getSizeOfSide = (size, side, getter) => {
            if (sizeIsValid(size[side]) || !(0, _window.hasWindow)()) {
                return 0
            }
            const elementSize = getter(this._$element);
            return elementSize <= 1 ? 0 : elementSize
        };
        const elementWidth = getSizeOfSide(size, "width", x => (0, _size.getWidth)(x));
        const elementHeight = getSizeOfSide(size, "height", x => (0, _size.getHeight)(x));
        let canvas = {
            width: size.width <= 0 ? 0 : pickPositiveValue([size.width, elementWidth, defaultCanvas.width]),
            height: size.height <= 0 ? 0 : pickPositiveValue([size.height, elementHeight, defaultCanvas.height]),
            left: pickPositiveValue([margin.left, defaultCanvas.left]),
            top: pickPositiveValue([margin.top, defaultCanvas.top]),
            right: pickPositiveValue([margin.right, defaultCanvas.right]),
            bottom: pickPositiveValue([margin.bottom, defaultCanvas.bottom])
        };
        if (canvas.width - canvas.left - canvas.right <= 0 || canvas.height - canvas.top - canvas.bottom <= 0) {
            canvas = {
                width: 0,
                height: 0
            }
        }
        return canvas
    },
    _updateSize() {
        const rawCanvas = this._calculateRawCanvas();
        if ((0, _utils2.areCanvasesDifferent)(this._canvas, rawCanvas) || this.__forceRender) {
            this._canvas = (0, _utils2.floorCanvasDimensions)(rawCanvas);
            this._recreateSizeDependentObjects(true);
            this._renderer.resize(this._canvas.width, this._canvas.height);
            this._change(["LAYOUT"])
        }
    },
    _recreateSizeDependentObjects: _common.noop,
    _getMinSize: () => [0, 0],
    _getAlignmentRect: _common.noop,
    _setContentSize() {
        const canvas = this._canvas;
        const layout = this._layout;
        let rect = canvas.width > 0 && canvas.height > 0 ? [canvas.left, canvas.top, canvas.width - canvas.right, canvas.height - canvas.bottom] : [0, 0, 0, 0];
        rect = layout.forward(rect, this._getMinSize());
        const nextRect = this._applySize(rect) || rect;
        layout.backward(nextRect, this._getAlignmentRect() || nextRect)
    },
    _getOption(name, isScalar) {
        const theme = this._themeManager.theme(name);
        const option = this.option(name);
        return isScalar ? void 0 !== option ? option : theme : (0, _extend.extend)(true, {}, theme, option)
    },
    _setupResizeHandler() {
        const redrawOnResize = (0, _utils.parseScalar)(this._getOption("redrawOnResize", true), true);
        if (this._disposeResizeHandler) {
            this._removeResizeHandler()
        }
        this._disposeResizeHandler = (0, _base_widget.createResizeHandler)(this._$element[0], redrawOnResize, () => this._requestChange(["CONTAINER_SIZE"]))
    },
    _removeResizeHandler() {
        if (this._disposeResizeHandler) {
            this._disposeResizeHandler();
            this._disposeResizeHandler = null
        }
    },
    _onBeginUpdate: _common.noop,
    beginUpdate() {
        if (this._initialized && this._isUpdateAllowed()) {
            this._onBeginUpdate();
            this._suspendChanges()
        }
        this.callBase(...arguments);
        return this
    },
    endUpdate() {
        this.callBase();
        this._isUpdateAllowed() && this._resumeChanges();
        return this
    },
    option(name) {
        if (this._initialized && this._applyingChanges && (arguments.length > 1 || (0, _type.isObject)(name))) {
            this._optionsQueue = this._optionsQueue || [];
            this._optionsQueue.push(this._getActionForUpdating(arguments))
        } else {
            return baseOptionMethod.apply(this, arguments)
        }
    },
    _getActionForUpdating(args) {
        return () => {
            baseOptionMethod.apply(this, args)
        }
    },
    _clean: _common.noop,
    _render: _common.noop,
    _optionChanged(arg) {
        if (this._optionChangedLocker) {
            return
        }
        const partialChanges = this.getPartialChangeOptionsName(arg);
        let changes = [];
        if (partialChanges.length > 0) {
            partialChanges.forEach(pc => changes.push(this._partialOptionChangesMap[pc]))
        } else {
            changes.push(this._optionChangesMap[arg.name])
        }
        changes = changes.filter(c => !!c);
        if (this._eventTrigger.change(arg.name)) {
            this._change(["EVENTS"])
        } else if (changes.length > 0) {
            this._change(changes)
        } else {
            this.callBase.apply(this, arguments)
        }
    },
    _notify: _common.noop,
    _changesApplied: _common.noop,
    _optionChangesMap: {
        size: "CONTAINER_SIZE",
        margin: "CONTAINER_SIZE",
        redrawOnResize: "RESIZE_HANDLER",
        theme: "THEME",
        rtlEnabled: "THEME",
        encodeHtml: "THEME",
        elementAttr: "ELEMENT_ATTR",
        disabled: "DISABLED"
    },
    _partialOptionChangesMap: {},
    _partialOptionChangesPath: {},
    getPartialChangeOptionsName(changedOption) {
        const {
            fullName: fullName
        } = changedOption;
        const sections = fullName.split(/[.]/);
        const {
            name: name
        } = changedOption;
        const {
            value: value
        } = changedOption;
        const options = this._partialOptionChangesPath[name];
        const partialChangeOptionsName = [];
        if (options) {
            if (true === options) {
                partialChangeOptionsName.push(name)
            } else {
                options.forEach(op => {
                    fullName.indexOf(op) >= 0 && partialChangeOptionsName.push(op)
                });
                if (1 === sections.length) {
                    if ("object" === (0, _type.type)(value)) {
                        this._addOptionsNameForPartialUpdate(value, options, partialChangeOptionsName)
                    } else if ("array" === (0, _type.type)(value)) {
                        if (value.length > 0 && value.every(item => this._checkOptionsForPartialUpdate(item, options))) {
                            value.forEach(item => {
                                this._addOptionsNameForPartialUpdate(item, options, partialChangeOptionsName)
                            })
                        }
                    }
                }
            }
        }
        return partialChangeOptionsName.filter((value, index, self) => self.indexOf(value) === index)
    },
    _checkOptionsForPartialUpdate: (optionObject, options) => !Object.keys(optionObject).some(key => -1 === options.indexOf(key)),
    _addOptionsNameForPartialUpdate(optionObject, options, partialChangeOptionsName) {
        const optionKeys = Object.keys(optionObject);
        if (this._checkOptionsForPartialUpdate(optionObject, options)) {
            optionKeys.forEach(key => options.indexOf(key) > -1 && partialChangeOptionsName.push(key))
        }
    },
    _visibilityChanged() {
        this.render()
    },
    _setThemeAndRtl() {
        this._themeManager.setTheme(this.option("theme"), this.option("rtlEnabled"))
    },
    _getRendererOptions() {
        return {
            rtl: this.option("rtlEnabled"),
            encodeHtml: this.option("encodeHtml"),
            animation: this._getAnimationOptions()
        }
    },
    _setRendererOptions() {
        this._renderer.setOptions(this._getRendererOptions())
    },
    svg() {
        return this._renderer.svg()
    },
    getSize() {
        const canvas = this._canvas || {};
        return {
            width: canvas.width,
            height: canvas.height
        }
    },
    isReady: getFalse,
    _dataIsReady: getTrue,
    _resetIsReady() {
        this.isReady = getFalse
    },
    _renderGraphicObjects() {
        const renderer = this._renderer;
        const graphics = _m_charts.default.getGraphicObjects();
        Object.keys(graphics).forEach(id => {
            if (!this._graphicObjects[id]) {
                const {
                    type: type,
                    colors: colors,
                    rotationAngle: rotationAngle,
                    template: template,
                    width: width,
                    height: height
                } = graphics[id];
                switch (type) {
                    case "linear":
                        this._graphicObjects[id] = renderer.linearGradient(colors, id, rotationAngle);
                        break;
                    case "radial":
                        this._graphicObjects[id] = renderer.radialGradient(colors, id);
                        break;
                    case "pattern":
                        this._graphicObjects[id] = renderer.customPattern(id, this._getTemplate(template), width, height)
                }
            }
        })
    },
    _drawn() {
        this.isReady = getFalse;
        if (this._dataIsReady()) {
            this._renderer.onEndAnimation(() => {
                this.isReady = getTrue
            })
        }
        this._eventTrigger("drawn", {})
    }
});
var _default = baseWidget;
exports.default = _default;
(0, _helpers.replaceInherit)(baseWidget);
