    /*
     * This is a derivative of the similarly named class in the YUI Library.
     * The original license:
     * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
     * Code licensed under the BSD License:
     * http://developer.yahoo.net/yui/license.txt
     */

    /**
     * @class Ext.dd.DDProxy
     * A DragDrop implementation that inserts an empty, bordered div into
     * the document that follows the cursor during drag operations.  At the time of
     * the click, the frame div is resized to the dimensions of the linked html
     * element, and moved to the exact location of the linked element.
     *
     * References to the "frame" element refer to the single proxy element that
     * was created to be dragged in place of all DDProxy elements on the
     * page.
     *
     * @extends Ext.dd.DD
     * @constructor
     * @param {String} id the id of the linked html element
     * @param {String} sGroup the group of related DragDrop objects
     * @param {object} config an object containing configurable attributes
     *                Valid properties for DDProxy in addition to those in DragDrop:
     *                   resizeFrame, centerFrame, dragElId
     */
    Ext.define('Ext.dd.DDProxy', {
        extend: 'Ext.dd.DD',

        statics: {
            /**
             * The default drag frame div id
             * @property Ext.dd.DDProxy.dragElId
             * @type String
             * @static
             */
            dragElId: "ygddfdiv"
        },

        constructor: function(id, sGroup, config) {
            if (id) {
                this.init(id, sGroup, config);
                this.initFrame();
            }
        },

        /**
         * By default we resize the drag frame to be the same size as the element
         * we want to drag (this is to get the frame effect).  We can turn it off
         * if we want a different behavior.
         * @property resizeFrame
         * @type boolean
         */
        resizeFrame: true,

        /**
         * By default the frame is positioned exactly where the drag element is, so
         * we use the cursor offset provided by Ext.dd.DD.  Another option that works only if
         * you do not have constraints on the obj is to have the drag frame centered
         * around the cursor.  Set centerFrame to true for this effect.
         * @property centerFrame
         * @type boolean
         */
        centerFrame: false,

        /**
         * Creates the proxy element if it does not yet exist
         * @method createFrame
         */
        createFrame: function() {
            var self = this;
            var body = document.body;

            if (!body || !body.firstChild) {
                setTimeout( function() { self.createFrame(); }, 50 );
                return;
            }

            var div = this.getDragEl();

            if (!div) {
                div    = document.createElement("div");
                div.id = this.dragElId;
                var s  = div.style;

                s.position   = "absolute";
                s.visibility = "hidden";
                s.cursor     = "move";
                s.border     = "2px solid #aaa";
                s.zIndex     = 999;

                // appendChild can blow up IE if invoked prior to the window load event
                // while rendering a table.  It is possible there are other scenarios
                // that would cause this to happen as well.
                body.insertBefore(div, body.firstChild);
            }
        },

        /**
         * Initialization for the drag frame element.  Must be called in the
         * constructor of all subclasses
         * @method initFrame
         */
        initFrame: function() {
            this.createFrame();
        },

        applyConfig: function() {
            this.callParent();

            this.resizeFrame = (this.config.resizeFrame !== false);
            this.centerFrame = (this.config.centerFrame);
            this.setDragElId(this.config.dragElId || Ext.dd.DDProxy.dragElId);
        },

        /**
         * Resizes the drag frame to the dimensions of the clicked object, positions
         * it over the object, and finally displays it
         * @method showFrame
         * @param {int} iPageX X click position
         * @param {int} iPageY Y click position
         * @private
         */
        showFrame: function(iPageX, iPageY) {
            var el = this.getEl();
            var dragEl = this.getDragEl();
            var s = dragEl.style;

            this._resizeProxy();

            if (this.centerFrame) {
                this.setDelta( Math.round(parseInt(s.width,  10)/2),
                               Math.round(parseInt(s.height, 10)/2) );
            }

            this.setDragElPos(iPageX, iPageY);

            Ext.fly(dragEl).show();
        },

        /**
         * The proxy is automatically resized to the dimensions of the linked
         * element when a drag is initiated, unless resizeFrame is set to false
         * @method _resizeProxy
         * @private
         */
        _resizeProxy: function() {
            if (this.resizeFrame) {
                var el = this.getEl();
                Ext.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
            }
        },

        // overrides Ext.dd.DragDrop
        b4MouseDown: function(e) {
            var x = e.getPageX();
            var y = e.getPageY();
            this.autoOffset(x, y);
            this.setDragElPos(x, y);
        },

        // overrides Ext.dd.DragDrop
        b4StartDrag: function(x, y) {
            // show the drag frame
            this.showFrame(x, y);
        },

        // overrides Ext.dd.DragDrop
        b4EndDrag: function(e) {
            Ext.fly(this.getDragEl()).hide();
        },

        // overrides Ext.dd.DragDrop
        // By default we try to move the element to the last location of the frame.
        // This is so that the default behavior mirrors that of Ext.dd.DD.
        endDrag: function(e) {

            var lel = this.getEl();
            var del = this.getDragEl();

            // Show the drag frame briefly so we can get its position
            del.style.visibility = "";

            this.beforeMove();
            // Hide the linked element before the move to get around a Safari
            // rendering bug.
            lel.style.visibility = "hidden";
            Ext.dd.DDM.moveToEl(lel, del);
            del.style.visibility = "hidden";
            lel.style.visibility = "";

            this.afterDrag();
        },

        beforeMove : function(){

        },

        afterDrag : function(){

        },

        toString: function() {
            return ("DDProxy " + this.id);
        }

    });