/**
 * This class is used for {@link Ext.grid.Grid grid} cells that contain a child
 * {@link Ext.Component} or {@link Ext.Widget}. This cell type is typically used by
 * specifying {@link Ext.grid.column.Widget} column type.
 *
 * {@link Ext.grid.Row Rows} create cells based on the {@link Ext.grid.column.Column#cell}
 * config. Application code would rarely create cells directly.
 */
Ext.define('Ext.grid.cell.Widget', {
    extend: 'Ext.grid.cell.Base',
    xtype: 'widgetcell',
 
    config: {
        /**
         * @cfg {Boolean} forceWidth
         * `true` to measure the available width of the cell and set that
         * width on the underlying widget. If `false`, the widget width will auto
         * size.
         */
        forceWidth: false,
 
        /**
         * @cfg {Object} widget (required)
         * The config object for a {@link Ext.Component} or {@link Ext.Widget}.
         *
         * @cfg {String} widget.xtype (required) The type of component or widget to create.
         */
        widget: null
    },
 
    align: 'center',
 
    classCls: Ext.baseCSSPrefix + 'widgetcell',
 
    updateColumn: function(column, oldColumn) {
        var me = this,
            parent, firstCell;
 
        me.callParent([column, oldColumn]);
 
        if (!column || !me.getForceWidth()) {
            return;
        }
 
        // We need to be able to measure some dimensions of the cells
        // to be able to size the widgets if forceWidth is true. We can
        // only do this once we hit the DOM. However, we only want to do this
        // for the first cell because it can be expensive. If we've already
        // done it, no need to do so again.
 
        firstCell = column.firstCell;
        if (firstCell && firstCell.measured) {
            me.measured = true;
            return;
        }
 
        parent = me.getParent();
        if (parent && !parent.isSpecialRow && !column.firstCell) {
            column.firstCell = me;
            me.element.on('resize', 'handleFirstResize', me, {single: true});
        }
    },
 
    updateValue: function(value) {
        var widget = this.getWidget(),
            defaultBindProperty;
            
        if (widget) {
            defaultBindProperty = widget.defaultBindProperty;
 
            if (defaultBindProperty) {
                widget.setConfig(defaultBindProperty, value);
            }
        }
    },
 
    applyWidget: function(widget) {
        if (widget) {
            var parent = this.getParent();
 
            if (parent && !parent.isSpecialRow) {
                widget = Ext.apply({
                    parent: this
                }, widget);
                widget = Ext.widget(widget);
            } else {
                widget = undefined;
            }
        }
        return widget;
    },
 
    updateWidget: function(widget, oldWidget) {
        var me = this;
 
        if (oldWidget) {
            oldWidget.measurer = null;
            oldWidget.destroy();
        }
 
        if (widget) {
            me.innerElement.appendChild(widget.element);
            if (me.getForceWidth()) {
                me.setWidgetWidth(me.getWidth());
            }
        }
    },
 
    updateWidth: function(width, oldWidth) {
        this.callParent([width, oldWidth]);
        this.setWidgetWidth(width);
    },
 
    doDestroy: function() {
        this.setWidget(null);
        this.callParent();
    },
 
    privates: {
        handleFirstResize: function() {
            var me = this,
                width = me.getWidth(),
                cells, len, i, cell;
 
            // Once we have the measurement available for the first cell, 
            // go and cascade it for other cells.
            cells = me.getColumn().getCells();
 
            for (= 0, len = cells.length; i < len; ++i) {
                cell = cells[i];
                cell.measured = true;
                cell.setWidgetWidth(width);
            }
        },
 
        setWidgetWidth: function(width) {
            var me = this,
                el = me.innerElement,
                widget, column, leftPad, rightPad;
 
            if (!me.measured) {
                return;
            }
 
            widget = me.getWidget();
            if (widget) {
                column = me.getColumn();
                leftPad = parseInt(column.getCachedStyle(el, 'padding-left'), 10) || 0;
                rightPad = parseInt(column.getCachedStyle(el, 'padding-right'), 10) || 0;
                // Give the widget a reference to ourself to allow it to do any extra measuring
                widget.measurer = column;
                widget.setWidth(width - leftPad - rightPad);
                widget.redraw();
            }
        }
    }
});