/**
 * Actionとは、複数のコンポーネント間で有効に共有することができるように、特定のコンポーネントから抽象化された再利用可能な機能のピースのことです。Actionsを使うと、ハンドラ、設定オプション、Actionインターフェイス(主に{@link Ext.toolbar.Toolbar}、{@link Ext.button.Button}、および{@link Ext.menu.Menu}コンポーネント)をサポートするコンポーネント全体のUIの更新を共有できます。
 *
 * 単一のActionインスタンスは、同じ設定を共有するUIコンポーネントを、その数に関わらず、コンフィグオブジェクトとして使用できます。Actionは、設定を提供するだけでなく、それに基づくコンポーネントすべてに、Actionを単体で呼び出すことを通じて、即座に呼び出される共通のメソッド一式を与えます。
 *
 * Actionに設定されるべきコンポーネントは、以下のメソッドもサポートしていなくてはなりません。
 *
 * - setText(文字列)
 * - setIconCls(文字列)
 * - setDisabled(boolean)
 * - setVisible(boolean)
 * - setHandler(関数)
 *
 * これにより、Actionは、関連するコンポーネントを制御できます。
 *
 * 使用例:
 *
 *     // Define the shared Action.  Each Component below will have the same
 *     // display text and icon, and will display the same message on click.
 *     var action = new Ext.Action({
 *         {@link #text}: 'Do something',
 *         {@link #handler}: function(){
 *             Ext.Msg.alert('Click', 'You did something.');
 *         },
 *         {@link #iconCls}: 'do-something',
 *         {@link #itemId}: 'myAction'
 *     });
 *
 *     var panel = new Ext.panel.Panel({
 *         title: 'Actions',
 *         width: 500,
 *         height: 300,
 *         tbar: [
 *             // Add the Action directly to a toolbar as a menu button
 *             action,
 *             {
 *                 text: 'Action Menu',
 *                 // Add the Action to a menu as a text item
 *                 menu: [action]
 *             }
 *         ],
 *         items: [
 *             // Add the Action to the panel body as a standard button
 *             new Ext.button.Button(action)
 *         ],
 *         renderTo: Ext.getBody()
 *     });
 *
 *     // Change the text for all components using the Action
 *     action.setText('Something else');
 *
 *     // Reference an Action through a container using the itemId
 *     var btn = panel.getComponent('myAction');
 *     var aRef = btn.baseAction;
 *     aRef.setText('New text');
 */
Ext.define('Ext.Action', {

    /* Begin Definitions */

    /* End Definitions */

    /**
     * @cfg {String} [text='']
     * このActionによって構成される、すべてのコンポーネントに設定するテキスト。
     */
    /**
     * @cfg {String} [iconCls='']
     * このActionによって構成される、 すべてのコンポーネントのヘッダーアイコンとして使用される背景背景画像を指定するCSSクラスセレクタ。
     *
     * カスタムアイコンクラスを指定する例は次のようになります:
     *
     *     // specify the property in the config for the class:
     *          ...
     *          iconCls: 'do-something'
     *
     *     // css class that specifies background image to be used as the icon image:
     *     .do-something { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
     *
     * Ext JSに付属するデフォルトのアイコンクラスはありません。
     */
    /**
     * @cfg {Boolean} [disabled=false]
     * このActionによって構成される、すべてのコンポーネントを無効にする場合はtrue、それらを有効にする場合はfalse。
     */
    /**
     * @cfg {Boolean} [hidden=false]
     * このActionによって構成される、すべてのコンポーネントを非表示にする場合はtrue、表示する場合はfalse。
     */
    /**
     * @cfg {Function} handler
     * 主なイベントが引き起こされたときに、このアクションに結合している各コンポーネントによって呼び出される関数。
     */
    /**
     * @cfg {String} itemId
     * {@link Ext.Component}.{@link Ext.Component#itemId itemId}を参照してください。
     */
    /**
     * @cfg {Object} scope
     * {@link #handler}が実行されるときのスコープ(this参照)。デフォルトはブラウザウィンドウです。
     */

    /**
     * 新しいActionを作成します。
     * @param {Object} config コンフィグオブジェクト。
     */
    constructor : function(config){
        this.initialConfig = config;
        this.itemId = config.itemId = (config.itemId || config.id || Ext.id());
        this.items = [];
    },

    /*
     * @property {Boolean} isAction
     * `true`にするとこのクラスでオブジェクトをインスタンス化されたActionもしくはそのサブクラスとして認識します。
     */
    isAction : true,

    /**
     * このActionによって構成される、すべてのコンポーネントで表示されるテキストを設定します。
     * @param {String} text 表示されるテキスト
     */
    setText : function(text){
        this.initialConfig.text = text;
        this.callEach('setText', [text]);
    },

    /**
     * このActionによって構成される、すべてのコンポーネントで現在表示されているテキストを取得します。
     */
    getText : function(){
        return this.initialConfig.text;
    },

    /**
     * このActionによって構成される、すべてのコンポーネントのアイコンCSSクラスを設定します。クラスはアイコン画像として使用する背景画像が指定されている必要があります。
     * @param {String} cls アイコン画像を供給するCSSクラス
     */
    setIconCls : function(cls){
        this.initialConfig.iconCls = cls;
        this.callEach('setIconCls', [cls]);
    },

    /**
     * このActionによって構成される、すべてのコンポーネントで現在使用されているアイコンCSSクラスを取得します。
     */
    getIconCls : function(){
        return this.initialConfig.iconCls;
    },

    /**
     * このActionによって構成される、すべてのコンポーネントの無効状態を設定します。{@link #enable}および{@link #disable}用のショートカットメソッド。
     * @param {Boolean} disabled コンポーネントを無効にする場合はtrue、有効にする場合はfalse。
     */
    setDisabled : function(v){
        this.initialConfig.disabled = v;
        this.callEach('setDisabled', [v]);
    },

    /**
     * このActionによって構成される、すべてのコンポーネントを有効にします。
     */
    enable : function(){
        this.setDisabled(false);
    },

    /**
     * このActionによって構成される、すべてのコンポーネントを無効にします。
     */
    disable : function(){
        this.setDisabled(true);
    },

    /**
     * このActionを使用しているコンポーネントが現在無効になっている場合はtrue、そうでない場合はfalseを返します。
     */
    isDisabled : function(){
        return this.initialConfig.disabled;
    },

    /**
     * このActionによって構成される、すべてのコンポーネントの非表示状態を設定します。`{@link #hide}`および`{@link #show}`用のショートカットメソッド。
     * @param {Boolean} hidden コンポーネントを非表示にする場合はtrue、表示する場合はfalse。
     */
    setHidden : function(v){
        this.initialConfig.hidden = v;
        this.callEach('setVisible', [!v]);
    },

    /**
     * このActionによって構成される、すべてのコンポーネントを表示します。
     */
    show : function(){
        this.setHidden(false);
    },

    /**
     * このActionによって構成される、すべてのコンポーネントを非表示にします。
     */
    hide : function(){
        this.setHidden(true);
    },

    /**
     * このActionによって構成されているコンポーネントが現在非表示になっている場合はtrue、そうでない場合はfalseを返します。
     */
    isHidden : function(){
        return this.initialConfig.hidden;
    },

    /**
     * 主なイベントが引き起こされたときに、このアクションを使用している各コンポーネントによって呼び出される関数を設定します。
     * @param {Function} fn アクションのコンポーネントによって呼び出される関数。関数は引数なしで呼び出されます。
     * @param {Object} scope 関数実行時のスコープ(this参照)。デフォルトはイベントが発火したコンポーネントです。
     */
    setHandler : function(fn, scope){
        this.initialConfig.handler = fn;
        this.initialConfig.scope = scope;
        this.callEach('setHandler', [fn, scope]);
    },

    /**
     * 現在このActionに結びついている各コンポーネントで、指定された関数を実行します。渡される関数は基本的なActionのコンフィグ/メソッドインターフェースをサポートするオブジェクトになる1つの引数を受け入れます。
     * @param {Function} fn 各コンポーネントで実行する関数。
     * @param {Object} scope 関数実行時のスコープ(this参照)。デフォルトはコンポーネントです。
     */
    each : function(fn, scope){
        Ext.each(this.items, fn, scope);
    },

    // @private
    callEach : function(fnName, args){
        var items = this.items,
            i = 0,
            len = items.length,
            item;

        Ext.suspendLayouts();
        for(; i < len; i++){
            item = items[i];
            item[fnName].apply(item, args);
        }
        Ext.resumeLayouts(true);
    },

    // @private
    addComponent : function(comp){
        this.items.push(comp);
        comp.on('destroy', this.removeComponent, this);
    },

    // @private
    removeComponent : function(comp){
        Ext.Array.remove(this.items, comp);
    },

    /**
     * このアクションは、元のコンフィグオブジェクトで指定されたハンドラ関数や{@link #setHandler}で設定されたハンドラ関数を手動で使用して実行します。この関数に渡されるすべての引数はハンドラ関数に渡されます。
     * @param {Object...} args ハンドラ関数に渡される可変の数の引数
     */
    execute : function(){
        this.initialConfig.handler.apply(this.initialConfig.scope || Ext.global, arguments);
    }
});