    /*!
     * Ext JS Library 3.3.0
     * Copyright(c) 2006-2010 Ext JS, Inc.
     * licensing@extjs.com
     * http://www.extjs.com/license
     */
    /**
     * @class Ext.ux.ToolbarDroppable
     * @extends Object
     * Plugin which allows items to be dropped onto a toolbar and be turned into new Toolbar items.
     * To use the plugin, you just need to provide a createItem implementation that takes the drop
     * data as an argument and returns an object that can be placed onto the toolbar. Example:
     *
     * new Ext.ux.ToolbarDroppable({
     *   createItem: function(data) {
     *     return new Ext.Button({text: data.text});
     *   }
     * });
     *
     * The afterLayout function can also be overridden, and is called after a new item has been
     * created and inserted into the Toolbar. Use this for any logic that needs to be run after
     * the item has been created.
     */
    Ext.ux.ToolbarDroppable = Ext.extend(Object, {
        /**
         * @constructor
         */
        constructor: function(config) {
          Ext.apply(this, config, {

          });
        },

        /**
         * Initializes the plugin and saves a reference to the toolbar
         * @param {Ext.Toolbar} toolbar The toolbar instance
         */
        init: function(toolbar) {
          /**
           * @property toolbar
           * @type Ext.Toolbar
           * The toolbar instance that this plugin is tied to
           */
          this.toolbar = toolbar;

          this.toolbar.on({
              scope : this,
              render: this.createDropTarget
          });
        },

        /**
         * Creates a drop target on the toolbar
         */
        createDropTarget: function() {
            /**
             * @property dropTarget
             * @type Ext.dd.DropTarget
             * The drop target attached to the toolbar instance
             */
            this.dropTarget = new Ext.dd.DropTarget(this.toolbar.getEl(), {
                notifyOver: this.notifyOver.createDelegate(this),
                notifyDrop: this.notifyDrop.createDelegate(this)
            });
        },

        /**
         * Adds the given DD Group to the drop target
         * @param {String} ddGroup The DD Group
         */
        addDDGroup: function(ddGroup) {
            this.dropTarget.addToGroup(ddGroup);
        },

        /**
         * Calculates the location on the toolbar to create the new sorter button based on the XY of the
         * drag event
         * @param {Ext.EventObject} e The event object
         * @return {Number} The index at which to insert the new button
         */
        calculateEntryIndex: function(e) {
            var entryIndex = 0,
                toolbar    = this.toolbar,
                items      = toolbar.items.items,
                count      = items.length,
                xTotal     = toolbar.getEl().getXY()[0],
                xHover     = e.getXY()[0] - xTotal;

            for (var index = 0; index < count; index++) {
                var item     = items[index],
                    width    = item.getEl().getWidth(),
                    midpoint = xTotal + width / 2;

                xTotal += width;

                if (xHover < midpoint) {
                    entryIndex = index;

                    break;
                } else {
                    entryIndex = index + 1;
                }
            }

            return entryIndex;
        },

        /**
         * Returns true if the drop is allowed on the drop target. This function can be overridden
         * and defaults to simply return true
         * @param {Object} data Arbitrary data from the drag source
         * @return {Boolean} True if the drop is allowed
         */
        canDrop: function(data) {
            return true;
        },

        /**
         * Custom notifyOver method which will be used in the plugin's internal DropTarget
         * @return {String} The CSS class to add
         */
        notifyOver: function(dragSource, event, data) {
            return this.canDrop.apply(this, arguments) ? this.dropTarget.dropAllowed : this.dropTarget.dropNotAllowed;
        },

        /**
         * Called when the drop has been made. Creates the new toolbar item, places it at the correct location
         * and calls the afterLayout callback.
         */
        notifyDrop: function(dragSource, event, data) {
            var canAdd = this.canDrop(dragSource, event, data),
                tbar   = this.toolbar;

            if (canAdd) {
                var entryIndex = this.calculateEntryIndex(event);

                tbar.insert(entryIndex, this.createItem(data));
                tbar.doLayout();

                this.afterLayout();
            }

            return canAdd;
        },

        /**
         * Creates the new toolbar item based on drop data. This method must be implemented by the plugin instance
         * @param {Object} data Arbitrary data from the drop
         * @return {Mixed} An item that can be added to a toolbar
         */
        createItem: function(data) {
            throw new Error("The createItem method must be implemented in the ToolbarDroppable plugin");
        },

        /**
         * Called after a new button has been created and added to the toolbar. Add any required cleanup logic here
         */
        afterLayout: Ext.emptyFn
    });