//==================================================================================================
// D a t a _ s t r u c t u r e                                                            Interface
// B i n a r y _ t r e e
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU Library General Public License for more details (http://www.gnu.org).

/*DESCRIPTION*/
/* This module provides a binary tree data structure. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "data_structure/binary_tree.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guDataStructureBinaryTree
#define guDataStructureBinaryTree

// Headers //---------------------------------------------------------------------------------------
#include <bpp/standard.hpp> /*INCLUDE*/

namespace bpp {

// Importation/Exportation //-----------------------------------------------------------------------
#ifdef DATA_STRUCTURE_DLL
 #define dll_export DLL_EXPORT
#else
 #define dll_export DLL_IMPORT
#endif

// Namespaces //------------------------------------------------------------------------------------
#define public_area  dataStructureBinaryTree
#define private_area dataStructureBinaryTree_private

namespace public_area  { /*NAMESPACE*/ using namespace standard; }
namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniDataStructureBinaryTree
has_initializer;

// Macrocommands //---------------------------------------------------------------------------------
/*ALIAS*/
#define tdTree class prData //

/*ALIAS*/
#define tuTree prData //

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 template <tdTree> class clBinaryTree;
}

namespace private_area {}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area {
 template <tdTree> clOutStream & operator << (clOutStream &,const clBinaryTree<tuTree> &);
 template <tdTree> clInStream & operator >> (clInStream &,clBinaryTree<tuTree> &);

 template <tdTree> clOutStream & operator << (clOutStream &,
                                              const std_vector(clBinaryTree<tuTree> *) &);

 template <tdTree> clInStream & operator >> (clInStream & agStream,
                                             std_vector(clBinaryTree<tuTree> *) &);
}

namespace private_area { testing_mode ( function void test(void); ) }

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 /*ERROR*/ extern_error erEmptyTree; /* The tree is empty. */
}

// Constants & Variables //-------------------------------------------------------------------------
extern_static_constant(private,tcString,goNextTreeFlag,?);
extern_static_constant(private,tcString,goNodeFlag,?);
extern_static_constant(private,tcString,goTreeEndFlag,?);
extern_static_constant(private,tcString,goTreeStartFlag,?);

// T r e e  Interface //----------------------------------------------------------------------------
namespace public_area {
 /*CLASS clBinaryTree */ /* Represents the binary tree data structure. */
 template <tdTree> class clBinaryTree {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clBinaryTree */ /* This class. */
  public_property typedef clBinaryTree<prData> cpTree;
  //-----------------------------------------------------------------------------------------Private
  private_property cpTree * atLeft;
  private_property cpTree * atRight;

  private_property void copy(const cpTree &);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clBinaryTree */ /* Indicates if the tree is empty. */
  read_only_attribute(tyBoolean,atEmpty,empty);

  /*ATTRIBUTE clBinaryTree */ /* Data contained in the root node of the tree. */
  read_only_attribute(prData,atData,data);

  public_property constructor clBinaryTree(void);
  public_property constructor clBinaryTree(const cpTree &);
  public_property constructor clBinaryTree(const prData &,cpTree * = nil,cpTree * = nil);
  public_property constructor clBinaryTree(const prData &,const cpTree &,const cpTree &);
  public_property destructor  clBinaryTree(void);

  public_property cpTree & operator = (const cpTree &);

  public_property cpTree &       left(void);
  public_property const cpTree & left(void) const;
  public_property cpTree &       right(void);
  public_property const cpTree & right(void) const;

  public_property void       clear(void);
  public_property tyCardinal depth(void) const;
  public_property cpTree &   extractLeft(void);
  public_property cpTree &   extractRight(void);
  public_property void       out(clOutStream &) const;
  public_property void       setData(const prData &);
  public_property void       setLeft(cpTree *);
  public_property void       setLeft(const cpTree &);
  public_property void       setRight(cpTree *);
  public_property void       setRight(const cpTree &);
  public_property tyCardinal size(void) const;
  public_property tyCardinal width(void) const;
 };
}

// Functions Inline //------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// T r e e  Inline //-------------------------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------------Copy
 template <tdTree> inline void clBinaryTree<tuTree>::copy(const cpTree & agTree) {
  if (not agTree.atEmpty) {
   atData=agTree.atData;
   atLeft=new_object(cpTree(*(agTree.atLeft)));
   atRight=new_object(cpTree(*(agTree.atRight)));
   atEmpty=false;
  }
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clBinaryTree */ /* Builds an empty tree. */
 template <tdTree> inline clBinaryTree<tuTree>::clBinaryTree(void)
 : atLeft(nil),atRight(nil),atEmpty(true),atData(prData()) {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clBinaryTree */
 /* Builds a tree by merging two trees. The two trees are not duplicated but directly inserted
    into the new tree. */
 template <tdTree>
 inline clBinaryTree<tuTree>::clBinaryTree(const prData & agData,cpTree * agLeft,cpTree * agRight)
 : atLeft(agLeft),atRight(agRight),atEmpty(false),atData(agData) {
  if (atLeft==nil) atLeft=new_object(cpTree());
  if (atRight==nil) atRight=new_object(cpTree());
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clBinaryTree */ /* Builds a tree by merging two trees. The two trees are duplicated. */
 template <tdTree>
 inline clBinaryTree<tuTree>::clBinaryTree(const prData & agData,const cpTree & agLeft,
                                           const cpTree & agRight)
 : atLeft(nil),atRight(nil),atEmpty(false),atData(agData) {
  atLeft=new_object(cpTree(agLeft));
  atRight=new_object(cpTree(agRight));
 }
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clBinaryTree */ /* Copies a tree. */
 template <tdTree>
 inline clBinaryTree<tuTree> & clBinaryTree<tuTree>::operator = (const cpTree & agTree) {
  clear();
  copy(agTree);
  return (*this);
 }
 //---------------------------------------------------------------------------------------------Left
 /*METHOD clBinaryTree */ /* Returns the left branch of the tree. Read-write version. */
 template <tdTree> inline clBinaryTree<tuTree> & clBinaryTree<tuTree>::left(void) {
  if (atEmpty) send_inline_error(erEmptyTree,"tree::left");
  return (*atLeft);
 }
 //---------------------------------------------------------------------------------------------Left
 /*METHOD clBinaryTree */ /* Returns the left branch of the tree. Read-only version. */
 template <tdTree> inline const clBinaryTree<tuTree> & clBinaryTree<tuTree>::left(void) const {
  if (atEmpty) send_inline_error(erEmptyTree,"tree::left");
  return (*atLeft);
 }
 //--------------------------------------------------------------------------------------------Right
 /*METHOD clBinaryTree */ /* Returns the right branch of the tree. Read-write version. */
 template <tdTree> inline clBinaryTree<tuTree> & clBinaryTree<tuTree>::right(void) {
  if (atEmpty) send_inline_error(erEmptyTree,"tree::right");
  return (*atRight);
 }
 //--------------------------------------------------------------------------------------------Right
 /*METHOD clBinaryTree */ /* Returns the right branch of the tree. Read-only version. */
 template <tdTree> inline const clBinaryTree<tuTree> & clBinaryTree<tuTree>::right(void) const {
  if (atEmpty) send_inline_error(erEmptyTree,"tree::right");
  return (*atRight);
 }
 //--------------------------------------------------------------------------------------------Clear
 /*METHOD clBinaryTree */ /* Empties the tree. */
 template <tdTree> inline void clBinaryTree<tuTree>::clear(void) {
  if (not atEmpty) {
   delete_object(atLeft);
   delete_object(atRight);
   atLeft=nil;
   atRight=nil;
   atEmpty=true;
  }
 }
 //--------------------------------------------------------------------------------------ExtractLeft
 /*METHOD clBinaryTree */ /* Extracts the left branch of the tree. */
 template <tdTree> inline clBinaryTree<tuTree> & clBinaryTree<tuTree>::extractLeft(void) {
  cpTree * lcLeft;

  if (atEmpty) send_inline_error(erEmptyTree,"tree::extractLeft");
  lcLeft=atLeft;
  atLeft=new_object(cpTree());
  return (*lcLeft);
 }
 //-------------------------------------------------------------------------------------ExtractRight
 /*METHOD clBinaryTree */ /* Extracts the right branch of the tree. */
 template <tdTree> inline clBinaryTree<tuTree> & clBinaryTree<tuTree>::extractRight(void) {
  cpTree * lcRight;

  if (atEmpty) send_inline_error(erEmptyTree,"tree::extractRight");
  lcRight=atRight;
  atRight=new_object(cpTree());
  return (*lcRight);
 }
 //------------------------------------------------------------------------------------------SetData
 /*METHOD clBinaryTree */ /* Sets the data contained in the root node of the tree. */
 template <tdTree> inline void clBinaryTree<tuTree>::setData(const prData & agData) {
  if (atEmpty) {
   atLeft=new_object(cpTree());
   atRight=new_object(cpTree());
   atEmpty=false;
  }

  atData=agData;
 }
 //------------------------------------------------------------------------------------------SetLeft
 /*METHOD clBinaryTree */
 /* Sets the left branch of the tree. The given branch is not duplicated but directly inserted
    in the tree. The old branch is destructed. */
 template <tdTree> inline void clBinaryTree<tuTree>::setLeft(cpTree * agTree) {
  if (atEmpty) send_inline_error(erEmptyTree,"tree::setLeft");
  delete_object(atLeft);

  if (agTree==nil) atLeft=new_object(cpTree());
  else atLeft=agTree;
 }
 //------------------------------------------------------------------------------------------SetLeft
 /*METHOD clBinaryTree */
 /* Sets the left branch of the tree. The given branch is duplicated.
    The old branch is destructed. */
 template <tdTree> inline void clBinaryTree<tuTree>::setLeft(const cpTree & agTree) {
  if (atEmpty) send_inline_error(erEmptyTree,"tree::setLeft");
  *atLeft=agTree;
 }
 //-----------------------------------------------------------------------------------------SetRight
 /*METHOD clBinaryTree */
 /* Sets the right branch of the tree. The given branch is not duplicated but directly inserted
    in the tree. The old branch is destructed. */
 template <tdTree> inline void clBinaryTree<tuTree>::setRight(cpTree * agTree) {
  if (atEmpty) send_inline_error(erEmptyTree,"tree::setRight");
  delete_object(atRight);

  if (agTree==nil) atRight=new_object(cpTree());
  else atRight=agTree;
 }
 //-----------------------------------------------------------------------------------------SetRight
 /*METHOD clBinaryTree */
 /* Sets the right branch of the tree. The given branch is duplicated.
    The old branch is destructed. */
 template <tdTree> inline void clBinaryTree<tuTree>::setRight(const cpTree & agTree) {
  if (atEmpty) send_inline_error(erEmptyTree,"tree::setRight");
  *atRight=agTree;
 }
}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------Tree Operator <<
 /*FUNCTION*/ /* Writes a tree into a stream. */
 template <tdTree>
 clOutStream & operator << (clOutStream & agStream,const clBinaryTree<tuTree> & agTree) {
  agStream << private_area::goTreeStartFlag << end_line;

  if (not agTree.empty()) {
   agStream << private_area::goNodeFlag << " = ";
   agStream << standard::string((tyBoolean)(not agTree.left().empty()));
   agStream << " , " << standard::string((tyBoolean)(not agTree.right().empty()));
   agStream << " ; ";
   agTree.data().out(agStream);
   agStream << end_line;

   if (not agTree.left().empty()) agTree.left().out(agStream);
   if (not agTree.right().empty()) agTree.right().out(agStream);
  }

  agStream << private_area::goTreeEndFlag << end_line;
  return (agStream);
 }
 //---------------------------------------------------------------------------------Tree Operator >>
 /*FUNCTION*/ /* Reads a tree from a stream. */
 template <tdTree> clInStream & operator >> (clInStream & agStream,clBinaryTree<tuTree> & agTree) {
  method_name("tree::operator >>");

  typedef clBinaryTree<tuTree> cpTree;

  tyBoolean lcLeft;
  tyBoolean lcRight;
  clString  lcString;

  tyBoolean lcFirst = false;

  agStream >> lcString;

  if (lcString==private_area::goTreeStartFlag) {
   agStream >> lcString;
   agTree.clear();
   lcFirst=true;
  }

  if (lcString!=private_area::goTreeEndFlag) {
   if (lcString!=private_area::goNodeFlag) send_error(erStreamReading);
   agStream >> lcString >> lcString;
   lcLeft=boolean(lcString.data());
   agStream >> lcString >> lcString;
   lcRight=boolean(lcString.data());
   agStream >> lcString;

   agTree.setData(prData(agStream));
   agTree.setLeft(new_object(cpTree()));
   agTree.setRight(new_object(cpTree()));
   if (lcLeft) agStream >> agTree.left();
   if (lcRight) agStream >> agTree.right();

   if (lcFirst) {
    agStream >> lcString;
    if (lcString!=private_area::goTreeEndFlag) send_error(erStreamReading);
   }
  }

  return (agStream);
 }
 //-------------------------------------------------------------------------Vector(Tree) Operator <<
 /*FUNCTION*/ /* Writes a vector of trees into a stream. */
 template <tdTree> clOutStream & operator << (clOutStream & agStream,
                                              const std_vector(clBinaryTree<tuTree> *) & agTreeS) {
  tyCardinal lcCounter = 0;

  while (lcCounter<agTreeS.size()) {
   agStream << *(agTreeS[lcCounter]);
   ++lcCounter;

   if (lcCounter<agTreeS.size())
    agStream << end_line << private_area::goNextTreeFlag << end_line << end_line;
  }

  return (agStream);
 }
 //-------------------------------------------------------------------------Vector(Tree) Operator >>
 /*FUNCTION*/ /* Reads a vector of trees from a stream. */
 template <tdTree> clInStream & operator >> (clInStream & agStream,
                                             std_vector(clBinaryTree<tuTree> *) & agTreeS) {
  method_name("std_vector(tree *)::operator >>");

  clString lcString;

  do {
   agTreeS.push_back(new_object(clBinaryTree<tuTree>));
   agStream >> *(agTreeS.back());
   agStream >> lcString;
  }
  while (lcString==private_area::goNextTreeFlag);

  if (lcString!="") send_error(erStreamReading);
  return (agStream);
 }
}

namespace private_area {}

// T r e e  Implementation //-----------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clBinaryTree */ /* Builds a tree by copying another one. */
 template <tdTree> clBinaryTree<tuTree>::clBinaryTree(const cpTree & agTree)
 : atLeft(nil),atRight(nil),atEmpty(true),atData(prData()) {
  clear();
  copy(agTree);
 }
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clBinaryTree */ /* Destructs the tree. */
 template <tdTree> clBinaryTree<tuTree>::~clBinaryTree(void) {
  if (not atEmpty) {
   delete_object(atLeft);
   delete_object(atRight);
  }
 }
 //--------------------------------------------------------------------------------------------Depth
 /*METHOD clBinaryTree */
 /* Returns the depth of the tree. A null depth means the tree is empty. */
 template <tdTree> tyCardinal clBinaryTree<tuTree>::depth(void) const {
  if (atEmpty) return (0);
  return (maxi(atLeft->depth(),atRight->depth()) + 1);
 }
 //----------------------------------------------------------------------------------------------Out
 /*METHOD clBinaryTree */ /* Writes the tree into a stream. */
 template <tdTree> void clBinaryTree<tuTree>::out(clOutStream & agStream) const {
  if (not atEmpty) {
   agStream << "node = ";
   agStream << standard::string(tyBoolean(not atLeft->atEmpty));
   agStream << " , " << standard::string(tyBoolean(not atRight->atEmpty));
   agStream << " ; ";
   atData.out(agStream);
   agStream << end_line;

   if (not atLeft->atEmpty) atLeft->out(agStream);
   if (not atRight->atEmpty) atRight->out(agStream);
  }
 }
 //---------------------------------------------------------------------------------------------Size
 /*METHOD clBinaryTree */ /* Returns the number of nodes in the tree. */
 template <tdTree> tyCardinal clBinaryTree<tuTree>::size(void) const {
  if (atEmpty) return (0);
  return (atLeft->size()+atRight->size()+1);
 }
 //--------------------------------------------------------------------------------------------Width
 /*METHOD clBinaryTree */
 /* Returns the width of the tree. A null width means the tree is empty. */
 template <tdTree> tyCardinal clBinaryTree<tuTree>::width(void) const {
  if (atEmpty) return (0);
  return (1+atLeft->width()+atRight->width());
 }
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef tdTree
#undef tuTree
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// D a t a _ s t r u c t u r e                                                       Implementation
// B i n a r y _ t r e e
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU Library General Public License for more details (http://www.gnu.org).

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "data_structure/binary_tree.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define DATA_STRUCTURE_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/data_structure/binary_tree.hpp> /*INTERFACE*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  dataStructureBinaryTree
#define private_area dataStructureBinaryTree_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Data_structure/Binary_tree");

// Initialization //--------------------------------------------------------------------------------
#undef iniDataStructureBinaryTree
static_constant(private_area::clInitializer,goInitializer);

// Errors //----------------------------------------------------------------------------------------
namespace public_area { static_error erEmptyTree; }

// Constants & Variables //-------------------------------------------------------------------------
static_constant(tcString,goNextTreeFlag);
static_constant(tcString,goNodeFlag);
static_constant(tcString,goTreeEndFlag);
static_constant(tcString,goTreeStartFlag);

// Static Members //--------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// X X X  Implementation //-------------------------------------------------------------------------
namespace {}

// I n i t i a l i z e r  Implementation //---------------------------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------------Start
 property void clInitializer::start(void) {
  if (atCounter++ == 0) {
   try {
    #include <bpp/modules.hpp> /*NEED*/
    registerStop(this);
    environment::informInitialization(goModuleName);

    erEmptyTree.create("Data Structure - The tree is empty.");

    goNextTreeFlag   = "<and>";
    goNodeFlag       = "node";
    goTreeEndFlag    = "<tree_end>";
    goTreeStartFlag  = "<tree_start>";
   }

   initializer_catch;
  }
 }
 //---------------------------------------------------------------------------------------------Stop
 property void clInitializer::stop(void) { environment::informTermination(goModuleName); }
}

// End //-------------------------------------------------------------------------------------------
}