/*
 * Implementation of class NTree
 *
 * $Date$
 * $Revision$
 *
 */

#ifndef NTREE_CC__
#define NTREE_CC__

#include "WTools/NTree.hh"
#include <cassert>
#ifdef _WIN32_WCE
#include "WImage/miscdefs.h"
#endif

#if !(defined __WATCOMC__ && __WATCOMC__ < 1230)
using namespace std;
#endif

template < class Type >
NTree < Type > :: NTree (int nChildren, NTree < Type > *parent, int position)
{
  init (nChildren, position, parent);
}

template < class Type >
NTree < Type > :: NTree (int nChildren, Type &data, 
                         int position, NTree < Type > *parent)
{
  init (nChildren, position, parent);
  m_data = data;
}

template < class Type > void
NTree < Type > :: init (int nChildren, int position, NTree < Type > *parent)
{
  m_aryness = nChildren;
  m_children = NEW (NTree* [m_aryness]);
  for (int i = 0; i < m_aryness; i++)
    {
      m_children[i] = NULL;
    }
  m_parent = parent;
  m_position = position;
}

template < class Type >
NTree < Type > :: ~NTree (void)
{
  // delete everything from here, also make sure nothing gets deleted
  // twice!
  if (m_parent != NULL)
    {
      m_parent->m_children[m_position] = NULL;
    }
  for (int i = 0; i < m_aryness; i++)
    {
      if (m_children[i] != NULL)
        {
          DELETE (m_children[i]);
          assert (m_children[i] == NULL);
        }
    }
  DELETE (m_children);
}
  
template < class Type > void
NTree < Type > :: appendAt (int pos, NTree < Type > *tree)
{
  if (hasChildAt (pos))
    {
      throw std::invalid_argument ("appendAt: the position is not empty.");
    }
  if (tree->aryness () != this->aryness ())
    {
      throw std::invalid_argument ("appendAt: the aryness is different.");
    }
  m_children[pos] = tree;
  tree->m_parent = this;
  tree->m_position = pos;
}

template < class Type > void
NTree < Type > :: appendAt (int pos, const Type &data)
{
  NTree < Type > *leaf = NEW (NTree < Type > (this->aryness (), this, pos));
  leaf->m_data = data;
  this->appendAt (pos, leaf);
}

template < class Type > NTree < Type > *
NTree < Type > :: clone (void) const
{
  NTree < Type > *ret = NEW (NTree < Type > (this->aryness ()));
  ret->m_data = this->m_data;
  copyLeaves (*ret, *this);
  return ret;
}

template < class Type > int
NTree < Type > :: card (void) const
{
  int ret = 1;
  for (int i = 0; i < this->aryness (); i++)
    {
      if (m_children[i] != NULL)
        {
          ret += m_children[i]->card ();
        }
    }
  return ret;
}

template < class Type > bool
NTree < Type > :: equals (const NTree < Type > &tree) const
{
  if (tree.aryness () != this->aryness () 
      || tree.card () != this->card ()
      || m_data != tree.m_data)
    {
      return false;
    }
  for (int i = 0; i < this->aryness (); i++)
    {
      if ((m_children[i] != NULL) != (tree.m_children[i] != NULL))
        {
          return false;
        }
      if (m_children[i] != NULL)
        {
          if (!m_children[i]->equals (*tree.m_children[i]))
            {
              return false;
            }
        }
    }
  return true;
}

template < class Type > void 
NTree < Type > :: copyLeaves (NTree < Type > &dst, 
                              const NTree < Type > &src) const
{
  if (dst.aryness () != src.aryness ())
    {
      throw std::invalid_argument ("copyLeaves: dimensions do not match.");
    }
  
  for (int i = 0; i < src.aryness (); i++)
    {
      if (src.m_children[i] == NULL)
        {
          dst.m_children[i] = NULL;
        }
      else
        {
          dst.appendAt (i, src.m_children[i]->m_data);
          copyLeaves (*dst.m_children[i], *src.m_children[i]);
        }
    }
}

template < class Type > void 
NTree < Type > :: appendNGenerations (int levels)
{
  if (levels == 0)
    {
      return;
    }
  for (int j = 0; j < this->aryness (); j++)
    {
      m_children[j]->appendAt (j, NEW (NTree < Type > (this->aryness ())));
      m_children[j]->appendNGenerations (levels - 1);
    }
}

#endif /* NTREE_CC__ */
