    /**
     * @class Ext.Element
     */

    // special markup used throughout Ext when box wrapping elements
    Ext.Element.boxMarkup = '';

    Ext.Element.addMethods(function(){
        var INTERNAL = "_internal",
            pxMatch = /(\d+)px/;
        return {
            /**
             * More flexible version of {@link #setStyle} for setting style properties.
             * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
             * a function which returns such a specification.
             * @return {Ext.Element} this
             */
            applyStyles : function(style){
                Ext.DomHelper.applyStyles(this.dom, style);
                return this;
            },

            /**
             * Returns an object with properties matching the styles requested.
             * For example, el.getStyles('color', 'font-size', 'width') might return
             * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
             * @param {String} style1 A style name
             * @param {String} style2 A style name
             * @param {String} etc.
             * @return {Object} The style object
             */
            getStyles : function(){
                var ret = {};
                Ext.each(arguments, function(v) {
                   ret[v] = this.getStyle(v);
                },
                this);
                return ret;
            },

            // deprecated
            getStyleSize : function(){
                var me = this,
                    w,
                    h,
                    d = this.dom,
                    s = d.style;
                if(s.width && s.width != 'auto'){
                    w = parseInt(s.width, 10);
                    if(me.isBorderBox()){
                       w -= me.getFrameWidth('lr');
                    }
                }
                if(s.height && s.height != 'auto'){
                    h = parseInt(s.height, 10);
                    if(me.isBorderBox()){
                       h -= me.getFrameWidth('tb');
                    }
                }
                return {width: w || me.getWidth(true), height: h || me.getHeight(true)};
            },

            // private  ==> used by ext full
            setOverflow : function(v){
                var dom = this.dom;
                if(v=='auto' && Ext.isMac && Ext.isGecko2){ // work around stupid FF 2.0/Mac scroll bar bug
                    dom.style.overflow = 'hidden';
                    (function(){dom.style.overflow = 'auto';}).defer(1);
                }else{
                    dom.style.overflow = v;
                }
            },

           /**
            * Wraps the specified element with a special 9 element markup/CSS block that renders by default as
            * a gray container with a gradient background, rounded corners and a 4-way shadow.
            * This special markup is used throughout Ext when box wrapping elements ({@link Ext.Button},
            * {@link Ext.Panel} when {@link Ext.Panel#frame frame=true}, {@link Ext.Window}).  The markup
            * is of this form:
            *
        Ext.Element.boxMarkup =
        '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div>
         <div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div>
         <div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
            *
            * Example usage:
            *
        // Basic box wrap
        Ext.get("foo").boxWrap();

        // You can also add a custom class and use CSS inheritance rules to customize the box look.
        // 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example
        // for how to create a custom box wrap style.
        Ext.get("foo").boxWrap().addClass("x-box-blue");
            *
            * @param {String} class (optional) A base CSS class to apply to the containing wrapper element
            * (defaults to 'x-box'). Note that there are a number of CSS rules that are dependent on
            * this name to make the overall effect work, so if you supply an alternate base class, make sure you
            * also supply all of the necessary rules.
            * @return {Ext.Element} The outermost wrapping element of the created box structure.
            */
            boxWrap : function(cls){
                cls = cls || 'x-box';
                var el = Ext.get(this.insertHtml("beforeBegin", "" + String.format(Ext.Element.boxMarkup, cls) + ""));        //String.format(''+Ext.Element.boxMarkup+'', cls)));
                Ext.DomQuery.selectNode('.' + cls + '-mc', el.dom).appendChild(this.dom);
                return el;
            },

            /**
             * Set the size of this Element. If animation is true, both width and height will be animated concurrently.
             * @param {Mixed} width The new width. This may be one of:
             * A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).
             * A String used to set the CSS width style. Animation may not be used.
             * A size object in the format {width: widthValue, height: heightValue}.
             *
             * @param {Mixed} height The new height. This may be one of:
             * A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels).
             * A String used to set the CSS height style. Animation may not be used.
             *
             * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
             * @return {Ext.Element} this
             */
            setSize : function(width, height, animate){
                var me = this;
                if(Ext.isObject(width)){ // in case of object from getSize()
                    height = width.height;
                    width = width.width;
                }
                width = me.adjustWidth(width);
                height = me.adjustHeight(height);
                if(!animate || !me.anim){
                    me.dom.style.width = me.addUnits(width);
                    me.dom.style.height = me.addUnits(height);
                }else{
                    me.anim({width: {to: width}, height: {to: height}}, me.preanim(arguments, 2));
                }
                return me;
            },

            /**
             * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
             * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
             * if a height has not been set using CSS.
             * @return {Number}
             */
            getComputedHeight : function(){
                var me = this,
                    h = Math.max(me.dom.offsetHeight, me.dom.clientHeight);
                if(!h){
                    h = parseInt(me.getStyle('height'), 10) || 0;
                    if(!me.isBorderBox()){
                        h += me.getFrameWidth('tb');
                    }
                }
                return h;
            },

            /**
             * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
             * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
             * if a width has not been set using CSS.
             * @return {Number}
             */
            getComputedWidth : function(){
                var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
                if(!w){
                    w = parseInt(this.getStyle('width'), 10) || 0;
                    if(!this.isBorderBox()){
                        w += this.getFrameWidth('lr');
                    }
                }
                return w;
            },

            /**
             * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
             for more information about the sides.
             * @param {String} sides
             * @return {Number}
             */
            getFrameWidth : function(sides, onlyContentBox){
                return onlyContentBox && this.isBorderBox() ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
            },

            /**
             * Sets up event handlers to add and remove a css class when the mouse is over this element
             * @param {String} className
             * @return {Ext.Element} this
             */
            addClassOnOver : function(className){
                this.hover(
                    function(){
                        Ext.fly(this, INTERNAL).addClass(className);
                    },
                    function(){
                        Ext.fly(this, INTERNAL).removeClass(className);
                    }
                );
                return this;
            },

            /**
             * Sets up event handlers to add and remove a css class when this element has the focus
             * @param {String} className
             * @return {Ext.Element} this
             */
            addClassOnFocus : function(className){
                this.on("focus", function(){
                    Ext.fly(this, INTERNAL).addClass(className);
                }, this.dom);
                this.on("blur", function(){
                    Ext.fly(this, INTERNAL).removeClass(className);
                }, this.dom);
                return this;
            },

            /**
             * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
             * @param {String} className
             * @return {Ext.Element} this
             */
            addClassOnClick : function(className){
                var dom = this.dom;
                this.on("mousedown", function(){
                    Ext.fly(dom, INTERNAL).addClass(className);
                    var d = Ext.getDoc(),
                        fn = function(){
                            Ext.fly(dom, INTERNAL).removeClass(className);
                            d.removeListener("mouseup", fn);
                        };
                    d.on("mouseup", fn);
                });
                return this;
            },

            /**
             * Returns the dimensions of the element available to lay content out in.
             * If the element (or any ancestor element) has CSS style display : none, the dimensions will be zero.
             * example:
            var vpSize = Ext.getBody().getViewSize();

            // all Windows created afterwards will have a default value of 90% height and 95% width
            Ext.Window.override({
                width: vpSize.width * 0.9,
                height: vpSize.height * 0.95
            });
            // To handle window resizing you would have to hook onto onWindowResize.

             * @param {Boolean} contentBox True to return the W3 content box within the padding area of the element. False
             * or omitted to return the full area of the element within the border. See http://www.w3.org/TR/CSS2/box.html
             * @return {Object} An object containing the elements's area: {width: <element width>, height: <element height>}
             */
            getViewSize : function(contentBox){
                var doc = document,
                    me = this,
                    d = me.dom,
                    extdom = Ext.lib.Dom,
                    isDoc = (d == doc || d == doc.body),
                    isBB, w, h, tbBorder = 0, lrBorder = 0,
                    tbPadding = 0, lrPadding = 0;
                if (isDoc) {
                    return { width: extdom.getViewWidth(), height: extdom.getViewHeight() };
                }
                isBB = me.isBorderBox();
                tbBorder = me.getBorderWidth('tb');
                lrBorder = me.getBorderWidth('lr');
                tbPadding = me.getPadding('tb');
                lrPadding = me.getPadding('lr');

                // Width calcs
                // Try the style first, then clientWidth, then offsetWidth
                if (w = me.getStyle('width').match(pxMatch)){
                    if ((w = parseInt(w[1], 10)) && isBB){
                        // Style includes the padding and border if isBB
                        w -= (lrBorder + lrPadding);
                    }
                    if (!contentBox){
                        w += lrPadding;
                    }
                } else {
                    if (!(w = d.clientWidth) && (w = d.offsetWidth)){
                        w -= lrBorder;
                    }
                    if (w && contentBox){
                        w -= lrPadding;
                    }
                }

                // Height calcs
                // Try the style first, then clientHeight, then offsetHeight
                if (h = me.getStyle('height').match(pxMatch)){
                    if ((h = parseInt(h[1], 10)) && isBB){
                        // Style includes the padding and border if isBB
                        h -= (tbBorder + tbPadding);
                    }
                    if (!contentBox){
                        h += tbPadding;
                    }
                } else {
                    if (!(h = d.clientHeight) && (h = d.offsetHeight)){
                        h -= tbBorder;
                    }
                    if (h && contentBox){
                        h -= tbPadding;
                    }
                }

                return {
                    width : w,
                    height : h
                };
            },

            /**
             * Returns the size of the element.
             * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
             * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
             */
            getSize : function(contentSize){
                return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
            },

            /**
             * Forces the browser to repaint this element
             * @return {Ext.Element} this
             */
            repaint : function(){
                var dom = this.dom;
                this.addClass("x-repaint");
                setTimeout(function(){
                    Ext.fly(dom).removeClass("x-repaint");
                }, 1);
                return this;
            },

            /**
             * Disables text selection for this element (normalized across browsers)
             * @return {Ext.Element} this
             */
            unselectable : function(){
                this.dom.unselectable = "on";
                return this.swallowEvent("selectstart", true).
                            applyStyles("-moz-user-select:none;-khtml-user-select:none;").
                            addClass("x-unselectable");
            },

            /**
             * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
             * then it returns the calculated width of the sides (see getPadding)
             * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
             * @return {Object/Number}
             */
            getMargins : function(side){
                var me = this,
                    key,
                    hash = {t:"top", l:"left", r:"right", b: "bottom"},
                    o = {};

                if (!side) {
                    for (key in me.margins){
                        o[hash[key]] = parseInt(me.getStyle(me.margins[key]), 10) || 0;
                    }
                    return o;
                } else {
                    return me.addStyles.call(me, side, me.margins);
                }
            }
        };
    }());