protected CoverTreeNode batch_insert(Integer p, int max_scale, // current
                                                                 // scale/level
      int top_scale, // max scale/level for this dataset
      Stack<DistanceNode> point_set, // set of points that are nearer to p
                                        // [will also contain returned unused
                                        // points]
      Stack<DistanceNode> consumed_set) // to return the set of points that have
                                        // been used to calc. max_dist to a
                                        // descendent
      // Stack<Stack<DistanceNode>> stack) //may not be needed
      {
    if (point_set.length == 0) {
      CoverTreeNode leaf = new_leaf(p);
      leaf.nodeid = m_NumNodes;
      m_NumNodes++; // incrementing node count
      m_NumLeaves++; // incrementing leaves count
      return leaf;
    } else {
      double max_dist = max_set(point_set); // O(|point_set|) the max dist
      // in point_set to point "p".
      int next_scale = Math.min(max_scale - 1, get_scale(max_dist));
      if (next_scale == Integer.MIN_VALUE) { // We have points with distance
        // 0. if max_dist is 0.
        Stack<CoverTreeNode> children = new Stack<CoverTreeNode>();
        CoverTreeNode leaf = new_leaf(p);
        leaf.nodeid = m_NumNodes;
        children.push(leaf);
        m_NumLeaves++;
        m_NumNodes++; // incrementing node and leaf count
        while (point_set.length > 0) {
          DistanceNode tmpnode = point_set.pop();
          leaf = new_leaf(tmpnode.idx);
          leaf.nodeid = m_NumNodes;
          children.push(leaf);
          m_NumLeaves++;
          m_NumNodes++; // incrementing node and leaf count
          consumed_set.push(tmpnode);
        }
        CoverTreeNode n = new_node(p); // make a new node out of p and assign
        // it the children.
        n.nodeid = m_NumNodes;
        m_NumNodes++; // incrementing node count
        n.scale = 100; // A magic number meant to be larger than all scales.
        n.max_dist = 0; // since all points have distance 0 to p
        n.num_children = children.length;
        n.children = children;
        return n;
      } else {
        Stack<DistanceNode> far = new Stack<DistanceNode>();
        split(point_set, far, max_scale); // O(|point_set|)

        CoverTreeNode child = batch_insert(p, next_scale, top_scale, point_set,
            consumed_set);

        if (point_set.length == 0) { // not creating any node in this
          // recursive call
          // push(stack,point_set);
          point_set.replaceAllBy(far); // point_set=far;
          return child;
        } else {
          CoverTreeNode n = new_node(p);
          n.nodeid = m_NumNodes;
          m_NumNodes++; // incrementing node count
          Stack<CoverTreeNode> children = new Stack<CoverTreeNode>();
          children.push(child);

          while (point_set.length != 0) { // O(|point_set| * num_children)
            Stack<DistanceNode> new_point_set = new Stack<DistanceNode>();
            Stack<DistanceNode> new_consumed_set = new Stack<DistanceNode>();
            DistanceNode tmpnode = point_set.pop();
            double new_dist = tmpnode.dist.last();
            consumed_set.push(tmpnode);

            // putting points closer to new_point into new_point_set (and
            // removing them from point_set)
            dist_split(point_set, new_point_set, tmpnode, max_scale); // O(|point_saet|)
            // putting points closer to new_point into new_point_set (and
            // removing them from far)
            dist_split(far, new_point_set, tmpnode, max_scale); // O(|far|)

            CoverTreeNode new_child = batch_insert(tmpnode.idx, next_scale,
                top_scale, new_point_set, new_consumed_set);
            new_child.parent_dist = new_dist;

            children.push(new_child);

            // putting the unused points from new_point_set back into
            // point_set and far
            double fmax = dist_of_scale(max_scale);
            tmpnode = null;
            for (int i = 0; i < new_point_set.length; i++) { // O(|new_point_set|)
              tmpnode = new_point_set.element(i);
              tmpnode.dist.pop();
              if (tmpnode.dist.last() <= fmax)
                point_set.push(tmpnode);
              else
                far.push(tmpnode);
            }
            // putting the points consumed while recursing for new_point
            // into consumed_set
            tmpnode = null;
            for (int i = 0; i < new_consumed_set.length; i++) { // O(|new_point_set|)
              tmpnode = new_consumed_set.element(i);
              tmpnode.dist.pop();
              consumed_set.push(tmpnode);
            }
          }// end while(point_size.size!=0)
          point_set.replaceAllBy(far); // point_set=far;
          n.scale = top_scale - max_scale;
          n.max_dist = max_set(consumed_set);
          n.num_children = children.length;
          n.children = children;
          return n;
        }// end else if(pointset!=0)
      }// end else if(next_scale != -214....
    }// end else if(pointset!=0)
  }