/**
 * @class Ext.util.ComponentDragger
 * @extends Ext.dd.DragTracker
 * <p>A subclass of Ext.dd.DragTracker which handles dragging any Component.</p>
 * <p>This is configured with a Component to be made draggable, and a config object for the
 * {@link Ext.dd.DragTracker} class.</p>
 * <p>A {@link #} delegate may be provided which may be either the element to use as the mousedown target
 * or a {@link Ext.DomQuery} selector to activate multiple mousedown targets.</p>
 * @constructor Create a new ComponentTracker
 * @param {object} comp The Component to provide dragging for.
 * @param {object} config The config object
 */

Ext.define('Ext.util.ComponentDragger', {

    /**
     * @cfg {Boolean} constrain
     * Specify as <code>true</code> to constrain the Component to within the bounds of the {@link #constrainTo} region.
     */


    /**
     * @cfg {String/Element} delegate
     * Optional. <p>A {@link Ext.DomQuery DomQuery} selector which identifies child elements within the Component's encapsulating
     * Element which are the drag handles. This limits dragging to only begin when the matching elements are mousedowned.</p>
     * <p>This may also be a specific child element within the Component's encapsulating element to use as the drag handle.</p>
     */


    /**
     * @cfg {Boolean} constrainDelegate
     * Specify as <code>true</code> to constrain the drag handles within the {@link constrainTo} region.
     */


    extend
: 'Ext.dd.DragTracker',

    autoStart
: 500,

    constructor
: function(comp, config) {
       
this.comp = comp;
       
this.initialConstrainTo = config.constrainTo;
       
this.callParent([ config ]);
   
},

    onStart
: function(e) {
       
var me = this,
            comp
= me.comp;

       
// Cache the start [X, Y] array
       
this.startPosition = comp.getPosition();

       
// If client Component has a ghost method to show a lightweight version of itself
       
// then use that as a drag proxy unless configured to liveDrag.
       
if (comp.ghost && !comp.liveDrag) {
             me
.proxy = comp.ghost();
             me
.dragTarget = me.proxy.header.el;
       
}

       
// Set the constrainTo Region before we start dragging.
       
if (me.constrain || me.constrainDelegate) {
            me
.constrainTo = me.calculateConstrainRegion();
       
}
   
},

    calculateConstrainRegion
: function() {
       
var me = this,
            comp
= me.comp,
            c
= me.initialConstrainTo,
            delegateRegion
,
            elRegion
,
            shadowSize
= comp.el.shadow ? comp.el.shadow.offset : 0;

       
// The configured constrainTo might be a Region or an element
       
if (!(c instanceof Ext.util.Region)) {
            c
=  Ext.fly(c).getViewRegion();
       
}

       
// Reduce the constrain region to allow for shadow
       
if (shadowSize) {
            c
.adjust(0, -shadowSize, -shadowSize, shadowSize);
       
}

       
// If they only want to constrain the *delegate* to within the constrain region,
       
// adjust the region to be larger based on the insets of the delegate from the outer
       
// edges of the Component.
       
if (!me.constrainDelegate) {
            delegateRegion
= Ext.fly(me.dragTarget).getRegion();
            elRegion
= me.proxy ? me.proxy.el.getRegion() : comp.el.getRegion();

            c
.adjust(
                delegateRegion
.top - elRegion.top,
                delegateRegion
.right - elRegion.right,
                delegateRegion
.bottom - elRegion.bottom,
                delegateRegion
.left - elRegion.left
           
);
       
}
       
return c;
   
},

   
// Move either the ghost Component or the target Component to its new position on drag
    onDrag
: function(e) {
       
var me = this,
            comp
= (me.proxy && !me.comp.liveDrag) ? me.proxy : me.comp,
            offset
= me.getOffset(me.constrain || me.constrainDelegate ? 'dragTarget' : null);

        comp
.setPosition.apply(comp, [me.startPosition[0] + offset[0], me.startPosition[1] + offset[1]]);
   
},

    onEnd
: function(e) {
       
if (this.proxy && !this.comp.liveDrag) {
           
this.comp.unghost();
       
}
   
}
});