/*
 * 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
 */
 
/**
 * 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.
 */
Ext.define('Ext.dd.DDProxy', {
    extend: 'Ext.dd.DD',
 
    statics: {
        /**
         * The default drag frame div id
         * @static
         */
        dragElId: "ygddfdiv"
    },
 
    /**
     * Creates new DDProxy.
     * @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
     */
    constructor: function(id, sGroup, config) {
        if (id) {
            this.init(id, sGroup, config);
            this.initFrame();
        }
    },
 
    /**
     * @property {Boolean} resizeFrame
     * 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.
     */
    resizeFrame: true,
 
    /**
     * @property {Boolean} centerFrame
     * 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.
     */
    centerFrame: false,
 
    /**
     * Creates the proxy element if it does not yet exist
     */
    createFrame: function() {
        var self = this,
            body = document.body,
            div,
            s;
 
        if (!body || !body.firstChild) {
            Ext.defer(function() {
                self.createFrame();
            }, 50);
 
            return;
        }
 
        div = this.getDragEl();
 
        if (!div) {
            div = document.createElement("div");
            div.id = this.dragElId;
            div.setAttribute('role', 'presentation');
            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
     */
    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
     * @param {Number} iPageX X click position
     * @param {Number} iPageY Y click position
     * @private
     */
    showFrame: function(iPageX, iPageY) {
        var me = this,
            dragEl = me.getDragEl(),
            s = dragEl.style;
 
        me._resizeProxy();
 
        if (me.centerFrame) {
            me.setDelta(Math.round(parseInt(s.width, 10) / 2),
                        Math.round(parseInt(s.height, 10) / 2));
        }
 
        me.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
     * @private
     */
    _resizeProxy: function() {
        var el;
        
        if (this.resizeFrame) {
            el = this.getEl();
 
            Ext.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
        }
    },
 
    // overrides Ext.dd.DragDrop
    b4MouseDown: function(e) {
        var xy = e.getXY(),
            x = xy[0],
            y = xy[1];
 
        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(),
            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);
    }
});