/*

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

*/
/**
@class Siesta.Test.Browser.Role.CanGetElementFromPoint

*/
Role('Siesta.Test.Browser.Role.CanGetElementFromPoint', {

    requires    : [
        '$'
    ],

    does        : [
        Siesta.Util.Role.CanCalculatePageScroll
    ],

    has : {
    },

    methods : {

        /**
         * This method will return the top-most DOM element at the specified coordinates from the test page. If
         * the resulting element is an iframe and `shallow` argument is not passed as `true`
         * it'll query the iframe for its element from the local point inside it.
         *
         * @param {Number} x The X coordinate, relative to the viewport area (currently visible part of the page)
         * @param {Number} y The Y coordinate, relative to the viewport area (currently visible part of the page)
         * @param {Boolean} [shallow] Pass `true` to _not_ check nested iframes if an element at the original coordinates is an iframe.
         *
         * @return {HTMLElement} The top-most element at the specified position on the test page
         */
        elementFromPoint : function (viewportX, viewportY, shallow, fallbackEl, fullInfo) {
            var queryRoot = this.global.document;
            var el        = queryRoot.elementFromPoint(viewportX, viewportY)

            var localX = viewportX
            var localY = viewportY

            if (!shallow) {
                // If we found IFRAME or shadow root and its not a `shallow` request, try to dig deeper
                // Web component shadow root might return its own shadowRoot if empty
                while (el && (el.nodeName.toUpperCase() === 'IFRAME' || (el.shadowRoot && el.shadowRoot !== queryRoot))) {
                    // if found iframe is loaded from different domain
                    // just accessing its "el.contentWindow.document" property will throw exception
                    try {
                        queryRoot  = this.getQueryableContainerForNestedContext(el);

                        if (el.nodeName.toUpperCase() === 'IFRAME') {
                            var pageOffset = this.$(el).offset();

                            localX = viewportX - this.pageXtoViewportX(pageOffset.left)
                            localY = viewportY - this.pageYtoViewportY(pageOffset.top)
                        }

                        el = queryRoot.elementFromPoint(localX, localY);

                        // If nothing is found inside the shadowRoot, return outer web component element
                        if (!el && typeof queryRoot.constructor === 'ShadowRoot') {
                            fallbackEl = queryRoot.host;
                        }
                    }
                    catch (e) {
                        // digging deeper failed likely due to DOMException of x-domain iframe , restore the local coordinates
                        localX = viewportX
                        localY = viewportY
                        break;
                    }
                }
            }

            // final fallback to the provided element or to the <body> element
            el = el || fallbackEl || this.getBodyElement();

            return fullInfo ? {
                el       : el,
                // viewport coords in the inner frame
                localXY  : [localX, localY],
                // viewport coords in the top frame (seems not needed, as just the input values are reused)
                globalXY : [viewportX, viewportY]
            } : el
        }
    }
});