class Link {
  constructor(to, from) {
  	this.from = from;
    this.to = to;
  }
}
class Node {
	constructor(id){
  	this.id = id;
  }
  
}
class Tree {
	constructor(NodeType){
		this.root = new NodeType(-1);
    this.links = {
    	[this.root.id]: this._emptyLink()
    };
	}
    
  _emptyLink() {
    return {
      out: new Set(),
      in: null
    };
  }
  
  updateLinkOut(node, link) {
    this.links[node.id].out.add(link);
  }
  updateLinkIn(node, link) {
    this.links[node.id].in = link;
  }
  
  insert(node, parentNode = this.root) {
    this.links[node.id] = this._emptyLink();
    let newLink = new Link(node,parentNode);
    this.updateLinkIn(node, newLink);
    this.updateLinkOut(parentNode, newLink);
  }
  
  traverseTree(current) {
		if(!current) current = this.root;
    
    console.log(current.id);
    let set = this.links[current.id].out;
    return set.forEach((link, index) => {
      let next = link.to;// WOW
      return next && this.traverseTree(next);
    });
  }
   bfs(current = this.root) {
    if(!current) current = this.root;
    var stack = [current] , node;
    while(stack.length > 0) {
      node = stack.shift();
      let set = this.links[node.id].out;   
	  set.forEach((item) => stack.push(item.to));
      // Do something
      console.log(node.id)
    }
  }
	
	removeLink(link) {
   		let parentOut = this.links[link.from.id].out;
    	parentOut.delete(link);
    	this.links[link.to.id].in = null;
  	}
	removeNode(node){
    	let link = this.links[node.id].in;
		this.removeLink(link);
    	return node;
	}
	updateNode(node, newNode) {
   		//update Links 
  	}
 	updateLink(link, newLink) {
    	// update Link
  	}
}

var tree = new Tree(Node);
var child1 = new Node(1);
var child2  = new Node(2);
tree.insert(child1);
tree.insert(child2);
tree.insert(new Node('L2-1-1'), child1);
tree.insert(new Node('L2-1-2'), child1);
tree.insert(new Node('L2-2-1'), child2);
tree.traverseTree();
console.log("----- BFS ---- ");
tree.bfs();
tree.removeNode(child1);
console.log("----- BFS ---- Child1");
tree.bfs(child1);