/**
 * @class Ext.Element
 */

(function(){
var D = Ext.lib.Dom,
        LEFT
= "left",
        RIGHT
= "right",
        TOP
= "top",
        BOTTOM
= "bottom",
        POSITION
= "position",
        STATIC
= "static",
        RELATIVE
= "relative",
        AUTO
= "auto",
        ZINDEX
= "z-index";

function animTest(args, animate, i) {
       
return this.preanim && !!animate ? this.preanim(args, i) : false        
}

Ext.Element.addMethods({
       
/**
      * Gets the current X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
      * @return {Number} The X position of the element
      */

    getX
: function(){
       
return D.getX(this.dom);
   
},

   
/**
      * Gets the current Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
      * @return {Number} The Y position of the element
      */

    getY
: function(){
       
return D.getY(this.dom);
   
},

   
/**
      * Gets the current position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
      * @return {Array} The XY position of the element
      */

    getXY
: function(){
       
return D.getXY(this.dom);
   
},

   
/**
      * Returns the offsets of this element from the passed element. Both element must be part of the DOM tree and not have display:none to have page coordinates.
      * @param {Mixed} element The element to get the offsets from.
      * @return {Array} The XY page offsets (e.g. [100, -200])
      */

    getOffsetsTo
: function(el){
       
var o = this.getXY(),
                e
= Ext.fly(el, '_internal').getXY();
       
return [o[0]-e[0],o[1]-e[1]];
   
},

   
/**
     * Sets the X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
     * @param {Number} The X position of the element
     * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
     * @return {Ext.Element} this
     */

    setX
: function(x, animate){            
           
return this.setXY([x, this.getY()], animTest.call(this, arguments, animate, 1));
   
},

   
/**
     * Sets the Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
     * @param {Number} The Y position of the element
     * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
     * @return {Ext.Element} this
     */

    setY
: function(y, animate){            
           
return this.setXY([this.getX(), y], animTest.call(this, arguments, animate, 1));
   
},

   
/**
     * Sets the element's left position directly using CSS style (instead of {@link #setX}).
     * @param {String} left The left CSS property value
     * @return {Ext.Element} this
     */

    setLeft
: function(left){
       
this.setStyle(LEFT, this.addUnits(left));
       
return this;
   
},

   
/**
     * Sets the element's top position directly using CSS style (instead of {@link #setY}).
     * @param {String} top The top CSS property value
     * @return {Ext.Element} this
     */

    setTop
: function(top){
       
this.setStyle(TOP, this.addUnits(top));
       
return this;
   
},

   
/**
     * Sets the element's CSS right style.
     * @param {String} right The right CSS property value
     * @return {Ext.Element} this
     */

    setRight
: function(right){
       
this.setStyle(RIGHT, this.addUnits(right));
       
return this;
   
},

   
/**
     * Sets the element's CSS bottom style.
     * @param {String} bottom The bottom CSS property value
     * @return {Ext.Element} this
     */

    setBottom
: function(bottom){
       
this.setStyle(BOTTOM, this.addUnits(bottom));
       
return this;
   
},

   
/**
     * Sets the position of the element in page coordinates, regardless of how the element is positioned.
     * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
     * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
     * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
     * @return {Ext.Element} this
     */

    setXY
: function(pos, animate){
           
var me = this;
       
if(!animate || !me.anim){
            D
.setXY(me.dom, pos);
       
}else{
            me
.anim({points: {to: pos}}, me.preanim(arguments, 1), 'motion');
       
}
       
return me;
   
},

   
/**
     * Sets the position of the element in page coordinates, regardless of how the element is positioned.
     * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
     * @param {Number} x X value for new position (coordinates are page-based)
     * @param {Number} y Y value for new position (coordinates are page-based)
     * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
     * @return {Ext.Element} this
     */

    setLocation
: function(x, y, animate){
       
return this.setXY([x, y], animTest.call(this, arguments, animate, 2));
   
},

   
/**
     * Sets the position of the element in page coordinates, regardless of how the element is positioned.
     * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
     * @param {Number} x X value for new position (coordinates are page-based)
     * @param {Number} y Y value for new position (coordinates are page-based)
     * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
     * @return {Ext.Element} this
     */

    moveTo
: function(x, y, animate){
       
return this.setXY([x, y], animTest.call(this, arguments, animate, 2));        
   
},    
   
   
/**
     * Gets the left X coordinate
     * @param {Boolean} local True to get the local css position instead of page coordinate
     * @return {Number}
     */

    getLeft
: function(local){
           
return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0;
   
},

   
/**
     * Gets the right X coordinate of the element (element X position + element width)
     * @param {Boolean} local True to get the local css position instead of page coordinate
     * @return {Number}
     */

    getRight
: function(local){
           
var me = this;
           
return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0;
   
},

   
/**
     * Gets the top Y coordinate
     * @param {Boolean} local True to get the local css position instead of page coordinate
     * @return {Number}
     */

    getTop
: function(local) {
           
return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0;
   
},

   
/**
     * Gets the bottom Y coordinate of the element (element Y position + element height)
     * @param {Boolean} local True to get the local css position instead of page coordinate
     * @return {Number}
     */

    getBottom
: function(local){
           
var me = this;
           
return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0;
   
},

   
/**
    * Initializes positioning on this element. If a desired position is not passed, it will make the
    * the element positioned relative IF it is not already positioned.
    * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
    * @param {Number} zIndex (optional) The zIndex to apply
    * @param {Number} x (optional) Set the page X position
    * @param {Number} y (optional) Set the page Y position
    */

    position
: function(pos, zIndex, x, y){
           
var me = this;
           
       
if(!pos && me.isStyle(POSITION, STATIC)){          
            me
.setStyle(POSITION, RELATIVE);          
       
} else if(pos) {
            me
.setStyle(POSITION, pos);
       
}
       
if(zIndex){
            me
.setStyle(ZINDEX, zIndex);
       
}
       
if(x || y) me.setXY([x || false, y || false]);
   
},

   
/**
    * Clear positioning back to the default when the document was loaded
    * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
    * @return {Ext.Element} this
     */

    clearPositioning
: function(value){
        value
= value || '';
       
this.setStyle({
            left
: value,
            right
: value,
            top
: value,
            bottom
: value,
           
"z-index" : "",
            position
: STATIC
       
});
       
return this;
   
},

   
/**
    * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
    * snapshot before performing an update and then restoring the element.
    * @return {Object}
    */

    getPositioning
: function(){
       
var l = this.getStyle(LEFT);
       
var t = this.getStyle(TOP);
       
return {
           
"position" : this.getStyle(POSITION),
           
"left" : l,
           
"right" : l ? "" : this.getStyle(RIGHT),
           
"top" : t,
           
"bottom" : t ? "" : this.getStyle(BOTTOM),
           
"z-index" : this.getStyle(ZINDEX)
       
};
   
},
   
   
/**
    * Set positioning with an object returned by getPositioning().
    * @param {Object} posCfg
    * @return {Ext.Element} this
     */

    setPositioning
: function(pc){
           
var me = this,
                style
= me.dom.style;
               
        me
.setStyle(pc);
       
       
if(pc.right == AUTO){
            style
.right = "";
       
}
       
if(pc.bottom == AUTO){
            style
.bottom = "";
       
}
       
       
return me;
   
},    
       
   
/**
     * Translates the passed page coordinates into left/top css values for this element
     * @param {Number/Array} x The page x or an array containing [x, y]
     * @param {Number} y (optional) The page y, required if x is not an array
     * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
     */

    translatePoints
: function(x, y){                
            y
= isNaN(x[1]) ? y : x[1];
        x
= isNaN(x[0]) ? x : x[0];
       
var me = this,
                relative
= me.isStyle(POSITION, RELATIVE),
                o
= me.getXY(),
                l
= parseInt(me.getStyle(LEFT), 10),
                t
= parseInt(me.getStyle(TOP), 10);
       
        l
= !isNaN(l) ? l : (relative ? 0 : me.dom.offsetLeft);
        t
= !isNaN(t) ? t : (relative ? 0 : me.dom.offsetTop);        

       
return {left: (x - o[0] + l), top: (y - o[1] + t)};
   
},
   
    animTest
: animTest
});
})();