
export default class Node {
  constructor(options) {
    // for (let name in options) {
    //   if (options.hasOwnProperty(name)) {
    //     this[name] = options[name];
    //   }
    // }
    // 节点位移key
    this.id = options.id;
    // 节点自身的数据
    this.data = options.data;
    // 指定节点选择框是否禁用为节点对象的某个属性值
    this.disabled = options.disabled || false;
    // 是否勾选
    this.checked = false;
    // 是否展开
    this.expanded = options.expanded || false;
    // 是否选中
    this.isCurrent = options.isCurrent || false;
    // 节点层级
    this.level = options.level;
    // 是否为叶子节点
    this.isLeaf = options.isLeaf;
    // 父子节点相互关联状态
    this.indeterminate = false;
    // 父节点
    this.parent = options.parent || undefined;
    // 子节点
    this.childNodes = options.childNodes || [];
    // 子节点数量
    this.childNodesSize = this.childNodes.length;
    // 子节点选中的数量
    this.childrenCheckedSize = 0;
    // 节点显示状态
    this.visible = options.visible || false;
  }
  addChildNodes(nodes) {
    this.childNodes = this.childNodes.concat(nodes);
    this.childNodesSize = this.childNodes.length;
  }
  // 设置节点是否为当前选择节点
  setCurrentStatus(status) {
    if (status) {
      this.isCurrent = true;
    } else {
      this.isCurrent = false;
    }
  }
  /**
   * 切换节点展开状态
  */
  toggleExpandStatus() {
    return this.setExpandStatus(!this.expanded);
  }
  /**
   * 修改节点的展开状态
   * status: 节点展开状态
  */
  setExpandStatus(status) {
    // 如果前后状态相同，不处理
    // 如果节点本身是叶子结点，不处理
    if (this.isLeaf) {
      return;
    }

    this.expanded = status;

    if (status) {
      this.visible = true;
      // 由关闭到展开
      // 子节点根据其父节点状态设置是否可见
      for (let item of this.childNodes) {
        if (item.parent.expanded && item.parent.visible) {
          item.visible = true;
        }
      }

      // 该节点展开，说明父节点一定是展开的
      if (this.parent) {
        this.parent.setExpandStatus(true);
      }
    } else {
      // 由展开到关闭
      // 所有孙子节点的可见状为false
      // 不需要更新祖先节点展开状态
      for (let item of this.childNodes) {
        item.visible = false;
      }
    }
  }
  /**
   * 切换节点勾选状态
  */
  toggleCheckedStatus(deep) {
    this.setCheckedStatus(!this.checked, deep);
  }
  /**
   * 设置节点的勾选状态，默认需要更新子节点选中
  */
  setCheckedStatus(checked, deep) {
    const size = this.doSetCheckedStatus(checked, deep);
    // 更新父节点的子节点选中数量
    this.updateParnetCheckedSize(checked, size, deep);
  }
  /**
   * 设置节点的选中状态，默认不需要更新子节点选中
  */
  doSetCheckedStatus(checked, deep = false) {
    let changeSize = 0;
    // 判断前后状态是否一致
    if (this.checked !== checked) {
      this.checked = checked;
      changeSize++;
    }
    if (deep && this.childNodesSize > 0) {
      let childChangeSize = 0;
      // 修改子节点的选中状态
      for (let item of this.childNodes) {
        childChangeSize += item.doSetCheckedStatus(checked, deep);
      }
      changeSize += childChangeSize;
      // 改变节点的子节点选中数量
      this.updateChildrenCheckedSize(checked, childChangeSize, deep, false);
    }
    return changeSize;
  }
  /**
   * 子节点选中数量变更
  */
  updateChildrenCheckedSize(checked, size, deep, changeChecked = true) {
    if (checked) {
      this.childrenCheckedSize += size;
    } else {
      this.childrenCheckedSize -= size;
    }
    if (deep) {
      if (changeChecked) {
        this.checked = this.childrenCheckedSize === this.childNodesSize;
      }
      this.indeterminate = this.childrenCheckedSize > 0 && this.childrenCheckedSize < this.childNodesSize;
    } else {
      this.indeterminate = this.childrenCheckedSize > 0 && this.childrenCheckedSize < this.childNodesSize;
    }
  }
  /**
   * 更新父节点的子节点选中数量
  */
  updateParnetCheckedSize(checked, size, deep) {
    const parent = this.parent;
    if (!parent) {
      return;
    }
    // 判断前后节点的勾选状态是否改变，
    // 若改变，节点状态变化的数量+1
    const oldChecked = parent.checked;
    parent.updateChildrenCheckedSize(checked, size, deep);
    const newChecked = parent.checked;
    if (newChecked === oldChecked) {
      parent.updateParnetCheckedSize(checked, size, deep);
    } else {
      parent.updateParnetCheckedSize(checked, size + 1, deep);
    }
  }
  /**
   * 获取所有子节点
   * deep: 是否需要孙子节点
  */
  getChildNodes(deep) {
    let nodes = [];
    for (let item of this.childNodes) {
      nodes.push(item);
      if (deep) {
        nodes = nodes.concat(item.getChildNodes(deep));
      }
    }
    return nodes;
  }
}
