/**
 * This is the layout style of choice for creating structural layouts in a multi-column format
 * where the width of each column can be specified as a percentage or fixed width, but the height
 * is allowed to vary based on the content. This class is intended to be extended or created
 * via the `layout: 'column'` {@link Ext.container.Container#layout} config, and should generally
 * not need to be created directly via the new keyword.
 *
 * ColumnLayout does not have any direct config options (other than inherited ones), but it does
 * support a specific config property of `columnWidth` that can be included in the config
 * of any panel added to it. The layout will use the columnWidth (if present) or width of each panel
 * during layout to determine how to size each panel. If width or columnWidth is not specified
 * for a given panel, its width will default to the panel's width (or auto).
 *
 * The width property is always evaluated as pixels, and must be a number greater than or equal
 * to 1. The columnWidth property is always evaluated as a percentage, and must be a decimal value
 * greater than 0 and less than 1 (e.g., .25).
 *
 * The basic rules for specifying column widths are pretty simple. The logic makes two passes
 * through the set of contained panels. During the first layout pass, all panels that either
 * have a fixed width or none specified (auto) are skipped, but their widths are subtracted
 * from the overall container width.
 *
 * During the second pass, all panels with columnWidths are assigned pixel widths in proportion
 * to their percentages based on the total **remaining** container width. In other words,
 * percentage width panels are designed to fill the space left over by all the fixed-width
 * and/or auto-width panels. Because of this, while you can specify any number of columns
 * with different percentages, the columnWidths must always add up to 1 (or 100%) when added
 * together, otherwise your layout may not render as expected.
 *
 *     @example
 *     // All columns are percentages -- they must add up to 1
 *     Ext.create('Ext.panel.Panel', {
 *         title: 'Column Layout - Percentage Only',
 *         width: 350,
 *         height: 250,
 *         layout:'column',
 *         items: [{
 *             title: 'Column 1',
 *             columnWidth: 0.25
 *         }, {
 *             title: 'Column 2',
 *             columnWidth: 0.55
 *         }, {
 *             title: 'Column 3',
 *             columnWidth: 0.20
 *         }],
 *         renderTo: Ext.getBody()
 *     });
 *
 *     // Mix of width and columnWidth -- all columnWidth values must add up
 *     // to 1. The first column will take up exactly 120px, and the last two
 *     // columns will fill the remaining container width.
 *
 *     Ext.create('Ext.Panel', {
 *         title: 'Column Layout - Mixed',
 *         width: 350,
 *         height: 250,
 *         layout:'column',
 *         items: [{
 *             title: 'Column 1',
 *             width: 120
 *         }, {
 *             title: 'Column 2',
 *             columnWidth: 0.7
 *         }, {
 *             title: 'Column 3',
 *             columnWidth: 0.3
 *         }],
 *         renderTo: Ext.getBody()
 *     });
 */
Ext.define('Ext.layout.container.Column', {
    extend: 'Ext.layout.container.Auto',
    alternateClassName: 'Ext.layout.ColumnLayout',
    alias: 'layout.column',
 
    type: 'column',
 
    itemCls: Ext.baseCSSPrefix + 'column',
 
    targetCls: Ext.baseCSSPrefix + 'column-layout-ct',
 
    // The clear value to force floats to wrap back to zero
    clearSide: 'left',
 
    // Columns with a columnWidth have their width managed.
    columnWidthSizePolicy: {
        readsWidth: 0,
        readsHeight: 1,
        setsWidth: 1,
        setsHeight: 0
    },
 
    createsInnerCt: true,
 
    manageOverflow: true,
 
    // Column layout needs to set the size of items configured with columnWidth, and it
    // needs to read the size of items with a configured width.
    setsItemSize: true,
    needsItemSize: true,
 
    isItemShrinkWrap: function(item) {
        return true;
    },
 
    getItemSizePolicy: function(item, ownerSizeModel) {
        if (item.columnWidth) {
            if (!ownerSizeModel) {
                ownerSizeModel = this.owner.getSizeModel();
            }
 
            if (!ownerSizeModel.width.shrinkWrap) {
                return this.columnWidthSizePolicy;
            }
        }
 
        return this.autoSizePolicy;
    },
 
    calculateItems: function(ownerContext, containerSize) {
        var me = this,
            columnCount = me.columnCount,
            targetContext = ownerContext.targetContext,
            items = ownerContext.childItems,
            len = items.length,
            contentWidth = 0,
            gotWidth = containerSize.gotWidth,
            blocked, availableWidth, i, itemContext, itemMarginWidth, itemWidth;
 
        // No parallel measurement, cannot lay out boxes.
        if (gotWidth === false) { // \\ TODO: Deal with target padding width
            // TODO: only block if we have items with columnWidth
            targetContext.domBlock(me, 'width');
            blocked = true;
        }
        else if (gotWidth) {
            availableWidth = containerSize.width;
        }
        else {
            // gotWidth is undefined, which means we must be width shrink wrap.
            // cannot calculate columnWidths if we're shrink wrapping.
            return true;
        }
 
        // we need the widths of the columns we don't manage to proceed so we block on them
        // if they are not ready...
        for (= 0; i < len; ++i) {
            itemContext = items[i];
 
            // Ensure that each row start clears to start of row.
            // Tall items would block it as below.
            // "Item 4" requires clear:left to begin at column zero.
            // +------------------------------- +
            // |+--------+ +--------+ +--------+|
            // ||        | |        | |        ||
            // || Item 1 | | Item 2 | | Item 3 ||
            // ||        | +--------+ +--------+|
            // ||        | +--------+           |
            // |+--------+ |        |           |
            // |           | Item 4 |           |
            // |           |        |           |
            // |           +--------+           |
            // +--------------------------------+
            if (columnCount) {
                if (% columnCount) {
                    itemContext.setProp('clear', null);
                }
                else {
                    itemContext.setProp('clear', me.clearSide);
                }
            }
 
            // this is needed below for non-calculated columns, but is also needed in the
            // next loop for calculated columns... this way we only call getMarginInfo in
            // this loop and use the marginInfo property in the next...
            itemMarginWidth = itemContext.getMarginInfo().width;
 
            if (!itemContext.widthModel.calculated) {
                itemWidth = itemContext.getProp('width');
 
                if (typeof itemWidth !== 'number') {
                    itemContext.block(me, 'width');
                    blocked = true;
                }
 
                contentWidth += itemWidth + itemMarginWidth;
            }
        }
 
        if (!blocked) {
            contentWidth = me.calculateItemSizeWithContent(availableWidth, contentWidth, items);
            ownerContext.setContentWidth(
                contentWidth + ownerContext.paddingContext.getPaddingInfo().width
            );
        }
 
        // we registered all the values that block this calculation, so abort now if blocked...
        return !blocked;
    },
 
    calculateItemSizeWithContent: function(availableWidth, contentWidth, items) {
        var itemMarginWidth, itemContext,
            itemWidth, i,
            len = items.length;
 
        availableWidth = (availableWidth < contentWidth) ? 0 : availableWidth - contentWidth;
 
        for (= 0; i < len; ++i) {
            itemContext = items[i];
 
            if (itemContext.widthModel.calculated) {
                itemMarginWidth = itemContext.marginInfo.width; // always set by above loop
                itemWidth = itemContext.target.columnWidth;
                itemWidth = Math.floor(itemWidth * availableWidth) - itemMarginWidth;
                itemWidth = itemContext.setWidth(itemWidth); // constrains to min/maxWidth
                contentWidth += itemWidth + itemMarginWidth;
            }
        }
 
        return contentWidth;
    }
});