/***
   * 
   *   发布订阅设计模式
   *    发布一个计划,并且向计划中订阅一个个的方法
   *    当触发某天事件或者到达了某个阶段,可以通知计划中订阅的方法,按照顺序依次执行
   * 
   */

  // 第二版:  支持自定义事件,且一个页面只有一个事件池 [单例设计模式]
let sub = (function(){
    // 创建自定义事件池
    let pond = {};

    // 订阅 / 移除订阅模式 / 通知执行
    // 添加
    const on = function on(event,func){
        !pond.hasOwnProperty(event) ? pond[event] = [] : null;
        let arr = pond[event]; 
        // 去重处理
        !arr.includes(func) ? arr.push(func) : null; 
    }

    // 移除 
    const off = function off(event,func){
        let arr = pond[event]; 
        if(!arr) return ;
        for(let i = 0; i < arr.length; i++){
            if(arr[i] === func){
                // 会导致数组塌陷, 带来一些无法控制的问题
                // arr.splice(i,1);
                arr[i] = null;
                break;
            }
        }
    }

    // 执行
    const fire = function fire(event,...params){
        let arr = pond[event]; 
        if(!arr) return ;
        for(let i=0;i<arr.length;i++){
            let itemFunc = arr[i];
            if(typeof itemFunc !== "function"){
                // 移除 null 
                arr.splice(i,1);
                i--;
                continue;
            }
            itemFunc(...params);
        }
        console.log(pond);
    }

    return {
        on,
        off,
        fire
    }
})();

// 测试
const fn1 = (x,y)=>{
    console.log('fn1',x,y); 
}
const fn2 = ()=>{
    console.log('fn2'); 
    sub.off('bodyClick',fn1);
    sub.off('bodyClick',fn2);
}
const fn3 = ()=>{
    console.log('fn3'); 
}
const fn4 = ()=>{
    console.log('fn4'); 
}
const fn5 = (x,y)=>{
    console.log('fn5',x,y); 
}

document.body.onclick = function () { 
   // 通知事件池的方法执行
   sub.fire('bodyClick',10,20);
}
  
// ;(()=>{
//     function sum(){
//         console.log('sum');
//     }
//     sub.on(sum);
// })();

sub.on('bodyClick',fn1);
sub.on('bodyClick',fn2);
sub.on('bodyClick',fn3);
sub.on('bodyClick',fn4);
sub.on('bodyClick',fn5);


// ---

setTimeout(()=>{
    sub.fire('AAA',100,200);
},1000);

sub.on('AAA',fn1);
sub.on('AAA',fn3);