"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.slotProxy = void 0;
const selenium_webdriver_1 = require("selenium-webdriver");
const elements_1 = require("../elements");
/**
 * Create a SlotProxy proxy for the given WebElement
 * @param el The WebElement to proxy
 * @param parent Optional WebElement hostComponent
 * @return {SlotProxy} A SlotProxy implementation which wraps the given WebElement.
 */
function slotProxy(el, parent) {
    if (!el) {
        throw Error('No root element given for SlotProxy');
    }
    return new SlotProxyImpl(el, parent);
}
exports.slotProxy = slotProxy;
/**
 * Default implementation of SlotProxy, used to wrap the underlying WebElement
 * for the collection row and delegate exposed functionality to that WebElement.
 * @private
 */
class SlotProxyImpl {
    constructor(el, parent) {
        this._root = el;
        this._parent = parent;
    }
    getDriver() {
        return this._root.getDriver();
    }
    findElement(locator) {
        return this._root.findElement(locator);
    }
    findElements(locator) {
        return this._root.findElements(locator);
    }
    /*
     * Invokes the contextual Action of the rootNode.
     */
    async doContextualAction(action) {
        if (!this._parent) {
            throw Error('Slot Proxy must be initialized with a parent to do a contextual action');
        }
        await this.scrollIntoView();
        const doesSwipeActionExist = await this.doesSwipeActionExist();
        if (doesSwipeActionExist) {
            const ojSwipeAction = await this.getSwipeAction();
            return ojSwipeAction.doAction(action);
        }
        const menu = await this.locateMenu();
        if (menu) {
            await this.openMenu(menu);
            const menuOption = await this.findMenuOptionByValue(action, menu);
            return this.doMenuAction(menuOption, menu);
        }
        throw Error('No Context menu configured for this host component.');
    }
    /*
     * Scrolls root node into view.
     */
    async scrollIntoView() {
        const actions = this.getDriver().actions();
        // selenium-webdriver 3.6.0
        // @ts-ignore
        if (actions.mouseMove) {
            // @ts-ignore
            return actions.mouseMove(this._root).perform();
        }
        else if (actions.move) {
            return actions.move({ origin: this._root }).perform();
        }
    }
    /*
     * Finds out if a swipe action menu exists.
     */
    async doesSwipeActionExist() {
        const swipeActions = await this._root.findElements(selenium_webdriver_1.By.css('OJ-SWIPE-ACTIONS'));
        return swipeActions.length > 0;
    }
    /*
     * Returns the swipe action menu for root node.
     */
    async getSwipeAction() {
        return (0, elements_1.ojSwipeActions)(this._root, selenium_webdriver_1.By.css('OJ-SWIPE-ACTIONS'));
    }
    /*
     * Locates and returns a menu if it exists.
     */
    async locateMenu() {
        const doesClosedMenuExist = await this.doesClosedMenuExist();
        if (doesClosedMenuExist && this._parent) {
            return (0, elements_1.ojMenu)(this._parent, selenium_webdriver_1.By.css('oj-menu[slot=contextMenu]'));
        }
        else {
            const doesOpenMenuExist = await this.doesOpenMenuExist();
            if (doesOpenMenuExist) {
                const menuId = await this.getOpenMenuId();
                if (menuId) {
                    const menu = await (0, elements_1.ojMenu)(this.getDriver(), selenium_webdriver_1.By.id(menuId));
                    await this.closeMenu(menu);
                    return Promise.resolve(menu);
                }
            }
            return Promise.resolve(undefined);
        }
    }
    /*
     * Closes menu programmatically.
     */
    async closeMenu(menu) {
        return this.getDriver().executeScript(`
     const menu = arguments[0];
     menu.close();
  `, menu);
    }
    /*
     * Finds out if a closed menu exists.
     */
    async doesClosedMenuExist() {
        if (this._parent) {
            const menus = await this._parent.findElements(selenium_webdriver_1.By.css('oj-menu[slot=contextMenu]'));
            return menus.length > 0;
        }
        return Promise.resolve(false);
    }
    /*
     * Gets menu ID from the surrogate.
     */
    async getOpenMenuId() {
        if (this._parent) {
            const surrogate = await this._parent.findElement(selenium_webdriver_1.By.css('OJ-SURROGATE'));
            const surrogateId = await surrogate.getAttribute('id');
            const lastIndex = surrogateId.lastIndexOf('_layer_surrogate');
            return surrogateId.substring(0, lastIndex);
        }
        return Promise.resolve(undefined);
    }
    /*
     * Finds out if an open menu exists.
     */
    async doesOpenMenuExist() {
        if (this._parent) {
            const surrogates = await this._parent.findElements(selenium_webdriver_1.By.css('OJ-SURROGATE'));
            return surrogates.length > 0;
        }
        return Promise.resolve(false);
    }
    /*
     * Opens menu programmatically.
     */
    async openMenu(menu) {
        await this.giveRootFocus();
        return this.getDriver().executeScript(`
      const menu = arguments[0];
      const launcher = arguments[1];
      const clickEvent = new CustomEvent('click');
      launcher.dispatchEvent(clickEvent);
      menu.open(clickEvent, { launcher: launcher })
    `, menu, this._root);
    }
    /*
     * Give the root node focus by clicking or tapping.
     */
    async giveRootFocus() {
        await this.getDriver().executeScript(`
    const root = arguments[0];
    root.click();
    `, this._root);
    }
    /*
     * Finds a given menu option given its value.
     */
    async findMenuOptionByValue(targetValue, menu) {
        const options = await menu.findElements(selenium_webdriver_1.By.css('oj-option'));
        for (let i = 0; i < options.length; i++) {
            const value = await options[i].getAttribute('value');
            if (value === targetValue) {
                return options[i];
            }
        }
        throw Error('No option associated with value: ' + targetValue);
    }
    /*
     * Executes menu action given a menu and the item to be executed.
     */
    async doMenuAction(item, menu) {
        const a = await item.findElement(selenium_webdriver_1.By.css('a')); // get the item anchor which should be active
        const aId = await a.getAttribute('id');
        let activeAId = await menu.getAttribute('aria-activedescendant');
        while (activeAId !== aId) {
            await menu.sendKeys(selenium_webdriver_1.Key.DOWN);
            activeAId = await menu.getAttribute('aria-activedescendant');
        }
        await item.click();
        await menu.whenBusyContextReady();
    }
}
//# sourceMappingURL=slot-proxy.js.map