//-----------------数据挟持Observer--------
//-----------------数据渲染Compile---------
//-----------------数据订阅Pubsub----------




class Observer{
  constructor(data, sub) {
    this.sub = sub
    this.data = data
    for(let key in data) {
      this._listen(data, key, data[key])
    }
  }
  _listen(obj, key, val) {
    this.dataProxy = new Proxy(obj, {
      get: (t, name) => {
        console.log("get===>", name, ":", t[name])
        return t[name]
      },
      set: (t, name, newVal) => {
        console.log("set===>", name, ":", newVal)
        t[name] = newVal
        this.sub.public(name, newVal)
        return true
      },
    })
  }
}

class MyVue {
  constructor(options) {
    const {el, data} = options;
    this.el = document.querySelector(el)
    // 订阅者注册
    this.sub = new Pubsub()
    
    // 数据挟持
    const vm = new Observer(data, this.sub)
    this.vm = vm.dataProxy
  
    // 数据渲染
    this.compile = new Compile(this.el, this.vm, this.sub)
    this.flag = this.compile.createFlag()
    this.el.appendChild(this.flag)
  }
}

class Compile {
  constructor(el, vm, sub) {
    this.el = el
    this.vm = vm
    this.sub = sub
  }
  createFlag() {
    let flag = document.createDocumentFragment()
    let child;
    while(child = this.el.firstChild) {
      this.compile(child)
      flag.appendChild(child)
    }
    return flag
  }
  compile(node) {
    switch(node.nodeType){
      case 1: // element
        const reg = /\{\{(.*)\}\}/;
        if(reg.test(node.textContent)) {
          let name  = RegExp.$1;
          node.textContent = this.vm[name]
          this.sub.subscribe(name, (newVal) => {
            node.textContent = newVal
          })
        }
        let attr = node.attributes
        if(attr.hasOwnProperty('x-model')){
          let name = attr['x-model'].nodeValue
          node.value = this.vm[name]
          const self = this
          node.addEventListener('input', (e) => {
            self.vm[name] = e.target.value
          })
          this.sub.subscribe(name, (newVal) => {
            if(node.value !== newVal)
              node.value = newVal
          })
        }
        break;
      case 3: // text
        break;
      default: 
        console.log("no nodetype")
    }
  }
}

class Pubsub{
  constructor(){
    this.subs = {}
  }
  // 订阅者注册
  subscribe(name, func) {
    this.subs[name] = this.subs[name] ? this.subs[name] : []
    this.subs[name].push(func)
  }
  // 发布
  public(name, args) {
    console.log(this.subs[name])
    if(!this.subs[name]) return;
    this.subs[name].map(func => func(args))
  }
}
