// src/vuex/store.js
import { applyMixin } from './install'
import ModuleCollection from './module/module-collection'
import { forEachValue } from './utils'

export let Vue
const installModule = (store, path, module, rootState) => {
  let namespaced = store._modules.getNamespace(path)
  console.log('namespaced', namespaced)

  // 将子模块的状态定义到根模块
  if (path.length > 0) {
    const parent = path.slice(0, -1).reduce((memo, current) => {
      return memo[current]
    }, rootState)
    // 这样添加的状态不是响应式的
    // parent[path[path.length - 1]] = module.state

    // 新增不存在的属性属性使用set,将其设置为响应式的
    Vue.set(parent, path[path.length - 1], module.state)
  }

  module.forEachMutation((mutation, key) => {
    store.mutations[namespaced + key] = store.mutations[namespaced + key] || []
    store.mutations[namespaced + key].push((payload) => mutation.call(store, module.state, payload))
  })
  module.forEachAction((action, key) => {
    store.actions[namespaced + key] = store.actions[namespaced + key] || []
    store.actions[namespaced + key].push((payload) => action.call(store, store, payload))
  })
  module.forEachChildren((childModule, key) => {
    installModule(store, path.concat(key), childModule, rootState)
  })
  module.forEachGetters((gettersFn, key) => {
    store.wrapGetters[namespaced + key] = () => {
      return gettersFn.call(store, module.state)
    }
  })
}

function resetStoreVM(store, state) {
  const computed = {}
  forEachValue(store.wrapGetters, (fn, key) => {
    computed[key] = fn
    Object.defineProperty(store.getters, key, {
      get: () => store._vm[key]
    })
  })
  store._vm = new Vue({
    data: {
      $$state: state
    },
    computed
  })
}

export class Store {
  constructor(options) {
    // 可能用户会有嵌套的module
    this._modules = new ModuleCollection(options)
    console.log('ddd', this._modules)
    this.mutations = {} // 将用户所有模块的mutation都放到这个对象中
    this.actions = {} // 将用户所有模块的action放到这个对象中
    this.getters = {}
    
    this.wrapGetters = {} // 用于临时存放所有的getters
    const state = options.state // 获取用户状态

    // 将用户所有模块的 mutation、action、state、getters 都放到对象中
    installModule(this, [], this._modules.root, state)
    resetStoreVM(this, state)
    console.log('this.state', this.state)
    console.log('this.getters', this.getters)
    console.log('this.mutations', this.mutations)
    console.log('this.actions', this.actions)
  }
  get state() {
    return this._vm._data.$$state
  }
  // commit 方法用于触发相应type的 mutations
  commit = (type, payload) => {
    this.mutations[type] && this.mutations[type].forEach(fn => fn(payload))
  }
  // dispatch 方法用于触发相应type的 actions
  dispatch = (type, payload) => {
    this.actions[type] && this.actions[type].forEach(fn => fn(payload))
  }
}

export const install = (_Vue) => {
  Vue = _Vue
  applyMixin(Vue)
}









 
 
 
 
 
 
 
 
 





















// src/vuex/module/module-collection.js
import { forEachValue } from "../utils"
import Module from "./module"

export default class ModuleCollection {
  constructor(options) { // 遍历用户的属性对数据进行格式化
    this.root = null
    this.register([], options)
  }
  // 获取 namespaced 路径, 整理成例如 a/c/e 这种形式
  getNamespace(path) {
    // 以 ['a', 'c', 'e'] 为例
    let module = this.root
    return path.reduce((namespace, key) => { // a/c/e/
      module = module.getChild(key)
      return namespace + (module.namespaced ? key + '/' : '')
    }, '')
  }
  register(path, rootModule) {
    const newModule = new Module(rootModule)
    if (path.length == 0) {
      this.root = newModule
    }else {
      const parent = path.slice(0, -1).reduce((memo, current) => {
        // return memo._children[current]
        return memo.getChild(current)
      }, this.root)
      // parent._children[path[path.length - 1]] = newModule
      parent.addChild(path[path.length - 1], newModule)
    }
    // 检测是否配置了 modules 属性
    if (rootModule.modules) {
      forEachValue(rootModule.modules, (module, moduleName) => {
        this.register(path.concat(moduleName), module)
      })
    }
  }
}









 
 
 
 


























// src/vuex/module/module.js
import { forEachValue } from "../utils"

export default class Module {
  constructor(rawModule) {
    this._raw = rawModule
    this._children = {}
    this.state = rawModule.state
  }
  // 便于获取 namespaced
  get namespaced() {
    return this._raw.namespaced
  }
  getChild(key) {
    return this._children[key]
  }
  addChild(key, module) {
    this._children[key] = module
  }
  forEachMutation(fn) {
    if (this._raw.mutations) { // 有mutation就遍历这个mutation
      forEachValue(this._raw.mutations, fn)
    }
  }
  forEachAction(fn) {
    if (this._raw.actions) { // 有action就遍历这个actions
      forEachValue(this._raw.actions, fn)
    }
  }
  forEachGetters(fn) {
    if (this._raw.getters) {
      forEachValue(this._raw.getters, fn)
    }
  }
  forEachChildren(fn) {
    forEachValue(this._children, fn)
  }
}