/**
 * @class Ext.EventManager
 * DOM要素のイベントハンドラを登録します。
 * 
 * このクラスは推奨されません。DOM要素にリスナを関連付けるには、Ext.dom.ElementのAPIを使ってください。例:
 * 
 *     var element = Ext.get('myId');
 *     
 *     element.on('click', function(e) {
 *         // event handling logic here
 *     });
 *
 * @singleton
 * @deprecated 5.0.0
 */
Ext.define('Ext.EventManager', {
    singleton: true,

    mouseLeaveRe: /(mouseout|mouseleave)/,
    mouseEnterRe: /(mouseover|mouseenter)/,

    /**
     * 要素にイベントハンドラを付加します。短縮形の{@link #on}でも同じです。通常、このバージョンを呼び出せるよう、要素上で{@link Ext.dom.Element#addListener}が直接使用されます。
     *
     * {@link Ext.EventManager#on}は{@link Ext.EventManager#addListener}のエイリアスです。
     *
     * @param {String/Ext.dom.Element/HTMLElement/Window} el イベントハンドラを割り当てるHTML要素かid。
     *
     * @param {String} eventName リッスンするイベント名。プロパティ名がイベント名であるオブジェクトでも可能です。
     *
     * @param {Function/String} [handler] イベントによって呼び出されるハンドラ関数。スコープが備わっていない場合、文字列のパラメータは`scope`オブジェクトや要素オブジェクトにおいてメソッド名であると仮定されます。
     * @param {Ext.event.Event} handler.event イベントが記述されている{@link Ext.event.Event EventObject}。
     * @param {Ext.dom.Element} handler.target イベントのターゲットである要素。`delegate`オプションを使ってフィルタリングできることに注意してください。
     * @param {Object} handler.options addListenerコールからのオプションオブジェクト。
     *
     * @param {Object} [scope] ハンドラ関数が実行されるスコープ(`this`の参照)。デフォルトはこの要素です。
     *
     * @param {Object} [options] ハンドラ設定プロパティを含むオブジェクト。これには、以下のプロパティのいずれかを含めることができます(これらのオプションの使用法の例については、{@link Ext.dom.Element#addListener}を参照してください)。
     * @param {Object} options.scope ハンドラ関数が実行されるスコープ(`this`の参照)。デフォルトはこの要素です。
     * @param {String} options.delegate ターゲットをフィルタリングする、またはターゲットの子孫を探すシンプルなセレクタです。シンプルセレクタについては、{@link Ext.dom.Query}を参照してください。
     * @param {Boolean} options.stopEvent trueにすると、イベントを停止します。パブリング(伝播)を停止し、デフォルトのアクションを防ぎます。
     * @param {Boolean} options.preventDefault trueにすると、デフォルトのアクションを防止します。
     * @param {Boolean} options.stopPropagation trueにすると、イベントのバブリングを防止します。
     * @param {Boolean} options.normalized falseにすると、ハンドラ関数にExt.event.Eventの代わりにブラウザイベントを渡します。
     * @param {Number} options.delay イベントの発火後、ハンドラの起動を遅らせるミリ秒単位の秒数。
     * @param {Boolean} options.single trueの場合、一度イベントによってハンドラが実行された後、そのハンドラを無効にするハンドラを追加します。
     * @param {Number} options.buffer ハンドラは、{@link Ext.util.DelayedTask}の中で、指定された時間分(ミリ秒)だけ遅延して実行されるようにスケジューリングされます。イベントがその時間内に再び発火する場合は、オリジナルのハンドラは*呼び出されず*、新しいハンドラが代わりに予定されます。
     * @param {Ext.dom.Element} options.target イベントが子ノードから*バブリングされたときではなく*、ターゲット要素で発火した時のみハンドラを呼び出します。
     * @param {Boolean} options.capture キャプチャを起動して子孫要素よりも*前*にターゲット要素上でリスナを発火する場合は、`true`に設定します。通常、イベントはターゲット要素と共にスタートして上位の先祖要素に向かってプロパゲーションしますが、キャプチャされた要素はDOMの上位から下位の子孫要素に向かってプロパゲーションします。このオプションは、javascriptのaddEventListenerメソッドのuseCaptureパラメータと同じものです。
     */
    addListener: function(element, eventName, fn, scope, options) {
        //<debug>
        Ext.log.warn("Ext.EventManager is deprecated. " +
            "Use Ext.dom.Element#addListener to attach an event listener.");
        //</debug>
        Ext.get(element).addListener(eventName, fn, scope, options);
    },

    /**
     * ブラウザのウィンドウサイズが変更されたときに通知するリスナを追加し、リサイズイベントのバッファリング(100ミリ秒)を提供し、ハンドラに新しいビューポートの幅と高さを渡します。
     * @param {Function} fn      ウィンドウのリサイズイベントによって呼び出されるハンドラ関数。
     * @param {Object}   scope   ハンドラ関数実行時のスコープ(<code>this</code>参照)。デフォルトはブラウザウィンドウ。
     * @param {Boolean}  [options] {@link Ext.dom.Element#addListener}に渡されるオプションのオブジェクト
     * @deprecated 5.0.0
     */
    onWindowResize: function(fn, scope, options) {
        //<debug>
        Ext.log.warn("Ext.EventManager is deprecated. " +
            "Use Ext.on('resize', fn) to attach a window resize listener.");
        //</debug>
        Ext.GlobalEvents.on('resize', fn, scope, options);
    },

    /**
     * ブラウザのwindowが破棄される(unload)ときに通知されるリスナに追加します。
     * @param {Function} fn      ウィンドウのunloadイベントによって呼び出されるハンドラ関数。
     * @param {Object}   scope   ハンドラ関数実行時のスコープ(<code>this</code>参照)。デフォルトはブラウザウィンドウ。
     * @param {Boolean}  options {@link Ext.dom.Element#addListener}に渡されるオプションのオブジェクト
     * @deprecated 5.0.0
     */
    onWindowUnload: function(fn, scope, options) {
        //<debug>
        Ext.log.warn("Ext.EventManager is deprecated. " +
            "Use Ext.getWin().on('unload', fn) to attach a window unload listener.");
        //</debug>
        Ext.getWin().on('unload', fn, scope, options);
    },

    /**
     * 要素とその子に以前追加されたリスナを再帰的に削除します。通常、このメソッドを呼び出すためには、要素上の{@link Ext.dom.Element#clearListeners}が直接使われます。
     * @param {String/Ext.dom.Element/HTMLElement/Window} el すべてのイベントハンドラを削除するid、またはHTML要素。
     * @param {String} eventName (optional) イベント名。
     * @deprecated 5.0.0
     */
    purgeElement: function(element, eventName) {
        //<debug>
        Ext.log.warn("Ext.EventManager is deprecated. " +
            "Call clearListeners() on a Ext.dom.Element to remove all listeners.");
        //</debug>
        Ext.get(element).clearListeners();
    },

    /**
     * 要素からイベントハンドラを削除します。通常、このメソッドを呼び出すためには、要素上の{@link Ext.dom.Element#clearListeners}が直接使われます。
     * @param {String/Ext.dom.Element/HTMLElement/Window} el すべてのイベントハンドラを削除するid、またはHTML要素。
     * @deprecated 5.0.0
     */
    removeAll: function(element) {
        //<debug>
        Ext.log.warn("Ext.EventManager is deprecated. " +
            "Call clearListeners() on a Ext.dom.Element to remove all listeners.");
        //</debug>
        Ext.get(element).clearListeners();
    },

    /**
     * 要素からイベントハンドラを削除します。短縮バージョンの{@link #un}も同じです。このバージョンを呼び出すためには、通常、要素上の{@link Ext.dom.Element#removeListener}が直接使われます。
     *
     * {@link Ext.EventManager#on}は{@link Ext.EventManager#addListener}のエイリアスです。
     *
     * @param {String/Ext.dom.Element/HTMLElement/Window} el リスナを削除するid、またはHTML要素。
     * @param {String} eventName イベント名。
     * @param {Function} fn 削除するハンドラ関数。**これは、{@link #addListener}コールに渡される関数に対する参照である必要があります。**
     * @param {Object} scope リスナ追加時にスコープ(`this`参照)が指定されていた場合には、これも同じオブジェクトを参照している必要があります。
     */
    removeListener: function(element, eventName, fn, scope, options) {
        //<debug>
        Ext.log.warn("Ext.EventManager is deprecated. " +
            "Use Ext.dom.Element#removeListener to remove an event listener.");
        //</debug>
        Ext.get(element).removeListener(eventName, fn, scope, options);
    },

    /**
     * 渡されたwindowのrisizeリスナを削除します。
     * @param {Function} fn        イベントによって呼び出されるメソッド
     * @param {Object}   scope    ハンドラのスコープ。
     * @deprecated 5.0.0
     */
    removeResizeListener: function(fn, scope) {
        //<debug>
        Ext.log.warn("Ext.EventManager is deprecated. " +
            "Use Ext.on('resize', fn) to detach a window resize listener.");
        //</debug>
        Ext.GlobalEvents.un('resize', fn, scope);
    },

    /**
     * 渡されたwindowのunloadリスナを削除します。
     * @param {Function} fn        イベントによって呼び出されるメソッド
     * @param {Object}   scope    ハンドラのスコープ。
     * @deprecated 5.0.0
     */
    removeUnloadListener: function(fn, scope) {
        //<debug>
        Ext.log.warn("Ext.EventManager is deprecated. " +
            "Use Ext.getWin().un('unload', fn) to detach a window unload listener.");
        //</debug>
        Ext.getWin().un('unload', fn, scope);
    },

    /**
     * イベントを中止します(preventDefaultとstopPropagation)
     * @param {Event} event 停止するイベント
     * @deprecated 5.0.0
     */
    stopEvent: function(event) {
        //<debug>
        Ext.log.warn("Ext.EventManager.stopEvent() is deprecated. " +
            "Call stopEvent() directly on the Ext.event.Event instance instead.");
        //</debug>
        this.stopPropagation(event);
        this.preventDefault(event);
    },

    /**
     * イベントのバブリングをキャンセルします。
     * @param {Event} event バブリングを停止するイベント。
     * @deprecated 5.0.0
     */
    stopPropagation: function(event) {
        //<debug>
        Ext.log.warn("Ext.EventManager.stopPropagation() is deprecated. " +
            "Call stopPropagation() directly on the Ext.event.Event instance instead.");
        //</debug>
        event = event.browserEvent || event;
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    },

    /**
     * ブラウザのデフォルトのイベント処理を防止します。
     * @param {Event} event デフォルトを回避するイベント
     * @deprecated 5.0.0
     */
    preventDefault: function(event) {
        //<debug>
        Ext.log.warn("Ext.EventManager.preventDefault() is deprecated. " +
            "Call preventDefault() directly on the Ext.event.Event instance instead.");
        //</debug>
        event = event.browserEvent || event;
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
            // Some keys events require setting the keyCode to -1 to be prevented
            try {
              // all ctrl + X and F1 -> F12
              if (event.ctrlKey || event.keyCode > 111 && event.keyCode < 124) {
                  event.keyCode = -1;
              }
            } catch (e) {
                // see this outdated document http://support.microsoft.com/kb/934364/en-us for more info
            }
        }
    },

    /**
     * 要素のidを取得します。割り当てられていない場合、自動でidを割り当てます。
     * @param {HTMLElement/Ext.dom.Element} element idを取得する要素。
     * @return {String} id
     * @deprecated 5.0.0
     */
    getId: function(element) {
        //<debug>
        Ext.log.warn("Ext.EventManager.getId() is deprecated. " +
            "Call Ext.get() to assign ids to elements.");
        //</debug>
        element = Ext.get(element);
        return element.id;
    },

    /**
     * イベントから関連するターゲットを取得します。
     * @param {Object} event イベント
     * @return {HTMLElement} 関連するターゲット。
     * @deprecated 5.0.0
     */
    getRelatedTarget: function(event) {
        //<debug>
        Ext.log.warn("Ext.EventManager.getRelatedTarget() is deprecated. " +
            "Call getRelatedTarget() directly on the Ext.event.Event instance instead.");
        //</debug>
        event = event.browserEvent || event;
        var target = event.relatedTarget;
        if (!target) {
            if (this.mouseLeaveRe.test(event.type)) {
                target = event.toElement;
            } else if (this.mouseEnterRe.test(event.type)) {
                target = event.fromElement;
            }
        }
        return this.resolveTextNode(target);
    },

    /**
     * イベントからx座標を取得します。
     * @param {Object} event イベント
     * @return {Number} x座標
     * @deprecated 5.0.0
     */
    getPageX: function(event) {
        //<debug>
        Ext.log.warn("Ext.EventManager.getPageX() is deprecated. " +
            "Call getX() directly on the Ext.event.Event instance instead.");
        //</debug>
        return this.getPageXY(event)[0];
    },

    /**
     * イベントからxとy座標を取得します。
     * @param {Object} event イベント
     * @return {Number[]} x/y座標
     * @deprecated 5.0.0
     */
    getPageXY: function(event) {
        //<debug>
        Ext.log.warn("Ext.EventManager.getPageXY() is deprecated. " +
            "Call getXY() directly on the Ext.event.Event instance instead.");
        //</debug>
        event = event.browserEvent || event;
        var x = event.pageX,
            y = event.pageY,
            docEl = doc.documentElement,
            body = doc.body;

        // pageX/pageY not available (undefined, not null), use clientX/clientY instead
        if (!x && x !== 0) {
            x = event.clientX + (docEl && docEl.scrollLeft || body && body.scrollLeft || 0) - (docEl && docEl.clientLeft || body && body.clientLeft || 0);
            y = event.clientY + (docEl && docEl.scrollTop  || body && body.scrollTop  || 0) - (docEl && docEl.clientTop  || body && body.clientTop  || 0);
        }
        return [x, y];
    },

    /**
     * イベントからy座標を取得します。
     * @param {Object} event イベント
     * @return {Number} y座標
     * @deprecated 5.0.0
     */
    getPageY: function(event) {
        //<debug>
        Ext.log.warn("Ext.EventManager.getPageY() is deprecated. " +
            "Call getY() directly on the Ext.event.Event instance instead.");
        //</debug>
        return this.getPageXY(event)[1];
    },

    /**
     * イベントのターゲットを取得します。
     * @param {Object} event イベント
     * @return {HTMLElement} ターゲット
     * @deprecated 5.0.0
     */
    getTarget: function(event) {
        //<debug>
        Ext.log.warn("Ext.EventManager.getTarget() is deprecated. " +
            "Call getTarget() directly on the Ext.event.Event instance instead.");
        //</debug>
        event = event.browserEvent || event;
        return EventManager.resolveTextNode(event.target || event.srcElement);
    },

    // technically no need to browser sniff this, however it makes
    // no sense to check this every time, for every event, whether
    // the string is equal.
    /**
     * ブラウザの違いに対して、いかなるテキストノードを分解します。
     * @private
     * @param {HTMLElement} node ノード
     * @return {HTMLElement} 変換されたノード
     * @deprecated 5.0.0
     */
    resolveTextNode: Ext.isGecko ?
        function(node) {
            if (node) {
                // work around firefox bug, https://bugzilla.mozilla.org/show_bug.cgi?id=101197
                var s = HTMLElement.prototype.toString.call(node);
                if (s !== '[xpconnect wrapped native prototype]' && s !== '[object XULElement]') {
                    return node.nodeType == 3 ? node.parentNode: node;
                }
            }
        }
        :
        function(node) {
            return node && node.nodeType == 3 ? node.parentNode: node;
        }
}, function(EventManager) {
    /**
     * @member Ext.EventManager
     * @method on
     * @inheritdoc Ext.EventManager#addListener
     */
    EventManager.on = EventManager.addListener;

    /**
     * @member Ext.EventManager
     * @method un
     * @inheritdoc Ext.EventManager#removeListener
     */
    EventManager.un = EventManager.removeListener;
});