/**
 * @class Ext.ux.DataTip
 * @extends Ext.ToolTip.
 * <p>This plugin implements automatic tooltip generation for an arbitrary number of child nodes <i>within</i> a Component.</p>
 * <p>This plugin is applied to a high level Component, which contains repeating elements, and depending on the host Component type,
 * it automatically selects a {@link Ext.ToolTip#delegate delegate} so that it appears when the mouse enters a sub-element.</p>
 * <p>When applied to a GridPanel, this ToolTip appears when over a row, and the Record's data is applied
 * using the Ext.Component#tpl template.</p>
 * <p>When applied to a DataView, this ToolTip appears when over a view node, and the Record's data is applied
 * using this object's {@link Ext.Component#tpl tpl} template.</p>
 * <p>When applied to a TreePanel, this ToolTip appears when over a tree node, and the Node's {@link Ext.tree.TreeNode#attributes attributes} are applied
 * using this object's {@link Ext.Component#tpl tpl} template.</p>
 * <p>When applied to a FormPanel, this ToolTip appears when over a Field, and the Field's <code>tooltip</code> property is used is applied
 * using this object's {@link Ext.Component#tpl tpl} template, or if it is a string, used as HTML content.</p>
 * <p>If more complex logic is needed to determine content, then the {@link Ext.Component#beforeshow beforeshow} event may be used.<p>
 * <p>This class also publishes a <b><code>beforeshowtip</code></b> event through its host Component. The <i>host Component</i> fires the
 * <b><code>beforeshowtip</code></b> event.
 */
export const DataTip = Ext.extend(
    Ext.ToolTip,
    (function () {
        function updateTip(tip, data) {
            if (tip.rendered) {
                tip.update(data);
            } else {
                if (Ext.isString(data)) {
                    tip.html = data;
                } else {
                    tip.data = data;
                }
            }
        }

        function onHostRender() {
            const e = this.body || this.el;
            if (this.dataTip.renderToTarget) {
                this.dataTip.render(e);
            }
            // In ExtJS 6, set the target element directly
            if (this.dataTip.setTarget) {
                this.dataTip.setTarget(e);
            } else if (e) {
                this.dataTip.target = e;
            }
        }

        function beforeGridTipShow(tip) {
            const rec = this.host
                .getStore()
                .getAt(this.host.getView().findRowIndex(tip.triggerElement));
            if (rec) {
                updateTip(tip, rec.data);
            } else {
                return false;
            }
        }

        function beforeTreeTipShow(tip) {
            const e = Ext.fly(tip.triggerElement).findParent(
                "div.x-tree-node-el",
                null,
                true
            );
            const node = e
                ? tip.host.getNodeById(
                    e.getAttribute("tree-node-id", "ext")
                )
                : null;
            if (node) {
                updateTip(tip, node.data);
            } else {
                return false;
            }
        }

        function beforeViewTipShow(tip) {
            const rec = this.host.getRecord(tip.triggerElement);
            if (rec) {
                updateTip(tip, rec.data);
            } else {
                return false;
            }
        }

        function beforeFormTipShow(tip) {
            const el = Ext.fly(tip.triggerElement).child("input,textarea"),
                field = el ? this.host.getForm().findField(el.id) : null;
            if (field && (field.tooltip || tip.tpl)) {
                updateTip(tip, field.tooltip || field);
            } else {
                return false;
            }
        }

        function beforeComboTipShow(tip) {
            const rec = this.host.store.getAt(this.host.selectedIndex);
            if (rec) {
                updateTip(tip, rec.data);
            } else {
                return false;
            }
        }

        return {
            init(host) {
                if (!host) {
                    return;
                }
                this.host = host;
                host.dataTip = this;
                if (host instanceof Ext.tree.TreePanel) {
                    this.delegate = this.delegate || "div.x-tree-node-el";
                    this.on("beforeshow", beforeTreeTipShow);
                } else if (host instanceof Ext.grid.GridPanel) {
                    this.delegate = this.delegate || host.getView().rowSelector;
                    this.on("beforeshow", beforeGridTipShow);
                } else if (host instanceof Ext.DataView) {
                    this.delegate = this.delegate || host.itemSelector;
                    this.on("beforeshow", beforeViewTipShow);
                } else if (host instanceof Ext.FormPanel) {
                    this.delegate = "div.x-form-item";
                    this.on("beforeshow", beforeFormTipShow);
                } else if (host instanceof Ext.form.ComboBox) {
                    this.delegate = this.delegate || host.itemSelector;
                    this.on("beforeshow", beforeComboTipShow);
                }
                if (host.rendered) {
                    onHostRender.call(host);
                } else {
                    // In ExtJS 6, use listeners instead of createSequence
                    host.on("render", onHostRender, host, { single: true });
                }
            },
        };
    })(),
);
