Ext.define('Ext.rtl.dom.Element_scroll', {
    override: 'Ext.dom.Element',

    rtlGetScroll: function() {
        var me = this,
            dom = me.dom,
            doc = document,
            body = doc.body,
            scroll = me.getScroll(),
            // The left value returned from getScroll() may be a negative number.  In rtl
            // mode left should always be reported as a positive number of pixels from the
            // right, so use the absolute value of left.
            left = Math.abs(scroll.left),
            isDocOrBody = (dom === doc || dom === body);

        if (isDocOrBody ? (3 & me._rtlDocScrollFlag) : (me._rtlScrollFlag === 1)) {
            // If the browser reports scrollLeft as the number of pixels from left
            // (same as ltr) we need to convert it to a rtl position by subtracting it
            // from scrollWidth
            if (isDocOrBody) {
                dom = body;
            }
            
            left = dom.scrollWidth - left -
                (isDocOrBody ? Ext.Element.getViewportWidth() : dom.clientWidth);
        }
        scroll.left = left;

        return scroll;
    },
    
    rtlGetScrollLeft: function() {
        return this.rtlGetScroll().left;
    },
    
    rtlSetScrollLeft: function(left){
        var me = this;

        me.dom.scrollLeft = me.rtlNormalizeScrollLeft(left);
        return me;
    },

    rtlScrollTo: function(side, value, animate) {
        if (side === 'left') {
            value = this.rtlNormalizeScrollLeft(value);
        }

        return this.scrollTo(side, value, animate);
    },

    rtlScrollBy: function(deltaX, deltaY, animate) {
        var me = this,
            dom = me.dom,
            left, maxScroll;

        // Extract args if deltas were passed as an Array.
        if (deltaX.length) {
            animate = deltaY;
            deltaY = deltaX[1];
            deltaX = deltaX[0];
        } else if (typeof deltaX != 'number') { // or an object
            animate = deltaY;
            deltaY = deltaX.y;
            deltaX = deltaX.x;
        }
       
        if (deltaX) {
            left = me.rtlNormalizeScrollLeft(
                me.constrainScrollLeft(me.rtlGetScrollLeft() + deltaX)
            ); 
 
            me.scrollTo('left', left, animate);
        }
        if (deltaY) {
            me.scrollTo('top', me.constrainScrollTop(dom.scrollTop + deltaY), animate);
        }

        return me;
    },

    rtlScroll: function(direction, distance, animate) {
        if (!this.isScrollable()) {
            return false;
        }
        var me = this,
            side = direction === 'r' || direction === 'l' ? 'left' : 'top',
            scrolled = false,
            currentScroll, constrainedScroll;

        if (direction === 'r') {
            distance = -distance;
        }

        if (side === 'left') {
            currentScroll = me.rtlGetScrollLeft();
            constrainedScroll = me.constrainScrollLeft(currentScroll + distance);
        } else {
            currentScroll = me.dom.scrollTop;
            constrainedScroll = me.constrainScrollTop(currentScroll + distance);
        }

        if (constrainedScroll !== currentScroll) {
            this.rtlScrollTo(side, constrainedScroll, animate);
            scrolled = true;
        }

        return scrolled;
    },

    rtlNormalizeScrollLeft: function(left){
        var dom = this.dom,
            flag = this._rtlScrollFlag;
            
        if (flag === 0) {
            left = -left;
        } else if (flag === 1) {
            left = dom.scrollWidth - left - dom.clientWidth;
        }
        return left;
    }
    
}, function() {
    var Element = this;

    /*
     * Sets a _rtlScrollFlag property on the Element class prototype indicating how the
     * browser reports scrollLeft on overflowing rtl elements.  This method cannot be used
     * reliably on the documentElement or document.body because the behavior of these
     * elements can be different from other elements in some browsers.
     * 
     * 0: offset from right (negative number) - firefox
     * 1: offset from left (positive number) - IE6, IE7, IE6 - IE9 quirks, and Webkit
     * 2: offset from right (positive number) - IE8 - IE10 & IE10 quirks
     */
    function cacheRtlScrollFlag() {
        var el = Ext.getBody().createChild({
            tag: 'div',
            style: 'direction:rtl;position:absolute;overflow:auto;height:100px;width:100px;',
            children: [{
                tag: 'div',
                style: 'height:30px;width:150px;'
            }]
        }),
        dom = el.dom,
        flag = 2;

        if (dom.scrollLeft === 50) {
            flag = 1;
        } else {
            dom.scrollLeft = -1;
            if (dom.scrollLeft) {
                flag = 0;
            }
        }

        el.remove();
        Element.prototype._rtlScrollFlag = flag;
    }

    /*
     * scrollLeft on the document/body is reported differently from ordinary
     * overflowing elements in many browsers (see getRtlScrollFlag).There are 2
     * separate things we have to detect:
     * 1. The element that overflows - when the document overflows some browsers
     * set scrollLeft on the document body (webkit and IE quirks), while other
     * browsers set scrollLeft on the documentElement (all other supported browsers
     * at the time of this writing).
     * 2. The scrollLeft of the overflowing document/body can be one of the
     * following:
     *    a. number of pixels offset from right expressed as a negative number
     *       (Webkit, Firefox)
     *    b. number of pixels offset from right expressed as a positive number
     *       (IE8 - IE10 strict mode, and IE10 quirks mode.
     *    c. number of pixels offset from left expressed as a positive number
     *       (IE6 - IE9 quirks mode, and IE6/IE7 strict mode.
     *
     * The following logic feture detects the handling of scrollLeft and sets the 
     * _rtlDocScrollFlag property on this class' prototype as a bit flag which has 
     * the following values:
     * 
     * 0 - docEl, negative right
     * 1 - docEl, positive left
     * 2 - docEl, positive right
     * 4 - body, negative right
     * 5 - body, positive left
     */
    function cacheRtlDocScrollFlag() {
        var doc = document,
            docEl = doc.documentElement,
            body = doc.body,
            // flag defaults to body, negative right (webkit) so no detection needed
            // is needed for this scenario
            flag = 4,
            bodyStyle = body.style,
            // save the direction property so we can set it back when we are done.
            direction = bodyStyle.direction,
            el = Ext.getBody().createChild(
                '<div style="height:20000px;width:20000px;"></div>'
            ), 
            dom = el.dom,
            ltrRight, rtlRight

        bodyStyle.direction = 'ltr';
        ltrRight = dom.getBoundingClientRect().right;

        bodyStyle.direction = 'rtl';
        rtlRight = dom.getBoundingClientRect().right;
        
        // when the body has vertical overflow some browser continue to show the
        // vertical scrollbar on the right side of the page even in rtl mode.
        Element.prototype._rtlBodyScrollbarOnRight = (ltrRight === rtlRight);

        // First, check if scrollLeft is a non-zero value on the documentElement or
        // body. This means scrollLeft is a positive number offset from the left.
        if (docEl.scrollLeft > 0) {
            // IE6/7 strict
            flag = 1;
        } else if (body.scrollLeft > 0) {
            // IE6 - IE9 quirks
            flag = 5;
        } else {
            // The next step is to attempt to set scrollLeft values, This allows us to
            // test for non-zero values to see if the value was valid (scrollLeft
            // resets to 0 when a non-valid value is set).
            // attempt to set the documentElement's scrollLeft to a negative number
            docEl.scrollLeft = -1;
            if (docEl.scrollLeft) {
                // it worked! we were able to set a negative scroll left on the
                // documentElement (firefox)
                flag = 0;
            } else {
                // attempt to set the documentElement's scrollLeft to a positive number
                docEl.scrollLeft = 1;
                if (docEl.scrollLeft) {
                    // success setting scroll left to a positive number on
                    // documentElement (IE8 strict, IE9 strict, and IE10 quirks)
                    flag = 2;
                }
            }
        }

        el.remove();
        if (!direction) {
            // if direction is an empty string, we set it back to "ltr", because once
            // the direction style on the body element is changed to "rtl" in webkit,
            // it becomes permanent, even after it is set back to "", unless it is first
            // explicitly set back to "ltr"
            bodyStyle.direction = 'ltr';
            // read the scroll width before setting the direction back to "".
            // This forces webkit to update its computed direction style to ltr
            body.scrollWidth;
        }
        // set direction back to its original value
        bodyStyle.direction = direction;
        Element.prototype._rtlDocScrollFlag = flag;
    }

    Ext.on({
        ready: function() {
            // This function attaches to onReady with a priority of 1000 so that we can
            // detect how the browser reports scrollLeft by manipulating the document/body
            // before any components have been rendered to the page.  
            cacheRtlDocScrollFlag();
            cacheRtlScrollFlag();
        },
        single: true,
        priority: 1001
    });
});