/**
 * This override adds RTL support and the `rtl` config option to AbstactComponent.
 */
Ext.define('Ext.rtl.AbstractComponent', {
    override: 'Ext.AbstractComponent',

    /**
     * @cfg {Boolean} rtl
     * True to layout this component and its descendants in "rtl" (right-to-left) mode.
     * Can be explicitly set to false to override a true value inherited from an ancestor.
     */
    
    initStyles: function(){
        if (this.getHierarchyState().rtl) {
            this.horizontalPosProp = 'right';
        }
        this.callParent(arguments);
    },

    convertPositionSpec: function(posSpec) {
        // Since anchoring is done based on page level coordinates, we need to invert
        // left and right in the position spec when the direction of the compoent being
        // aligned is not the same as the direction of the viewport/body
        if ((Ext.rootHierarchyState.rtl || false) !== (this.getHierarchyState().rtl || false)) {
            posSpec = posSpec.replace(/l/g, 'tmp').replace(/r/g, 'l').replace(/tmp/g, 'r');
        }
        return posSpec;
    },

    getAnchorToXY: function(el, anchor, local, mySize) {
        var doc = document,
            pos, scroll, extraX, extraY;

        if (el.dom == doc.body || el.dom == doc) {
            // anchor the element using the same coordinate system as the viewport or body
            scroll = Ext.rootHierarchyState.rtl ? el.rtlGetScroll() : el.getScroll();
            extraX = scroll.left;
            extraY = scroll.top;
        } else {
            pos = el.getXY();
            extraX = local ? 0 : pos[0];
            extraY = local ? 0 : pos[1];
        }

        return el.calculateAnchorXY(anchor, extraX, extraY, mySize);
    },

    getBorderPadding: function() {
        var borderPadding = this.el.getBorderPadding(),
            xBegin;
                
        if (this.isParentRtl()) {
            xBegin = borderPadding.xBegin;
            borderPadding.xBegin = borderPadding.xEnd;
            borderPadding.xEnd = xBegin;
        }

        return borderPadding;
    },

    getLocalX: function() {
        return this.isLocalRtl() ? this.el.rtlGetLocalX() : this.el.getLocalX();
    },

    getLocalXY: function() {
        return this.isLocalRtl() ? this.el.rtlGetLocalXY() : this.el.getLocalXY();
    },
    
    unitizeBox: function(box) {
        if (this.getHierarchyState().rtl) {
            return Ext.dom.Element.rtlUnitizeBox(box); 
        } else {
            return this.callParent(arguments);
        } 
    },
    
    parseBox: function(box) {
        if (this.getHierarchyState().rtl) {
            return Ext.dom.Element.rtlParseBox(box); 
        } else {
            return this.callParent(arguments);
        }
    },

    initHierarchyState: function(hierarchyState) {
        this.callParent(arguments);
        var rtl = this.rtl;

        if (rtl !== undefined) {
            // unlike the other hierarchical properties which should always
            // be inherited from the hierarchy unless true, rtl should only
            // be inherited if undefined, that is if this component instance
            // does not have rtl specified as true or false.
            hierarchyState.rtl = rtl;
        }
    },

    /**
     * Returns true if this component's local coordinate system is rtl. For normal
     * components this equates to the value of isParentRtl().  Floaters are a bit different
     * because a floater's element can be a childNode of something other than its
     * parent component's element.  For floaters we have to read the dom to see if the
     * component's element's parentNode has a css direction value of "rtl".
     * @return {Boolean}
     * @private
     */
    isLocalRtl: function() {
        var me = this,
            rtl, offsetParent, doc;

        if (me.floating) {
            if (me._isOffsetParentRtl === undefined) {
                
                // position:fixed elements do not report an offsetParent, so fall back to parentNode
                offsetParent = this.el.dom.offsetParent || this.el.dom.parentNode;
                if (offsetParent) {
                    doc = document;
                    if (offsetParent === doc.documentElement) {
                        // the default offsetParent is the body in most browsers,
                        // in IE7 strict it is the document element.  If this is the case
                        // test the body's style, since its direction style is what
                        // determines if the page-level coordinate system is rtl.
                        offsetParent = doc.body;
                    }
                    me._isOffsetParentRtl =
                        Ext.fly(offsetParent, '_isLocalRtl').isStyle('direction', 'rtl');
                }
            }
            rtl = !!me._isOffsetParentRtl;
        } else {
            rtl = this.isParentRtl();
        }

        return rtl;
    },

    /**
     * Returns true if this component's parent container is rtl. Used by rtl positioning
     * methods to determine if the component should be positioned using a right-to-left
     * coordinate system.
     * @return {Boolean}
     * @private
     */
    isParentRtl: function() {
        var me = this,
            hierarchyState = me.getHierarchyState(),
            isRtl = false,
            myRtl;

        if (hierarchyState.hasOwnProperty('rtl')) {
            // Temporarily remove this component's rtl property so we can see what the rtl
            // value is on the prototype.  A component is only rtl positioned if it is
            // inside of an rtl coordinate system (if one of it's ancestors is rtl). We
            // can't just use ownerCt/floatParent hierarchyState, because components may
            // not have a container, but might still be part of a rtl coordinate system by
            // virtue of the viewport.  These components will inherit the correct rtl
            // value from the prototype becuase all hierarchy states inherit from
            // Ext.rootHierarchyState
            myRtl = hierarchyState.rtl;
            delete hierarchyState.rtl;
        }

        if (hierarchyState.rtl) {
            isRtl = true;
        }

        if (myRtl !== undefined) {
            // restore this component's original hierarchyState rtl property
            hierarchyState.rtl = myRtl;
        }

        return isRtl;
    },

    setLocalX: function(x) {
        return this.isLocalRtl() ? this.el.rtlSetLocalX(x) : this.el.setLocalX(x);
    },

    setLocalXY: function(x, y) {
        return this.isLocalRtl() ? this.el.rtlSetLocalXY(x, y) : this.el.setLocalXY(x, y);
    },
    
    isOppositeRootDirection: function(){
        return !this.getHierarchyState().rtl !== !Ext.rootHierarchyState.rtl;
    }
}, function() {
    Ext.on({
        ready: function() {
            // If the document or body has "direction:rtl" then we set the rtl flag in the
            // root hierarchy state so that the page-level coordinate system will be
            // right-based (similar to using a Viewport with "rtl: true").
            if ((Ext.fly(document.documentElement).isStyle('direction', 'rtl')) ||
                (Ext.getBody().isStyle('direction', 'rtl'))) {
                Ext.rootHierarchyState.rtl = true;
            }
        },
        single: true,
        priority: 1000
    });
});