@Override
  public CRDTMessage remove(UnorderedNode<T> subtree) throws PreconditionException {
    if (wcp.lookup().getRoot() == subtree) throw new PreconditionException("Removing root");
    if (!wcp.lookup().contains(subtree))
      throw new PreconditionException("Removing node " + subtree + " not in the tree");

    CRDTMessage msg = null;

    for (List<T> w : wcp.toBeRemoved(subtree)) {
      CRDTMessage del = words.remove(w);
      msg = msg == null ? del : msg.concat(del);
    }
    return msg;
  }
  @Override
  public CRDTMessage add(UnorderedNode<T> father, T element) throws PreconditionException {
    if (!wcp.lookup().contains(father))
      throw new PreconditionException("Adding node " + element + " with father not in the tree");
    if (father.getChild(element) != null)
      throw new PreconditionException("Adding node " + element + " already present under father");

    CRDTMessage msg = null;
    for (List<T> wf : wcp.addMapping(father)) {
      List<T> w = new Word(wf, element);
      CRDTMessage add = words.add(w);
      msg = msg == null ? add : msg.concat(add);
    }
    return msg;
  }
 @Override
 public String toString() {
   return "WordTree<"
       + words.getClass()
       + ','
       + wcp.getClass()
       + ">{"
       + this.getReplicaNumber()
       + '}';
 }
 @Override
 public UnorderedNode<T> getRoot() {
   return (UnorderedNode<T>) wcp.lookup().getRoot();
 }
 @Override
 public Tree<T> lookup() {
   return wcp.lookup();
 }
 @Override
 public synchronized void addObserver(Observer obsrvr) {
   super.addObserver(obsrvr);
   ((HashTree<T>) wcp.lookup()).addObserver(obsrvr);
 }