private RedBlackNode find(int value, RedBlackNode node) {
    if (node.getValue() == value) {
      return node;
    } else if (value < node.getValue()) {
      if (!((RedBlackNode) node.getLeft()).isFake()) {
        return find(value, (RedBlackNode) node.getLeft());
      }
    } else if (value > node.getValue()) {
      if (!((RedBlackNode) node.getRight()).isFake()) {
        return find(value, (RedBlackNode) node.getRight());
      }
    }

    // value not in tree
    return null;
  }
 private void rotate_right(RedBlackNode x) {
   RedBlackNode y = (RedBlackNode) x.getLeft();
   x.setLeft(y.getRight());
   if (!((RedBlackNode) y.getRight()).isFake()) {
     y.getRight().setParent(x);
   }
   y.setParent(x.getParent());
   if (x.getParent() == null) root = y;
   else {
     if (x.isRight()) {
       x.getParent().setRight(y);
     } else x.getParent().setLeft(y);
   }
   y.setRight(x);
   x.setParent(y);
 }
 // returns null if not there
 private RedBlackNode findParent(int value) {
   RedBlackNode tmp = root;
   RedBlackNode prevPtr = null;
   while (!tmp.isFake()) {
     prevPtr = tmp;
     if (value < tmp.getValue()) tmp = (RedBlackNode) tmp.getLeft();
     else tmp = (RedBlackNode) tmp.getRight();
   }
   return prevPtr;
 }
  public void insert(int value) {
    // Case 1
    if (root == null) {
      root = new RedBlackNode(BLACK);
      root.setValue(value);
      // insert fake leaves
      root.setRight(new RedBlackNode(true, true));
      root.setLeft(new RedBlackNode(true, true));
      return;
    }

    // insert node as red
    RedBlackNode tmp = findParent(value);
    RedBlackNode child = new RedBlackNode(RED);
    child.setValue(value);
    child.setParent(tmp);
    if (value < tmp.getValue()) {
      tmp.setLeft(child);
    } else {
      tmp.setRight(child);
    }

    // insert fake leaves
    child.setRight(new RedBlackNode(true, true));
    child.setLeft(new RedBlackNode(true, true));

    RedBlackNode x = child;
    while ((x != root) && (((RedBlackNode) x.getParent()).getColor() == RED)) {
      if (x.getParent().isLeft()) {
        RedBlackNode gParent = grandparent(x);
        RedBlackNode uncle = (RedBlackNode) gParent.getRight();
        if (uncle.getColor() == RED) {
          ((RedBlackNode) child.getParent()).setBlack();
          uncle.setBlack();
          gParent.setRed();
          x = gParent; // move x up the tree
        } else {
          if (x.isRight()) {
            // move x up and rotate
            x = (RedBlackNode) x.getParent();
            rotate_left(x);
          }
          ((RedBlackNode) x.getParent()).setBlack();
          grandparent(x).setRed();
          rotate_right(grandparent(x));
        }
      } else { // parent is right child
        RedBlackNode gParent = grandparent(x);
        RedBlackNode uncle = (RedBlackNode) gParent.getLeft();
        if (uncle.getColor() == RED) {
          ((RedBlackNode) child.getParent()).setBlack();
          uncle.setBlack();
          gParent.setRed();
          x = gParent; // move x up the tree
        } else {
          if (x.isLeft()) {
            // move x up and rotate
            x = (RedBlackNode) x.getParent();
            rotate_right(x);
          }
          ((RedBlackNode) x.getParent()).setBlack();
          grandparent(x).setRed();
          rotate_left(grandparent(x));
        }
      }
    }
    root.setBlack();
  }