/*
 * class NTree
 *
 * $Date$
 * $Revision$
 *
 */

#ifndef NTREE_HH__
#define NTREE_HH__

#include "WImage/miscdefs.h"
#include <stdexcept>

#ifndef _WIN32_WCE
#include <iostream>
#endif


/** 
 * @addtogroup WTools 
 * @{ */

/**
 * A class for n-ary trees. Rather relaxed attitude towards position 
 * checking; crashes are avoided but errors not always flagged!
 */
template < class Type > class 
NTree 
{
public:
  /** Constructor, creates one empty tree node. The data is
   * uninitialized after creation.
   * @param nChildren the number of children to this node
   * @param position the position in the parent node if applicable
   * @param parent the parent node or NULL if root node */
  NTree (int nChildren, NTree < Type > *parent = NULL, int position = -1);
  /** Constructor, creates and initializes one tree node. 
   * @param nChildren the number of children to this node
   * @param data the data to initialize with (the data will be 
   * assigned using the assignment operator)
   * @param position the position in the parent node if applicable
   * @param parent the parent node or NULL if root node */
  NTree (int nChildren, Type &data, 
         int position = -1, NTree < Type > *parent = NULL);
  /** Destructor. Releases memory. */
  ~NTree (void);
  /** Is this node the root of a tree?
   * @return true if root, false if not */
  inline bool isRoot (void) const { return m_parent == NULL; }
  /** Returns the position of this node in the parent node.
   * @return the position in the parent node, -1 if this is a root node */
  inline int position (void) const { return m_position; }
  /** Returns the kind of tree this is (i.e. how many children each node has).
   * @return the aryness */
  inline int aryness (void) const { return m_aryness; }
  /** Has this node any neighbour nodes to its left?
   * @return true if there are */
  inline bool hasLeftSibling (void) const { 
    return !isRoot () && m_position > 0 
      && m_parent->hasChildAt (m_position - 1); 
  }
  /** Has this node any neighbour nodes to its right?
   * @return true if there are */
  inline bool hasRightSibling (void) const { 
    return !isRoot () && m_position < m_aryness - 1 
      && m_parent->hasChildAt (m_position + 1); 
  }
  /** Has this node any children at a particular position?
   * @param pos the position
   * @return true if it has any children at that position */
  inline bool hasChildAt (int pos) const { 
    return indexOK (pos) && m_children[pos] != NULL; 
  }
  /** Has this node any children at all?
   * @return true if it has children */
  inline bool hasChildren (void) const {
    int i; for (i = 0; i < m_aryness && !hasChildAt (i); i++) { }
    return i != m_aryness;
  }
  /** Returns the number of nodes.
   * @return the number of nodes */
  int card (void) const;
  /** Compares two trees. The `==' equality operator will be used for the
   * data fields 
   * @param tree the other tree
   * @return true if the trees have identical data / number of children */
  bool equals (const NTree &tree) const;
  /** Produce a copy of this tree. The data fields will be copied.
   * @return the copy */ 
  NTree < Type > *clone (void) const; 
  /** Destroy the subtree at a particular position. 
   * @param pos the position */
  inline void destroyAt (int pos) { DELETE (m_children[pos]); }
  /** Appends a tree at a particular position. The tree will not be 
   * duplicated.
   * @param pos the position
   * @param tree the tree
   * @exception invalid_argument if the tree has a different aryness from this
   * @exception invalid_argument if the position is not empty */
  void appendAt (int pos, NTree < Type > *tree); 
  /** Creates a new node and appends it at a particular position. 
   * @param pos the position
   * @param data the data to append 
   * @exception invalid_argument if the position is not empty */
  void appendAt (int pos, const Type &data); 
  /** Return a reference to this node's data.
   * @return a reference to the data */
  inline Type &data (void) { return m_data; }
  /** Return a reference to the node/subtree at a particular position.
   * @param pos the position
   * @return the subtree
   * @exception invalid_argument if the given position is empty */
  inline NTree < Type > &childAt (int pos) { 
    if (!indexOK (pos) || m_children[pos] == NULL)
      {
        throw std::invalid_argument ("childAt: no child at this position");
      }
    return *m_children[pos];
  } 
  /** Return a reference to the node/subtree left to this.
   * @return the left sibling
   * @exception invalid_argument if there is no left sibling */
  NTree < Type > &leftSibling (void) {
    if (!hasLeftSibling ())
      {
        throw std::invalid_argument ("leftSibling: no left sibling");
      }
    return *m_parent->m_children[m_position - 1];
  }
  /** Return a reference to the node/subtree right to this.
   * @return the right sibling
   * @exception invalid_argument if there is no right sibling */
  NTree < Type > &rightSibling (void) {
    if (!hasRightSibling ())
      {
        throw std::invalid_argument ("rightSibling: no right sibling");
      }
    return *m_parent->m_children[m_position + 1];
  }
  
protected:
  /** Initialize the node.
   * @param nChildren the number of children (aryness)
   * @param position the position in the parent node if applicable
   * @param parent the parent node or NULL if root */
  void init (int nChildren, int position, NTree < Type > *parent);
  /** Create empty child nodes to this.
   * @param levels the number of generations to add. */
  void appendNGenerations (int levels); 
  /** Check whether an index is out of bounds.
   * @param pos the index
   * @return false if the index is out of bounds */
  inline bool indexOK (int pos) const { return pos >= 0 && pos < m_aryness; }
  /** Copy one tree's leaves to another tree. Data fields will be 
   * copied using the `=' assignment operator. Both trees need to 
   * have identical arynesses.
   * @param dst the destination tree
   * @param src the source tree 
   * @exception invalid_argument if the dimensions do not match */
  void copyLeaves (NTree < Type > &dst, const NTree < Type > &src) const;
  
  /** An array of `aryness' elements holding the children's addresses */
  NTree < Type > **m_children;

  /** The parent node's address or NULL if root */
  NTree < Type > *m_parent;

  /** The data field. */
  Type m_data;

  /** The number of children this node can have */
  int m_aryness;
  /** This node's position in the parent node or -1 if root */
  int m_position;
}; /* class NTree */

#include "../NTree.cc"

/** @} */

#endif /* NTREE_HH__ */

