/**
 * Sencha Touchのボタンを表示するシンプルクラスです。
 *
 * {@link #icon}、{@link #iconCls}、{@link #iconAlign}、{@link #ui}、{@link #text}などの設定を使用して、さまざまなスタイルのボタンを作成できます。
 *
 * ##シンプルボタン
 *
 * 最も簡単な形式のボタンです。
 *
 *     @example miniphone
 *     var button = Ext.create('Ext.Button', {
 *         text: 'Button'
 *     });
 *     Ext.Viewport.add({ xtype: 'container', padding: 10, items: [button] });
 *
 * ##アイコン
 *
 * {@link #iconCls}設定を使用して、アイコンだけのボタンを作成することもできます。
 *
 *     @example miniphone
 *     var button = Ext.create('Ext.Button', {
 *         iconCls: 'refresh'
 *     });
 *     Ext.Viewport.add({ xtype: 'container', padding: 10, items: [button] });
 *
 * Senchaはhttp://wwww.pictos.ccの「Font」や「PNG」アイコンパックを提供します。Sassで{@link Global_CSS#icon icon}ミックスインを含むアイコンを使用します。
 *
 * ##バッジ
 *
 * ボタンには、{@link #badgeText}設定を使用して、その上にバッジを付けることもできます。
 *
 *     @example
 *     Ext.create('Ext.Container', {
 *         fullscreen: true,
 *         padding: 10,
 *         items: {
 *             xtype: 'button',
 *             text: 'My Button',
 *             badgeText: '2'
 *         }
 *     });
 *
 * ##UI
 *
 * ボタンにはさまざまなデフォルトのUIも用意されています。以下のようなUIが使用可能です({@link #$include-button-uis $include-button-uis}が`true`に設定されている場合):
 *
 * - **normal** - 基本のグレーボタン
 * - **back** - 黒のボタン
 * - **forward** - 前へのボタン
 * - **round** - 丸いボタン
 * - **action** - {@link Global_CSS#$active-color $active-color}を使用する影付き(デフォルトでは濃紺)
 * - **decline** - {@link Global_CSS#$alert-color $alert-color}を使用する影付き(デフォルトでは赤)
 * - **confirm** - {@link Global_CSS#$confirm-color $confirm-color}を使用する影付き(デフォルトでは緑)
 *
 * また、最後の3つのUIそれぞれに`-round`を追加して、丸い形にすることもできます。
 *
 * - **action-round**
 * - **decline-round**
 * - **confirm-round**
 *
 * 設定方法は次のように非常に簡単です。
 *
 *     var uiButton = Ext.create('Ext.Button', {
 *         text: 'My Button',
 *         ui: 'action'
 *     });
 *
 * するとこのようなボタンになります。
 *
 *     @example miniphone preview
 *     Ext.create('Ext.Container', {
 *         fullscreen: true,
 *         padding: 4,
 *         defaults: {
 *             xtype: 'button',
 *             margin: 5
 *         },
 *         layout: {
 *             type: 'vbox',
 *             align: 'center'
 *         },
 *         items: [
 *             { ui: 'normal', text: 'normal' },
 *             { ui: 'round', text: 'round' },
 *             { ui: 'action', text: 'action' },
 *             { ui: 'decline', text: 'decline' },
 *             { ui: 'confirm', text: 'confirm' }
 *         ]
 *     });
 *
 * デフォルトの{@link #ui}は**normal**であることに注意してください。
 *
 * さらに、{@link #sencha-button-ui sencha-button-ui}CSSミックスインを使用して独自のUIを作成することもできます。
 *
 * ##例
 *
 * この例では、画面上のたくさんのアイコンは2つのツールバーに表示されています。中央のボタンをクリックすると、ページ上のあらゆるボタンの{@link #iconCls}が切り替わります。
 *
 *     @example preview
 *     Ext.createWidget('container', {
 *         fullscreen: true,
 *         layout: {
 *             type: 'vbox',
 *             pack:'center',
 *             align: 'center'
 *         },
 *         items: [
 *             {
 *                 xtype: 'button',
 *                 text: 'Change iconCls',
 *                 handler: function() {
 *                     // classes for all the icons to loop through.
 *                     var availableIconCls = [
 *                         'action', 'add', 'arrow_down', 'arrow_left',
 *                         'arrow_right', 'arrow_up', 'compose', 'delete',
 *                         'organize', 'refresh', 'reply', 'search',
 *                         'settings', 'star', 'trash', 'maps', 'locate',
 *                         'home'
 *                     ];
 *                     // get the text of this button,
 *                     // so we know which button we don't want to change
 *                     var text = this.getText();
 *
 *                     // use ComponentQuery to find all buttons on the page
 *                     // and loop through all of them
 *                     Ext.Array.forEach(Ext.ComponentQuery.query('button'), function(button) {
 *                         // if the button is the change iconCls button, continue
 *                         if (button.getText() === text) {
 *                             return;
 *                         }
 *
 *                         // get the index of the new available iconCls
 *                         var index = availableIconCls.indexOf(button.getIconCls()) + 1;
 *
 *                         // update the iconCls of the button with the next iconCls, if one exists.
 *                         // if not, use the first one
 *                         button.setIconCls(availableIconCls[(index === availableIconCls.length) ? 0 : index]);
 *                     });
 *                 }
 *             },
 *             {
 *                 xtype: 'toolbar',
 *                 docked: 'top',
 *                 items: [
 *                     { xtype: 'spacer' },
 *                     { iconCls: 'action' },
 *                     { iconCls: 'add' },
 *                     { iconCls: 'arrow_down' },
 *                     { iconCls: 'arrow_left' },
 *                     { iconCls: 'arrow_up' },
 *                     { iconCls: 'compose' },
 *                     { iconCls: 'delete' },
 *                     { iconCls: 'organize' },
 *                     { iconCls: 'refresh' },
 *                     { xtype: 'spacer' }
 *                 ]
 *             },
 *             {
 *                 xtype: 'toolbar',
 *                 docked: 'bottom',
 *                 ui: 'light',
 *                 items: [
 *                     { xtype: 'spacer' },
 *                     { iconCls: 'reply' },
 *                     { iconCls: 'search' },
 *                     { iconCls: 'settings' },
 *                     { iconCls: 'star' },
 *                     { iconCls: 'trash' },
 *                     { iconCls: 'maps' },
 *                     { iconCls: 'locate' },
 *                     { iconCls: 'home' },
 *                     { xtype: 'spacer' }
 *                 ]
 *             }
 *         ]
 *     });
 *
 */
Ext.define('Ext.Button', {
    extend: 'Ext.Component',

    xtype: 'button',

    /**
     * @event tap
     * @preventable doTap
     * ボタンがタップされる度に発火します。
     * @param {Ext.Button} this コンテナに追加されるアイテム。
     * @param {Ext.EventObject} e イベントオブジェクト。
     */

    /**
     * @event release
     * @preventable doRelease
     * ボタンが離される度に発火します。
     * @param {Ext.Button} this コンテナに追加されるアイテム。
     * @param {Ext.EventObject} e イベントオブジェクト。
     */

    cachedConfig: {
        /**
         * @cfg {String} pressedCls
         * ボタンが押されたときに、ボタンに追加するCSSクラス。
         * @accessor
         */
        pressedCls: Ext.baseCSSPrefix + 'button-pressing',

        /**
         * @cfg {String} badgeCls
         * ボタンがバッジを持つ場合、そのバッジに追加するCSSクラス。バッジは、ボタンの上にある小型の数字、文字、アイコンとして表示されます。例えば、更新回数を示す小型の赤文字があります。
         * @accessor
         */
        badgeCls: Ext.baseCSSPrefix + 'badge',

        /**
         * @cfg {String} hasBadgeCls
         * ボタンがバッジである場合に追加されるCSSクラス(これはボタン要素自身に基づいていて、バッジ要素には基づいていないことに注意してください)。
         * @private
         * @accessor
         */
        hasBadgeCls: Ext.baseCSSPrefix + 'hasbadge',

        /**
         * @cfg {String} labelCls
         * フィールドのラベル要素に追加するCSSクラス。
         * @accessor
         */
        labelCls: Ext.baseCSSPrefix + 'button-label',

        /**
         * @cfg {String} iconCls
         * アイコン要素に追加するオプションのCSSクラスです。CSS背景画像を使用して独自のボタンアイコンを作成する場合に便利です。
         * @accessor
         */
        iconCls: null
    },

    config: {
        /**
         * @cfg {String} badgeText
         * オプションのバッジテキスト。バッジは、ボタンの上にある小型の数字、文字、アイコンとして表示されます。例えば、更新回数を示す小型の赤文字があります。
         * @accessor
         */
        badgeText: null,

        /**
         * @cfg {String} text
         * ボタンのテキスト。
         * @accessor
         */
        text: null,

        /**
         * @cfg {String} icon
         * ボタン上にアイコンを表示させたい場合にアイコンイメージに使用するurl。
         * @accessor
         */
        icon: false,

        /**
         * @cfg {String} iconAlign
         * アイコンをレンダリングするボタン内の位置。オプションは、`top`、`right`、`bottom`、`left`、`center`です({@link #text}が設定されていない場合)。
         * @accessor
         */
        iconAlign: 'left',

        /**
         * @cfg {Number/Boolean} pressedDelay
         * `tabstart`から`pressedCls`を追加した瞬間までの遅延時間(ミリ秒単位)。`true`に設定すると、デフォルトは100msになります。
         */
        pressedDelay: 0,

        /**
         * @cfg {Function} handler
         * ボタンがタップされたときに実行されるハンドラ関数。
         * @accessor
         */
        handler: null,

        /**
         * @cfg {Object} scope
         * 設定された{@link #handler}を発火するスコープ。
         * @accessor
         */
        scope: null,

        /**
         * @cfg {String} autoEvent
         * (オプション)ボタンがタップされたときに`tap`の代わりに発火されるイベント名。
         * @accessor
         */
        autoEvent: null,

        /**
         * @cfg {String} ui
         * このボタンにレンダリングする際のuiスタイル。有効なデフォルトのオプション:
         *
         * - `'normal'` - 基本のグレーボタン(デフォルト)
         * - `'back'` - 黒のボタン
         * - `'forward'` - 前へのボタン
         * - `'round'` - 丸いボタン
         * - `'plain'`
         * - `'action'` - {@link Global_CSS#$active-color $active-color}を使用する影付き(デフォルトでは濃紺)
         * - `'decline'` - {@link Global_CSS#$alert-color $alert-color}を使用する影付き(デフォルトでは赤)
         * - `'confirm'` - {@link Global_CSS#$confirm-color $confirm-color}を使用する影付き(デフォルトでは緑)
         *
         * また、最後の3つのUIそれぞれに`-round`を追加して、丸い形にすることもできます。
         *
         * - **action-round**
         * - **decline-round**
         * - **confirm-round**
         *
         * @accessor
         */
        ui: 'normal',

        /**
         * @cfg {String} html このボタンを設置するHTML。
         *
         * テキストだけを追加する場合は、{@link #text}設定を使用してください。
         */

        /**
         * @cfg
         * @inheritdoc
         */
        baseCls: Ext.baseCSSPrefix + 'button'
    },

    template: [
        {
            tag: 'span',
            reference: 'badgeElement',
            hidden: true
        },
        {
            tag: 'span',
            className: Ext.baseCSSPrefix + 'button-icon',
            reference: 'iconElement'
        },
        {
            tag: 'span',
            reference: 'textElement',
            hidden: true
        }
    ],

    initialize: function() {
        this.callParent();

        this.element.on({
            scope      : this,
            tap        : 'onTap',
            touchstart : 'onPress',
            touchend   : 'onRelease'
        });
    },

    /**
     * @private
     */
    updateBadgeText: function(badgeText) {
        var element = this.element,
            badgeElement = this.badgeElement;

        if (badgeText) {
            badgeElement.show();
            badgeElement.setText(badgeText);
        }
        else {
            badgeElement.hide();
        }

        element[(badgeText) ? 'addCls' : 'removeCls'](this.getHasBadgeCls());
    },

    /**
     * @private
     */
    updateText: function(text) {
        var textElement = this.textElement;
        
        if (textElement) {
            if (text) {
                textElement.show();
                textElement.setHtml(text);
            } else {
                textElement.hide();
            }

            this.refreshIconAlign();
        }
    },

    /**
     * @private
     */
    updateHtml: function(html) {
        var textElement = this.textElement;

        if (html) {
            textElement.show();
            textElement.setHtml(html);
        }
        else {
            textElement.hide();
        }
    },

    /**
     * @private
     */
    updateBadgeCls: function(badgeCls, oldBadgeCls) {
        this.badgeElement.replaceCls(oldBadgeCls, badgeCls);
    },

    /**
     * @private
     */
    updateHasBadgeCls: function(hasBadgeCls, oldHasBadgeCls) {
        var element = this.element;

        if (element.hasCls(oldHasBadgeCls)) {
            element.replaceCls(oldHasBadgeCls, hasBadgeCls);
        }
    },

    /**
     * @private
     */
    updateLabelCls: function(labelCls, oldLabelCls) {
        this.textElement.replaceCls(oldLabelCls, labelCls);
    },

    /**
     * @private
     */
    updatePressedCls: function(pressedCls, oldPressedCls) {
        var element = this.element;

        if (element.hasCls(oldPressedCls)) {
            element.replaceCls(oldPressedCls, pressedCls);
        }
    },

    /**
     * @private
     */
    updateIcon: function(icon) {
        var me = this,
            element = me.iconElement;

        if (icon) {
            me.showIconElement();
            element.setStyle('background-image', 'url(' + icon + ')');
            me.refreshIconAlign();
        } else {
        	element.setStyle('background-image', '');
            me.hideIconElement();
        }
    },

    /**
     * @private
     */
    updateIconCls: function(iconCls, oldIconCls) {
        var me = this,
            element = me.iconElement;

        if (iconCls) {
            me.showIconElement();
            element.replaceCls(oldIconCls, iconCls);
            me.refreshIconAlign();
        } else {
			element.removeCls(oldIconCls);
            me.hideIconElement();
        }
    },

    /**
     * @private
     */
    updateIconAlign: function(alignment, oldAlignment) {
        var element = this.element,
            baseCls = Ext.baseCSSPrefix + 'iconalign-';

        if (!this.getText()) {
            alignment = "center";
        }

        element.removeCls(baseCls + "center");
        element.removeCls(baseCls + oldAlignment);
        if (this.getIcon() || this.getIconCls()) {
            element.addCls(baseCls + alignment);
        }
    },

    refreshIconAlign: function() {
        this.updateIconAlign(this.getIconAlign());
    },

    applyAutoEvent: function(autoEvent) {
        var me = this;

        if (typeof autoEvent == 'string') {
            autoEvent = {
                name : autoEvent,
                scope: me.scope || me
            };
        }

        return autoEvent;
    },

    /**
     * @private
     */
    updateAutoEvent: function(autoEvent) {
        var name  = autoEvent.name,
            scope = autoEvent.scope;

        this.setHandler(function() {
            scope.fireEvent(name, scope, this);
        });

        this.setScope(scope);
    },

    /**
     * アイコン要素を非表示にするために`icon`と`iconCls`で使用されます。
     * @private
     */
    hideIconElement: function() {
        this.iconElement.removeCls(Ext.baseCSSPrefix + 'shown');
        this.iconElement.addCls(Ext.baseCSSPrefix + 'hidden');
    },

    /**
     * アイコン要素を表示するために`icon`と`iconCls`で使用されます。
     * @private
     */
    showIconElement: function() {
        this.iconElement.removeCls(Ext.baseCSSPrefix + 'hidden');
        this.iconElement.addCls(Ext.baseCSSPrefix + 'shown');
    },

    /**
     * オーバーライドして、 '{ui}-back'をチェックします。これは、backのUIがある場合には、クラス名を2つ追加することが必要なためです。uiクラスとbackクラス:
     *
     * `ui:'action-back'`は、
     *
     * `class="x-button-action x-button-back"になりますが、`
     *
     * `ui:'action'`は、
     *
     * `class="x-button-action"になります。`
     *
     * このため、`back`がある場合は、配列に分割し、UIとして両方を追加します。
     * @private
     */
    applyUi: function(config) {
        if (config && Ext.isString(config)) {
            var array  = config.split('-');
            if (array && (array[1] == "back" || array[1] == "forward")) {
                return array;
            }
        }

        return config;
    },

    getUi: function() {
        //Now that the UI can sometimes be an array, we need to check if it an array and return the proper value.
        var ui = this._ui;
        if (Ext.isArray(ui)) {
            return ui.join('-');
        }
        return ui;
    },

    applyPressedDelay: function(delay) {
        if (Ext.isNumber(delay)) {
            return delay;
        }
        return (delay) ? 100 : 0;
    },

    // @private
    onPress: function() {
        var me = this,
            element = me.element,
            pressedDelay = me.getPressedDelay(),
            pressedCls = me.getPressedCls();

        if (!me.getDisabled()) {
            if (pressedDelay > 0) {
                me.pressedTimeout = setTimeout(function() {
                    delete me.pressedTimeout;
                    if (element) {
                        element.addCls(pressedCls);
                    }
                }, pressedDelay);
            }
            else {
                element.addCls(pressedCls);
            }
        }
    },

    // @private
    onRelease: function(e) {
        this.fireAction('release', [this, e], 'doRelease');
    },

    // @private
    doRelease: function(me, e) {
        if (!me.getDisabled()) {
            if (me.hasOwnProperty('pressedTimeout')) {
                clearTimeout(me.pressedTimeout);
                delete me.pressedTimeout;
            }
            else {
                me.element.removeCls(me.getPressedCls());
            }
        }
    },

    // @private
    onTap: function(e) {
        if (this.getDisabled()) {
            return false;
        }

        this.fireAction('tap', [this, e], 'doTap');
    },

    /**
     * @private
     */
    doTap: function(me, e) {
        var handler = me.getHandler(),
            scope = me.getScope() || me;

        if (!handler) {
            return;
        }

        if (typeof handler == 'string') {
            handler = scope[handler];
        }

        //this is done so if you hide the button in the handler, the tap event will not fire on the new element
        //where the button was.
        if (e && e.preventDefault) {
            e.preventDefault();
        }

        handler.apply(scope, arguments);
    }
}, function() {
    //<deprecated product=touch since=2.0>

    /**
     * バッジのテキストを更新します。
     * @method setBadge
     * @param {String} text
     * @deprecated 2.0.0
代わりに{@link #setBadgeText}を使用してください。
     */
    Ext.deprecateClassMethod(this, 'setBadge', 'setBadgeText');

    /**
     * アイコンクラスを更新します。
     * @method setIconClass
     * @param {String} iconClass
     * @deprecated 2.0.0
代わりに{@link #setIconCls}を使用してください。
     */
    Ext.deprecateClassMethod(this, 'setIconClass', 'setIconCls');

    this.override({
        constructor: function(config) {
            if (config) {
                /**
                 * @cfg {String} badge
                 * オプションのバッジテキスト。
                 * @deprecated 2.0.0
代わりに{@link #badgeText}を使用してください。
                 */
                if (config.hasOwnProperty('badge')) {
                    //<debug warn>
                    Ext.Logger.deprecate("'badge' config is deprecated, please use 'badgeText' config instead", this);
                    //</debug>
                    config.badgeText = config.badge;
                    delete config.badge;
                }
            }

            this.callParent([config]);
        }
    });

    //</deprecated>
});