/**
 * This override adds RTL positioning methods to Ext.dom.Element.
 */
Ext.define('Ext.rtl.dom.Element_position', {
    override: 'Ext.dom.Element',

    _positionTopRight: ['position', 'top', 'right'],

    statics: {
        getXY: function(el) {
            var doc = document,
                bd = doc.body,
                docEl = doc.documentElement,
                leftBorder = 0,
                topBorder = 0,
                ret = [0,0],
                x, box, scroll;

            el = Ext.getDom(el);

            if(el !== doc && el !== bd){
                // IE has the potential to throw when getBoundingClientRect
                // is called on an element not attached to dom
                if (Ext.isIE) {
                    try {
                        box = el.getBoundingClientRect();
                        // In some versions of IE, the documentElement (HTML element)
                        // will have a 2px border that gets included, so subtract it off
                        topBorder = docEl.clientTop || bd.clientTop;
                        leftBorder = docEl.clientLeft || bd.clientLeft;
                    } catch (ex) {
                        box = { left: 0, top: 0 };
                    }
                } else {
                    box = el.getBoundingClientRect();
                }

                doc = Ext.fly(document, '_getXY');
                if (Ext.rootHierarchyState.rtl) {
                    scroll = doc.rtlGetScroll();
                    x = Ext.Element.getViewportWidth() - box.right + scroll.left;
                } else {
                    scroll = doc.getScroll();
                    x = box.left + scroll.left;
                }
                ret = [
                    Math.round(x - leftBorder),
                    Math.round(box.top + scroll.top - topBorder)
                ];
            }
            return ret;
        },

        setXY: function(el, xy) {
            (el = Ext.fly(el, '_setXY')).position();

            var pts = el.translatePoints(xy),
                style = el.dom.style,
                pos;

            style[Ext.rootHierarchyState.rtl ? 'left' : 'right'] = 'auto';
            for (pos in pts) {
                if (!isNaN(pts[pos])) {
                    style[pos] = pts[pos] + 'px';
                }
            }
        }
    },

    getPositioning: function(autoPx){
        var xStyle = Ext.rootHierarchyState.rtl ? 'right' : 'left',
            styles = this.getStyle([xStyle, 'top', 'position', 'z-index']),
            dom = this.dom;

        if(autoPx) {
            if(styles[xStyle] === 'auto') {
                styles[xStyle] = (xStyle === 'left') ? (dom.offsetLeft + 'px') :
                    (dom.offsetParent.offsetWidth - dom.offsetLeft - dom.offsetWidth);
            }
            if(styles.top === 'auto') {
                styles.top = dom.offsetTop + 'px';
            }
        }

        return styles;
    },

    rtlGetLocalX: function() {
        var me = this,
            offsetParent = me.dom.offsetParent,
            x = me.getStyle('right');

        if (!x || x === 'auto') {
            x = 0;
        } else if (me.pxRe.test(x)) {
            x = parseFloat(x);
        } else {
            x = me.getX();
            if (offsetParent) {
                x -= Ext.fly(offsetParent, '_rtlGetLocalX').getX();
            }
        }

        return x;
    },

    rtlGetLocalXY: function() {
        var me = this,
            offsetParent = me.dom.offsetParent,
            style = me.getStyle(['right', 'top']),
            x = style.right,
            y = style.top;

        if (!x || x === 'auto') {
            x = 0;
        } else if (me.pxRe.test(x)) {
            x = parseFloat(x);
        } else {
            x = me.getX();
            if (offsetParent) {
                x -= Ext.fly(offsetParent, '_rtlGetLocalXY').getX();
            }
        }

        if (!y || y === 'auto') {
            y = 0;
        } else if (me.pxRe.test(y)) {
            y = parseFloat(y);
        } else {
            y = me.getY();
            if (offsetParent) {
                y -= Ext.Element.getY(offsetParent);
            }
        }

        return [x, y];
    },

    rtlSetLocalX: function(x) {
        var style = this.dom.style;

        // clear left style just in case it was previously set by setXY/setLocalXY
        style.left = 'auto';
        style.right = (x === null) ? 'auto' : x + 'px';
    },

    rtlSetLocalXY: function(x, y) {
        var style = this.dom.style;

        // clear left style just in case it was previously set by setXY/setLocalXY
        style.left = 'auto';

        if (x && x.length) {
            y = x[1];
            x = x[0];
        }

        if (x === null) {
            style.right = 'auto';
        } else if (x !== undefined) {
            style.right = x + 'px';
        }

        if (y === null) {
            style.top = 'auto';
        } else if (y !== undefined) {
            style.top = y + 'px';
        }
    },

    rtlSetX: function(x, animate) {
        return this.rtlSetXY([x, this.getY()], animate);
    },

    rtlSetXY: function(xy, animate) {
        var me = this,
            pts, style, pos;

        if (!animate || !me.anim) {
            pts = me.rtlTranslatePoints(xy);
            style = me.dom.style;

            // left position may have been previously set by setXY or setLocalXY
            // so clear it here just in case.
            style.left = 'auto';
            for (pos in pts) {
                if (!isNaN(pts[pos])) {
                    style[pos] = pts[pos] + "px";
                }
            }
        } else {
            if (!Ext.isObject(animate)) {
                animate = {};
            }
            me.animate(Ext.applyIf({ to: { x: xy[0], y: xy[1] } }, animate));
        }
        return me;
    },

    rtlSetY: function(y, animate) {
        return this.rtlSetXY([this.getX(), y], animate);
    },

    rtlTranslatePoints: function(x, y) {
        var pos = this.rtlTranslateXY(x, y);

        return {
            right: pos.x,
            top: pos.y
        };
    },

    rtlTranslateXY: function(x, y) {
        var me = this,
            styles = me.getStyle(me._positionTopRight),
            relative = styles.position == 'relative',
            right = parseFloat(styles.right),
            top = parseFloat(styles.top),
            xy = me.getXY(),
            dom = me.dom,
            doc, body, offsetParentWidth, offsetParent;

        if (x && x.length) {
             y = x[1];
             x = x[0];
        }
        if (isNaN(right)) {
            doc = document;
            body = doc.body;
            if (dom === body) {
                // translateXY can sometimes be called on the body element.
                // e.g. in Renderable#afterFirstLayout if the "container" is a viewport
                right = 0;
            } else {
                offsetParent = dom.offsetParent;
                offsetParentWidth = (offsetParent &&
                    offsetParent !== body && offsetParent !== doc.documentElement) ?
                        offsetParent.scrollWidth : Ext.Element.getViewportWidth();
                right = offsetParentWidth - dom.offsetLeft - me.getWidth();
            }
        }
        if (isNaN(top)) {
            top = relative ? 0 : me.dom.offsetTop;
        }
        right = (typeof x == 'number') ? x - xy[0] + right : undefined;
        top = (typeof y == 'number') ? y - xy[1] + top : undefined;
        return {
            x: right,
            y: top
        };
    },

    setX: function(x, animate) {
        return Ext.rootHierarchyState.rtl ? this.rtlSetX(x, animate) :
            this.callParent(arguments);
    },

    setXY: function(xy, animate) {
        return Ext.rootHierarchyState.rtl ? this.rtlSetXY(xy, animate) :
            this.callParent(arguments);
    },

    setY: function(y, animate) {
        return Ext.rootHierarchyState.rtl ? this.rtlSetY(y, animate) :
            this.callParent(arguments);
    },

    translatePoints: function(x, y) {
        return Ext.rootHierarchyState.rtl ? this.rtlTranslatePoints(x, y) : 
            this.callParent(arguments);
    },

    translateXY: function(x, y) {
        return Ext.rootHierarchyState.rtl ? this.rtlTranslateXY(x, y) : 
            this.callParent(arguments);
    }
});