/*

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

*/
/**
@class Siesta.Test.Action.Role.HasTarget

This is a mixin, allowing the action to have "target" attribute, also aliased as "el". Target will be also passed
further on chain, as the argument after "next":

    t.chain(
        {
            action      : 'click',
            target      : buttonComp
        },
        function (next, buttonComp) {
            // target is available as 2nd argument

            next()
        },
        {
            action      : 'click',
            target      : '>>button',
            offset      : [10, 20]
        },
        function (next, buttonComp) {
            // various queries will be resolved down to Ext.Component instance or DOM element

            next()
        },
        ...
    )

If needed, this behavior can be disabled with {@link #passTargetToNext} option.

*/
Role('Siesta.Test.Action.Role.HasTarget', {


    has : {
        /**
         * @cfg {Siesta.Test.ActionTarget/Function} [target=undefined]
         *
         * A target for action. See {@link Siesta.Test.ActionTarget} for various values that can be provided.
         *
         * **Important.** If the function is provided for this config, it will be called and returning value used as actual target.
         * This is useful, since sometimes target for the action depends from the previous step and
         * is not yet available during `t.chain` call.
         *
         * For example, you want to click on the button which opens a window and then click on something in the window. Compare:
         *

    t.chain(
        // clicking on button opens the window
        {
            action      : 'click',
            target      : buttonComp
        },
        // FRAGILE: `windowComp` could not be rendered yet - `buttonComp` is not yet clicked!
        {
            action      : 'click',
            target      : windowComp.el.down('.clickArea')
        }

        // MORE ROBUST: taking the "el" right before this action starts
        {
            action      : 'click',
            target      : function () {
                return windowComp.el.down('.clickArea')
            }
        }
    )
         *
         * Target will be available in the next step as the 2nd argument. See {@link Siesta.Test.Action.Role.HasTarget}
         *
         * This config option can also be provided as "el"
         */
        target              : { required : false },

        normalizedTarget    : null,
        cachedTarget        : null,

        /**
         * @cfg {Object} el
         *
         * An alias for {@link #target}
         */

        /**
         * @cfg {Boolean} passTargetToNext Whether to pass the target further on chain as the first argument
         */
        passTargetToNext    : true,


        /**
         * @cfg {Object} options
         *
         * Any options that will be used when simulating the event. For information about possible
         * config options, please see: <https://developer.mozilla.org/en-US/docs/DOM/event.initMouseEvent>
         */
        options             : null,

        /**
         * @cfg {Array} offset
         *
         * An offset in X, Y coordinates from the targeted element. The offset can be expressed in 3 different ways.
         *
         * - Integers             : `[10, 20]`       -  offset 10px from left, 20px from top
         * - Percent              : `["10%", 20]`    -  offset 10% from left, 20px from top
         * - Percent + offset     : `["100%-2", 20]` -  offset -2px from right, 20px from top
         */
        offset              : null,

        waitForTarget       : true
    },


    after : {
        initialize : function () {
            if (!this.passTargetToNext) return

            var me          = this
            var prevNext    = this.next

            this.next       = function () {
                prevNext.call(this, me.normalizedTarget);
            }
        }
    },


    methods : {

        BUILD : function (config) {
            // allow "el" as synonym for "target"
            if (config.el && !config.target) config.target = config.el

            return config
        },


        getTarget : function () {
            if (this.cachedTarget) return this.cachedTarget

            var test        = this.test;
            var target      = this.target || test.getCursorPagePosition()

            if (test.typeOf(target) === 'Function') target = target.call(test, this);

            this.normalizedTarget   = test.normalizeActionTarget(target, true)

            return this.cachedTarget   = target
        }
    }
});