
import { HashObject } from "../HashObject";
import { Event } from "./Event";
/**
 * 事件触发基类 功能简单，如果需全能的，到时用EventEmitter3，现成库，事件名，事件，once否集合成实例
 * @class EventDispatcher
 * @extends HashObject
 * @public
 * @since 1.0.0
 */
export class EventDispatcher extends HashObject {
    /**
     * 捕获阶段事件名
     */
    protected eventTypes: any = {};
    /**
     * 冒泡阶段事件名
     */
    protected eventTypes1: any = {};

    public constructor() {
        super();
        this._instanceType = "EventDispatcher";
    }

    /**
     * 全局的鼠标事件的监听数对象表，比如{"onMouseMove":9,"onMouseDown":7}
     * @property _MECO
     * @private
     * @since 1.0.0
     */
    private static _MECO: any = {};
    /**
     * 所有鼠标事件的数量
     */
    public static _totalMEC: number = 0;

    /**
     * 看看有多少mouse或者touch侦听数
     * @method getMouseEventCount
     * @return {number}
     * @static
     * @private
     * @since 1.0.0
     * @param {string} type 获取事件类型，默认是所有
     */
    public static getMouseEventCount(type: string = ""): number {
        let count: number = 0;
        if (type == "") {
            //返回所有鼠标事件数
            for (let item in EventDispatcher._MECO) {
                if (item.indexOf("onMouse") == 0) {
                    count += EventDispatcher._MECO[item];
                }
            }
        } else {
            if (EventDispatcher._MECO[type]) {
                count = EventDispatcher._MECO[type];
            }
        }
        return count;
    }

    /**
     * 给对象添加一个侦听
     * @method addEventListener
     * @public
     * @since 1.0.0
     * @param {string} type 侦听类形
     * @param {Function}listener 侦听后的回调方法,如果这个方法是类实例的方法
     * @param context thisObject
     * @param {boolean} useCapture true 捕获阶段 false 冒泡阶段 默认 true
     * @example
     *      this.addEventListener(Event.ADD_TO_STAGE,function(e){trace(this);},this);
     */
    public addEventListener(type: string, listener: Function, context?: any, useCapture: boolean = true): this {
        if (!type) {
            throw new Error("添加侦听的type值为undefined");
        }
        if (!listener) {
            throw new Error("侦听回调函数不能为null");
        }
        let s = this;
        let eventTypes = s.eventTypes;
        if (!useCapture) {
            eventTypes = s.eventTypes1;
        }
        if (!eventTypes[type]) {
            eventTypes[type] = [];
        }
        // if (eventTypes[type].indexOf(listener) < 0) {
        //     eventTypes[type].unshift(listener);
        //     if (type.indexOf("onMouse") == 0) {
        //         s._changeMouseCount(type, true);
        //     }
        // }
        //改成EE的
        for (var i = 0, len = eventTypes[type].length; i < len; i++) {
            let ee: EE = eventTypes[type][i]
            if (ee.fn === listener && ee.context === context) {
                console.log("已添加过该事件")
                return s
            }
        }
        eventTypes[type].unshift(new EE(listener, context || s));
        if (type.indexOf("onMouse") == 0) {
            s._changeMouseCount(type, true);
        }
        return s
    }

    /**
     * 监听一次
     * @param type
     * @param listener
     * @param context
     * @param useCapture
     */
    public once(type: string, listener: Function, context?: any, useCapture: boolean = true): this {
        if (!type) {
            throw new Error("添加侦听的type值为undefined");
        }
        if (!listener) {
            throw new Error("侦听回调函数不能为null");
        }
        let s = this;
        let eventTypes = s.eventTypes;
        if (!useCapture) {
            eventTypes = s.eventTypes1;
        }
        if (!eventTypes[type]) {
            eventTypes[type] = [];
        }
        //考虑是否要检查已添加过该事件
        eventTypes[type].unshift(new EE(listener, context || s, true));
        if (type.indexOf("onMouse") == 0) {
            s._changeMouseCount(type, true);
        }
        return s
    }

    /**
     * 增加或删除相应mouse或touch侦听记数
     * @method _changeMouseCount
     * @private
     * @since 1.0.0
     * @param {string} type
     * @param {boolean} isAdd
     */
    private _changeMouseCount(type: string, isAdd: boolean): void {
        let count = isAdd ? 1 : -1;
        if (!EventDispatcher._MECO[type]) {
            EventDispatcher._MECO[type] = 0;
        }
        EventDispatcher._MECO[type] += count;
        if (EventDispatcher._MECO[type] < 0) {
            EventDispatcher._MECO[type] = 0;
        }
        EventDispatcher._totalMEC += count;
    }

    private _defaultEvent: Event;

    /**
     * 广播侦听
     * @method dispatchEvent
     * @public
     * @since 1.0.0
     * @param {Event|string} event 广播所带的事件对象,如果传的是字符串则直接自动生成一个的事件对象,事件类型就是你传入进来的字符串的值
     * @param {Object} data 广播后跟着事件一起传过去的其他任信息,默认值为null，在传参中
     * @param {boolean} useCapture true 捕获阶段 false 冒泡阶段 默认 true
     * @return {boolean} 如果有收听者则返回true
     * @example
     *      var mySprite=new Sprite(),
     *          yourEvent=new Event("yourCustomerEvent");
     *       yourEvent.data='false2x';
     *       mySprite.addEventListener("yourCustomerEvent",function(e){
     *          trace(e.data);
     *        })
     *       mySprite.dispatchEvent(yourEvent);
     */
    public dispatchEvent(event: any, data: any = null, useCapture: boolean = true): boolean {
        let s = this;
        if (typeof (event) == "string") {
            if (!s._defaultEvent) {
                s._defaultEvent = new Event(event);
            } else {
                s._defaultEvent.reset(event, s);
            }
            event = s._defaultEvent;
        }
        let listeners: EE[] = s.eventTypes[event.type];
        if (!useCapture) {
            listeners = s.eventTypes1[event.type];
        }
        if (listeners) {
            let len = listeners.length;
            if (event.target == null) {
                event.target = s;
            }
            if (data != null) {
                event.data = data;
            }
            for (let i = len - 1; i >= 0; i--) {
                if (!event["_pd"]) {
                    if (listeners[i]) {
                        let listener = listeners[i];
<<<<<<< HEAD
                        let type = event.type;
                        listener.fn.call(listener.context, event)
                        //必须做单独指向，因为有可能出现上面的fn.里执行的就是removeEventListener，导致listeners[i]不存在
                        if (listener.once) {
                            s.removeEventListener(type, listener.fn, listener.context, useCapture);
=======
                        let type = event.type;//防止call事件里触发其他事件导致event被修改；
                        listener.fn.call(listener.context, event)
                        //必须做单独指向，因为有可能出现上面的fn.里执行的就是removeEventListener，导致listeners[i]不存在
                        if (listener.once) {
                            s.removeEventListener(type/*event.type*/, listener.fn, listener.context, useCapture);
>>>>>>> b14a95c820b417eba6decc2ecbcf5732fa698cb4
                        }
                        // listeners[i](event);
                    } else {
                        //空的直接移除，
                        listeners.splice(i, 1);
                    }
                }
            }
            return true;
        } else {
            return false;
        }
    }

    /**
     * 是否有添加过此类形的侦听
     * @method hasEventListener
     * @public
     * @since 1.0.0
     * @param {string} type 侦听类形
     * @param {boolean} useCapture true 捕获阶段 false 冒泡阶段 默认 true
     * @return {boolean} 如果有则返回true
     */
    public hasEventListener(type: string, useCapture: boolean = true): boolean {
        let s = this;
        if (useCapture) {
            if (s.eventTypes[type] && s.eventTypes[type].length > 0) {
                return true
            }
        } else {
            if (s.eventTypes1[type] && s.eventTypes1[type].length > 0) {
                return true
            }
        }
        return false;
    }

    /**
     * 移除对应类型的侦听
     * @method removeEventListener
     * @public
     * @since 1.0.0
     * @param {string} type 要移除的侦听类型
     * @param {Function} listener 及侦听时绑定的回调方法
     * @param context listener和context都相等的才移除，默认自身
     * @param {boolean} useCapture true 捕获阶段 false 冒泡阶段 默认 true
     */
    public removeEventListener(type: string, listener: Function, context?: any, useCapture: boolean = true): this {
        let s = this;
        let listeners: EE[] = s.eventTypes[type];
        if (!useCapture) {
            listeners = s.eventTypes1[type];
        }
        if (listeners) {
            let len = listeners.length;
            let thisObject = context || s;
            for (let i = len - 1; i >= 0; i--) {
                if (listeners[i].fn === listener && listeners[i].context === thisObject) {
                    listeners.splice(i, 1);
                    if (type.indexOf("onMouse") == 0) {
                        s._changeMouseCount(type, false);
                    }
                }
                // if (listeners[i] === listener) {
                //     listeners.splice(i, 1);
                //     if (type.indexOf("onMouse") == 0) {
                //         s._changeMouseCount(type, false);
                //     }
                // }
            }
        }
        return s
    }

    /**
     * 移除对象中所有的侦听
     * @method removeAllEventListener
     * @public
     * @since 1.0.0
     */
    public removeAllEventListener() {
        let s = this;
        for (let type in s.eventTypes) {
            if (type.indexOf("onMouse") == 0) {
                for (let j = 0; j < s.eventTypes[type].length; j++) {
                    s._changeMouseCount(type, false);
                }
            }
        }
        for (let type in s.eventTypes1) {
            if (type.indexOf("onMouse") == 0) {
                for (let j = 0; j < s.eventTypes1[type].length; j++) {
                    s._changeMouseCount(type, false);
                }
            }
        }
        s.eventTypes1 = {};
        s.eventTypes = {};
    }

    destroy(): void {
        let s = this;
        s.removeAllEventListener();
        s.eventTypes = null;
        s.eventTypes1 = null;
    }
}

/**
 * 为了实现带入this和once
 * 暂不做回收处理，因为存在引用fn,context.内存销毁可能出问题
 * 如果非要作回收，回收时必须将fn,context置null；这样还有必要回收？
 */
class EE {
    fn: Function;
    context: any;
    once: boolean;
    constructor(fn: Function, context: any, once: boolean = false) {
        this.fn = fn;
        this.context = context;
        this.once = once;
    }
}
