/**
 * Component layout for buttons
 * @private
 */
Ext.define('Ext.layout.component.Button', {

    /* Begin Definitions */

    alias: ['layout.button'],

    extend: 'Ext.layout.component.Auto',

    /* End Definitions */

    type: 'button',

    cellClsRE: /-btn-(tl|br)\b/,
    htmlRE: /<.*>/,

    constructor: function () {
        this.callParent(arguments);

        this.hackWidth = (Ext.isIE6 || Ext.isIE7) && Ext.isStrict;
    },

    // TODO - use last run results if text has not changed?

    beginLayout: function (ownerContext) {
        this.callParent(arguments);

        this.cacheTargetInfo(ownerContext);
    },

    beginLayoutCycle: function(ownerContext) {
        var me = this,
            empty = '',
            owner = me.owner,
            btnEl = owner.btnEl,
            btnInnerEl = owner.btnInnerEl,
            text = owner.text;

        me.callParent(arguments);

        btnInnerEl.setStyle('overflow', empty);

        // Clear all element widths
        if (!ownerContext.widthModel.natural) {
            owner.el.setStyle('width', empty);
        }
        btnEl.setStyle('width', empty);
        btnInnerEl.setStyle('width', empty);
        owner.btnIconEl.setStyle('width', empty);
        
        if (ownerContext.heightModel.shrinkWrap && text && me.htmlRE.test(text)) {
            btnInnerEl.setStyle('line-height', 'normal');
            btnInnerEl.setStyle('height', 'auto');
            btnEl.setStyle('height', 'auto');
        }
    },

    calculateOwnerHeightFromContentHeight: function (ownerContext, contentHeight) {
        return contentHeight;
    },

    calculateOwnerWidthFromContentWidth: function (ownerContext, contentWidth) {
        return contentWidth;
    },

    measureContentWidth: function (ownerContext) {
        var me = this,
            owner = me.owner,
            btnEl = owner.btnEl,
            btnInnerEl = owner.btnInnerEl,
            btnFrameWidth, metrics, sizeIconEl, width, btnElContext, btnInnerElContext;

        // In IE7 strict mode button elements with width:auto get strange extra side margins within
        // the wrapping table cell, but they go away if the width is explicitly set. So we measure
        // the size of the text and set the width to match.
        if (owner.text && me.hackWidth && btnEl && btnEl.getWidth() > 20) {
            btnFrameWidth = me.btnFrameWidth;
            metrics = Ext.util.TextMetrics.measure(btnInnerEl, owner.text);
            width = metrics.width + btnFrameWidth + me.adjWidth;

            btnElContext = ownerContext.getEl('btnEl');
            btnInnerElContext = ownerContext.getEl('btnInnerEl');
            sizeIconEl = (owner.icon || owner.iconCls) && 
                    (owner.iconAlign == "top" || owner.iconAlign == "bottom");

            // This cheat works (barely) with publishOwnerWidth which calls setProp also
            // to publish the width. Since it is the same value we set here, the dirty bit
            // we set true will not be cleared by publishOwnerWidth.
            ownerContext.setWidth(width); // not setWidth (no framing)

            btnElContext.setWidth(metrics.width + btnFrameWidth);
            btnInnerElContext.setWidth(metrics.width + btnFrameWidth);

            if (sizeIconEl) {
                owner.btnIconEl.setWidth(metrics.width + btnFrameWidth);
            }
        } else {
            width = ownerContext.el.getWidth();
        }

        return width;
    },

    measureContentHeight: function (ownerContext) {
        var me = this,
            owner = me.owner,
            btnInnerEl = owner.btnInnerEl,
            height;

        if (owner.vertical) {
            height = Ext.util.TextMetrics.measure(btnInnerEl, owner.text).width;
            height += me.btnFrameHeight + me.adjHeight;

            // Vertical buttons need height explicitly set
            ownerContext.setHeight(height, /*dirty=*/true, /*force=*/true);
        } else {
            height = ownerContext.el.getHeight();
        }

        return height;
    },

    publishInnerHeight: function(ownerContext, height) {
        var me = this,
            owner = me.owner,
            isNum = Ext.isNumber,
            btnItem = ownerContext.getEl('btnEl'),
            btnInnerEl = owner.btnInnerEl,
            btnInnerItem = ownerContext.getEl('btnInnerEl'),
            btnHeight = isNum(height) ? height - me.adjHeight : height,
            btnFrameHeight = me.btnFrameHeight,
            text = owner.getText(),
            textHeight;

        btnItem.setHeight(btnHeight);
        btnInnerItem.setHeight(btnHeight);

        // Only need the line-height setting for regular, horizontal Buttons
        if (!owner.vertical && btnHeight >= 0) {
            btnInnerItem.setProp('line-height', btnHeight - btnFrameHeight + 'px');
        }

        // Button text may contain markup that would force it to wrap to more than one line (e.g. 'Button<br>Label').
        // When this happens, we cannot use the line-height set above for vertical centering; we instead reset the
        // line-height to normal, measure the rendered text height, and add padding-top to center the text block
        // vertically within the button's height. This is more expensive than the basic line-height approach so
        // we only do it if the text contains markup.
        if (text && me.htmlRE.test(text)) {
            btnInnerItem.setProp('line-height', 'normal');
            btnInnerEl.setStyle('line-height', 'normal');
            textHeight = Ext.util.TextMetrics.measure(btnInnerEl, text).height;
            btnInnerItem.setProp('padding-top',
                me.btnFrameTop + Math.max(btnHeight - btnFrameHeight - textHeight, 0) / 2);
            btnInnerItem.setHeight(btnHeight);
        }
    },

    publishInnerWidth: function(ownerContext, width) {
        var me = this,
            isNum = Ext.isNumber,
            btnItem = ownerContext.getEl('btnEl'),
            btnInnerItem = ownerContext.getEl('btnInnerEl'),
            btnWidth = isNum(width) ? width - me.adjWidth : width;

        btnItem.setWidth(btnWidth);
        btnInnerItem.setWidth(btnWidth);
    },

    cacheTargetInfo: function(ownerContext) {
        var me = this,
            padding, frameSize, btnWrapPadding, innerFrameSize;

        if (!('adjWidth' in me)) {
            padding = ownerContext.getPaddingInfo();
            frameSize = ownerContext.getFrameInfo();
            btnWrapPadding = ownerContext.getEl('btnWrap').getPaddingInfo();
            innerFrameSize = ownerContext.getEl('btnInnerEl').getPaddingInfo();

            Ext.apply(me, {
                // Width adjustment must take into account the arrow area. The btnWrap is the <em> which has padding to accommodate the arrow.
                adjWidth       : btnWrapPadding.width + frameSize.width + padding.width,
                adjHeight      : btnWrapPadding.height + frameSize.height + padding.height,
                btnFrameWidth  : innerFrameSize.width,
                btnFrameHeight : innerFrameSize.height,
                btnFrameTop    : innerFrameSize.top
            });
        }

        me.callParent(arguments);
    }
});