/** @file

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

#ifndef RBTREE_H_
#define RBTREE_H_

namespace ts { namespace detail {

/** A node in a red/black tree.

    This class provides only the basic tree operations. The client
    must provide the search and decision logic. This enables this
    class to be a base class for templated nodes with much less code
    duplication.
*/
struct RBNode {
  typedef RBNode self; ///< self reference type

  /// Node colors
  typedef enum { RED, BLACK } Color;

  /// Directional constants
  typedef enum { NONE, LEFT, RIGHT } Direction;

  /// Get a child by direction.
  /// @return The child in the direction @a d if it exists,
  /// @c NULL if not.
  self* getChild(
    Direction d //!< The direction of the desired child
  ) const;

  /** Determine which child a node is
      @return @c LEFT if @a n is the left child,
      @c RIGHT if @a n is the right child,
      @c NONE if @a n is not a child
  */
  Direction getChildDirection(
    self* const& n //!< The presumed child node
  ) const {
    return (n == _left) ? LEFT : (n == _right) ? RIGHT : NONE;
  }

  /** Get the parent node.
      @return A Node* to the parent node or a @c nil Node* if no parent.
  */
  self* getParent() const { return const_cast<self*>(_parent); }

  /// @return The color of the node.
  Color getColor() const { return _color; }

  self* leftmostDescendant() const {
      const self* n = this;
      while (n->_left)
          n = n->_left;

      return const_cast<self*>(n);
  }

  /** Reverse a direction
      @return @c LEFT if @a d is @c RIGHT, @c RIGHT if @a d is @c LEFT,
      @c NONE otherwise.
  */
  Direction flip(Direction d) {
    return LEFT == d ? RIGHT : RIGHT == d ? LEFT : NONE;
  }

  /** Perform internal validation checks.
      @return 0 on failure, black height of the tree on success.
  */
  int validate();

  /// Default constructor.
  RBNode()
    : _color(RED)
    , _parent(0)
    , _left(0)
    , _right(0)
    , _next(0)
    , _prev(0) {
  }

  /// Destructor (force virtual).
  virtual ~RBNode() { }

  /** Rotate the subtree rooted at this node.
      The node is rotated in to the position of one of its children.
      Which child is determined by the direction parameter @a d. The
      child in the other direction becomes the new root of the subtree.

      If the parent pointer is set, then the child pointer of the original
      parent is updated so that the tree is left in a consistent state.

      @note If there is no child in the other direction, the rotation
      fails and the original node is returned. It is @b not required
      that a child exist in the direction specified by @a d.

      @return The new root node for the subtree.
  */
  self* rotate(
    Direction d //!< The direction to rotate
  );

  /** Set the child node in direction @a d to @a n.
      The @a d child is set to the node @a n. The pointers in this
      node and @a n are set correctly. This can only be called if
      there is no child node already present.

      @return @a n.
  */
  self* setChild(
    self* n, //!< The node to set as the child
    Direction d //!< The direction of the child
  );

  /** Remove this node from the tree.
      The tree is rebalanced after removal.
      @return The new root node.
  */
  self* remove();

  void clearChild(Direction dir) {
    if (LEFT == dir) _left = 0;
    else if (RIGHT == dir) _right = 0;
  }

  /** @name Subclass hook methods */
  //@{
  /** Structural change notification.
      This method is called if the structure of the subtree rooted at
      this node was changed.

      This is intended a hook. The base method is empty so that subclasses
      are not required to override.
  */
  virtual void structureFixup() {}

  /** Called from @c validate to perform any additional validation checks.
      Clients should chain this if they wish to perform additional checks.
      @return @c true if the validation is successful, @c false otherwise.
      @note The base method simply returns @c true.
  */
  virtual bool structureValidate() { return true; }
  //@}

  /** Replace this node with another node.
      This is presumed to be non-order modifying so the next reference
      is @b not updated.
  */
  void replaceWith(
    self* n //!< Node to put in place of this node.
  );

  //! Rebalance the tree starting at this node
  /** The tree is rebalanced so that all of the invariants are
      true. The (potentially new) root of the tree is returned.

      @return The root node of the tree after the rebalance.
  */
  self* rebalanceAfterInsert();

  /** Rebalance the tree after a deletion.
      Called on the lowest modified node.
      @return The new root of the tree.
  */
  self* rebalanceAfterRemove(
    Color c, //!< The color of the removed node.
    Direction d //!< Direction of removed node from parent
  );

  //! Invoke @c structure_fixup() on this node and all of its ancestors.
  self* rippleStructureFixup();

  Color _color;  ///< node color
  self* _parent; ///< parent node (needed for rotations)
  self* _left;   ///< left child
  self* _right;  ///< right child
  self* _next; ///< Next node.
  self* _prev; ///< Previous node.
};

} /* namespace detail */

} /* namespace ts */


#endif /* RBTREE_H_ */
