/**
 * @class Ext.scroll.DomScroller
 * @private
 */
Ext.define('Ext.scroll.DomScroller', {
    extend: 'Ext.scroll.Scroller',
    alias: 'scroller.dom',
 
    isDomScroller: true,
 
    _spacerCls: Ext.baseCSSPrefix +  'domscroller-spacer',
 
    getMaxPosition: function() {
        var element = this.getElement(),
            x = 0,
            y = 0,
            dom;
 
        if (element && !element.destroyed) {
            dom = element.dom;
            x = dom.scrollWidth - dom.clientWidth;
            y = dom.scrollHeight - dom.clientHeight;
        }
 
        return {
            x: x,
            y: y
        };
    },
 
    getMaxUserPosition: function() {
        var me = this,
            element = me.getElement(),
            x = 0,
            y = 0,
            dom;
 
        if (element && !element.destroyed) {
            dom = element.dom;
            if (me.getX()) {
                x = dom.scrollWidth - dom.clientWidth;
            }
            if (me.getY()) {
                y = dom.scrollHeight - dom.clientHeight;
            }
        }
 
        return {
            x: x,
            y: y
        };
    },
 
    getPosition: function() {
        var element = this.getElement(),
            x = 0,
            y = 0,
            position;
 
        if (element && !element.destroyed) {
            position = this.getElementScroll(element);
            x = position.left;
            y = position.top;
        }
 
        return {
            x: x,
            y: y
        };
    },
 
    getSize: function() {
        var element = this.getElement(),
            size, dom;
 
        if (element && !element.destroyed) {
            dom = element.dom;
            size = {
                x: dom.scrollWidth,
                y: dom.scrollHeight
            };
        } else {
            size = {
                x: 0,
                y: 0
            };
        }
 
        return size;
    },
 
    setSize: function(size) {
        var me = this,
            element = me.getElement(),
            spacer, x, y;
 
        if (element) {
            spacer = me.getSpacer();
 
            // Typically a dom scroller simply assumes the scroll size dictated by its content.
            // In some cases, however, it is necessary to be able to manipulate this scroll size
            // (infinite lists for example).  This method positions a 1x1 px spacer element
            // within the scroller element to set a specific scroll size.
 
            if (size == null) {
                spacer.hide();
            } else {
                if (typeof size === 'number') {
                    x = size;
                    y = size;
                } else {
                    x = size.x || 0;
                    y = size.y || 0;
                }
 
                // Subtract spacer size from coordinates (spacer is always 1x1 px in size)
                if (> 0) {
                    x -= 1;
                }
                if (> 0) {
                    y -= 1;
                }
 
                me.setSpacerXY(spacer, x, y);
                spacer.show();
            }
        }
    },
 
    updateElement: function(element, oldElement) {
        this.initXStyle();
        this.initYStyle();
        this.callParent([element, oldElement]);
    },
 
    updateX: function(x) {
        this.initXStyle();
    },
 
    updateY: function(y) {
        this.initYStyle();
    },
 
    privates: {
        doScrollTo: function(x, y, animate) {
            var me = this,
                element = me.getElement(),
                maxPosition, dom, to, xInf, yInf;
 
            if (element && !element.destroyed) {
                dom = this.getElement().dom;
 
                xInf = (=== Infinity);
                yInf = (=== Infinity);
 
                if (xInf || yInf) {
                    maxPosition = me.getMaxPosition();
                    if (xInf) {
                        x = maxPosition.x;
                    }
                    if (yInf) {
                        y = maxPosition.y;
                    }
                }
 
                x = me.convertX(x);
 
                if (animate) {
                    to = {};
 
                    if (!= null) {
                        to.scrollTop = y;
                    }
 
                    if (!= null) {
                        to.scrollLeft = x;
                    }
 
                    element.animate(Ext.mergeIf({
                        to: {
                            scrollTop: y,
                            scrollLeft: x
                        }
                    }, animate));
                } else {
                    if (!= null) {
                        dom.scrollTop = y;
                    }
                    if (!= null) {
                        dom.scrollLeft = x;
                    }
                }
            }
        },
 
        // rtl hook
        getElementScroll: function(element) {
            return element.getScroll();
        },
 
        getSpacer: function() {
            var me = this,
                spacer = me._spacer,
                element;
 
            // In some cases (e.g. infinite lists) we need to be able to tell the scroller
            // to have a specific size, regardless of its contents.  This creates a spacer
            // element which can then be absolutely positioned to affect the element's
            // scroll size.
            if (!spacer) {
                element = me.getElement();
                spacer = me._spacer = element.createChild({
                    cls: me._spacerCls
                });
 
                spacer.setVisibilityMode(2); // 'display' visibilityMode
 
                // make sure the element is positioned if it is not already.  This ensures
                // that the spacer's position will affect the element's scroll size
                element.position();
            }
 
            return spacer;
        },
 
        // rtl hook
        setSpacerXY: function(spacer, x, y) {
            spacer.setLocalXY(x, y);
        },
 
        stopAnimation: function() {
            var anim = this.getElement().getActiveAnimation();
            if (anim) {
                anim.end();
            }
        }
    }
});