/**
 * @class Ext.dd.ScrollManager
 *

Provides automatic scrolling of overflow regions in the page during drag operations.


 *

The ScrollManager configs will be used as the defaults for any scroll container registered with it,
 * but you can also override most of the configs per scroll container by adding a
 *
ddScrollConfig object to the target element that contains these properties: {@link #hthresh},
 * {@link #vthresh}, {@link #increment} and {@link #frequency}.  Example usage:
 *


var el = Ext.get('scroll-ct');
el.ddScrollConfig = {
    vthresh: 50,
    hthresh: -1,
    frequency: 100,
    increment: 200
};
Ext.dd.ScrollManager.register(el);

 *
Note: This class uses "Point Mode" and is untested in "Intersect Mode".
 * @singleton
 */

Ext.dd.ScrollManager = function(){
   
var ddm = Ext.dd.DragDropMgr;
   
var els = {};
   
var dragEl = null;
   
var proc = {};
   
   
var onStop = function(e){
        dragEl
= null;
        clearProc
();
   
};
   
   
var triggerRefresh = function(){
       
if(ddm.dragCurrent){
             ddm
.refreshCache(ddm.dragCurrent.groups);
       
}
   
};
   
   
var doScroll = function(){
       
if(ddm.dragCurrent){
           
var dds = Ext.dd.ScrollManager;
           
var inc = proc.el.ddScrollConfig ?
                      proc
.el.ddScrollConfig.increment : dds.increment;
           
if(!dds.animate){
               
if(proc.el.scroll(proc.dir, inc)){
                    triggerRefresh
();
               
}
           
}else{
                proc
.el.scroll(proc.dir, inc, true, dds.animDuration, triggerRefresh);
           
}
       
}
   
};
   
   
var clearProc = function(){
       
if(proc.id){
            clearInterval
(proc.id);
       
}
        proc
.id = 0;
        proc
.el = null;
        proc
.dir = "";
   
};
   
   
var startProc = function(el, dir){
        clearProc
();
        proc
.el = el;
        proc
.dir = dir;
       
var freq = (el.ddScrollConfig && el.ddScrollConfig.frequency) ?
                el
.ddScrollConfig.frequency : Ext.dd.ScrollManager.frequency;
        proc
.id = setInterval(doScroll, freq);
   
};
   
   
var onFire = function(e, isDrop){
       
if(isDrop || !ddm.dragCurrent){ return; }
       
var dds = Ext.dd.ScrollManager;
       
if(!dragEl || dragEl != ddm.dragCurrent){
            dragEl
= ddm.dragCurrent;
           
// refresh regions on drag start
            dds
.refreshCache();
       
}
       
       
var xy = Ext.lib.Event.getXY(e);
       
var pt = new Ext.lib.Point(xy[0], xy[1]);
       
for(var id in els){
           
var el = els[id], r = el._region;
           
var c = el.ddScrollConfig ? el.ddScrollConfig : dds;
           
if(r && r.contains(pt) && el.isScrollable()){
               
if(r.bottom - pt.y <= c.vthresh){
                   
if(proc.el != el){
                        startProc
(el, "down");
                   
}
                   
return;
               
}else if(r.right - pt.x <= c.hthresh){
                   
if(proc.el != el){
                        startProc
(el, "left");
                   
}
                   
return;
               
}else if(pt.y - r.top <= c.vthresh){
                   
if(proc.el != el){
                        startProc
(el, "up");
                   
}
                   
return;
               
}else if(pt.x - r.left <= c.hthresh){
                   
if(proc.el != el){
                        startProc
(el, "right");
                   
}
                   
return;
               
}
           
}
       
}
        clearProc
();
   
};
   
    ddm
.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
    ddm
.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
   
   
return {
       
/**
         * Registers new overflow element(s) to auto scroll
         * @param {Mixed/Array} el The id of or the element to be scrolled or an array of either
         */

       
register : function(el){
           
if(Ext.isArray(el)){
               
for(var i = 0, len = el.length; i < len; i++) {
                       
this.register(el[i]);
               
}
           
}else{
                el
= Ext.get(el);
                els
[el.id] = el;
           
}
       
},
       
       
/**
         * Unregisters overflow element(s) so they are no longer scrolled
         * @param {Mixed/Array} el The id of or the element to be removed or an array of either
         */

        unregister
: function(el){
           
if(Ext.isArray(el)){
               
for(var i = 0, len = el.length; i < len; i++) {
                       
this.unregister(el[i]);
               
}
           
}else{
                el
= Ext.get(el);
               
delete els[el.id];
           
}
       
},
       
       
/**
         * The number of pixels from the top or bottom edge of a container the pointer needs to be to
         * trigger scrolling (defaults to 25)
         * @type Number
         */

        vthresh
: 25,
       
/**
         * The number of pixels from the right or left edge of a container the pointer needs to be to
         * trigger scrolling (defaults to 25)
         * @type Number
         */

        hthresh
: 25,

       
/**
         * The number of pixels to scroll in each scroll increment (defaults to 50)
         * @type Number
         */

        increment
: 100,
       
       
/**
         * The frequency of scrolls in milliseconds (defaults to 500)
         * @type Number
         */

        frequency
: 500,
       
       
/**
         * True to animate the scroll (defaults to true)
         * @type Boolean
         */

        animate
: true,
       
       
/**
         * The animation duration in seconds -
         * MUST BE less than Ext.dd.ScrollManager.frequency! (defaults to .4)
         * @type Number
         */

        animDuration
: .4,
       
       
/**
         * Manually trigger a cache refresh.
         */

        refreshCache
: function(){
           
for(var id in els){
               
if(typeof els[id] == 'object'){ // for people extending the object prototype
                    els
[id]._region = els[id].getRegion();
               
}
           
}
       
}
   
};
}();