    /*

    Siesta 5.3.0
    Copyright(c) 2009-2019 Bryntum AB
    https://bryntum.com/contact
    https://bryntum.com/products/siesta/license

    */
    /**
    @class Siesta.Recorder.Role.CanRecordPointOfInterest

    A mixin, providing the feature of recording the "moveCursorTo" event, when cursor is moved over certain
    "point of interest", which can be specified as an array of CSS selectors: {@link #moveCursorToSelectors}.

    This feature ensures that cursor is following the same path, activating the same UI elements as during recording
    session, like menu items, various hover elements etc.

    */
    Role('Siesta.Recorder.Role.CanRecordPointOfInterest', {

        does        : Siesta.Util.Role.CanMergeArrayAttributeFromClassHierarchy,

        has : {
            /**
             * @cfg {Array[String]} moveCursorToSelectors An array of strings with CSS selectors. If the mouse is
             * moved upon a target, matching any of these selectors, a `moveCursorTo` will be recorded.
             *
             * Used with {@link #recordPointsOfInterest} option.
             */
            moveCursorToSelectors           : Joose.I.Array,

            pointOfInterestSelector         : null,

            /**
             * @cfg {Boolean} recordPointsOfInterest Set this option to `true` to enable recording of "points of interest",
             * specified with the {@link #moveCursorToSelectors} CSS selectors
             *
             * This is useful in lots of scenarios, for example when triggering a menu item to show. You cannot click the menu item right away,
             * since it's hidden until you move the cursor over the top-level menu header.
             *
             * So if you will add the CSS selector for the top-level menu header in this config, recorder will insert `moveCursorTo` actions
             * every time mouse hovers it. This makes recording complex scenarios more robust.
             */
            recordPointsOfInterest          : true,

            lastPointOfInterestEl           : null
        },

        override : {

            initialize : function (cfg) {
                // will be merged from all the base classes, and also prepended with the possible config value, passed by the user
                this.moveCursorToSelectors          = this.mergeArrayAttributeFromClassHierarchy('moveCursorToSelectors', cfg)

                this.pointOfInterestSelector        = this.recordPointsOfInterest ? this.moveCursorToSelectors.join(',') : null

                if (this.pointOfInterestSelector) this.recordMouseMove = true

                this.SUPERARG(arguments)
            },

            onStart : function () {
                this.SUPERARG(arguments)

                if (this.pointOfInterestSelector) {
                    this.lastPointOfInterestEl = null;
                }
            },

            onStop : function () {
                this.SUPERARG(arguments)

                if (this.pointOfInterestSelector) {
                    this.lastPointOfInterestEl = null;
                }
            },

            processBodyMouseOver : function(e) {
                this.SUPERARG(arguments)

                var pointOfInterestSelector = this.pointOfInterestSelector

                if (!pointOfInterestSelector) return

                var pointOfInterestEl = e.target;

                if (
                    this.matches(pointOfInterestEl, pointOfInterestSelector)
                    || (pointOfInterestEl = this.closest(e.target, pointOfInterestSelector, 10))
                ) {

                    if (pointOfInterestEl !== this.lastPointOfInterestEl) {
                        this.lastPointOfInterestEl = pointOfInterestEl

                        // note, that `moveCursorTo` action is still recorded with real target of the event,
                        // which may be different from the `pointOfInterestEl`
                        this.addMoveCursorAction(e)
                    }
                }
            },

            processBodyMouseOut : function (e) {
                this.SUPERARG(arguments)

                if (!this.pointOfInterestSelector || !this.lastPointOfInterestEl) return

                if (!this.contains(this.lastPointOfInterestEl, e.target)) {
                    this.lastPointOfInterestEl = null
                }
            }
        }
        // eof methods
    });