/
ScryMUD/mud/
ScryMUD/mud/grrmud/Boards/
ScryMUD/mud/grrmud/Help/
ScryMUD/mud/grrmud/Pfiles/
ScryMUD/mud/grrmud/PlayerSacks/
ScryMUD/mud/grrmud/PlayerShops/
ScryMUD/mud/grrmud/help_filter/
ScryMUD/mud/hegemon/
ScryMUD/mud/hegemon/data/
ScryMUD/mud/hegemon/data/help/battle/
ScryMUD/mud/hegemon/data/help/client/
ScryMUD/mud/hegemon/data/help/communications/
ScryMUD/mud/hegemon/data/help/skills/
ScryMUD/mud/hegemon/data/help/spells/
ScryMUD/mud/include/
ScryMUD/mud/lib/
ScryMUD/mud/lib/bitfield/
ScryMUD/mud/lib/log/
ScryMUD/mud/lib/string2/
// $Id: tree2.h,v 1.2 1999/06/05 23:29:16 greear Exp $
// $Revision: 1.2 $  $Author: greear $ $Date: 1999/06/05 23:29:16 $

//
//ScryMUD Server Code
//Copyright (C) 1998  Ben Greear
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.
//
//This program 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 General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// To contact the Author, Ben Greear:  greear@cyberhighway.net, (preferred)
//                                     greearb@agcs.com
//

///**********************  tree2.h  *********************************///
/* This is the most heinous piece of code I have ever produced, other than
   that failed attempt at a suffix tree.  Hope I can get it working. */


#ifndef TREE_2_INCLUDE
#define TREE_2_INCLUDE

template <class T> class Tree2Node;
template <class T> class Tree2;

template <class T> class Tree2Cell {
   
   friend class Tree2Node<T>;
   friend class Tree2<T>;
   
private:
   Tree2Node<T>* ptr;
   
public:
   
   operator const int() const {
      if (ptr)
         return TRUE;
      return FALSE;
   }
   
   Tree2Cell(Tree2<T>& tree) { ptr = tree.root; }
   Tree2Cell(Tree2Node<T>& node) { ptr = &node; }
   Tree2Cell() { ptr = NULL; }
   
   void Head(Tree2<T>& tree) { ptr = tree.root;}
   void Head(Tree2Node<T>& nd) { ptr = &nd; }
   
   T& Data() { 
      if (ptr) {
         return ptr->data;
      }//if
      //log("TRACK: ERROR:  FATAL trying to get->NULL data in Data().\n");
      exit(102);
   }//Data()


   /* return current value, THEN increment by one */
   T& Next_Breadth() {	//will crash if let run too far
      if (!ptr) {
         //log("TRACK:  ERROR:  ptr is NULL, Next_Breadth.\n");
         exit(102);
      }//if
      T* tmp_ptr = &(ptr->data);
      ptr = ptr->next;
      return *tmp_ptr;
   }
   
   T& Parent() {		//will crash if let run too far
      if (!ptr) {
         //log("TRACK:  ERROR:  ptr is NULL, Parent.\n");
         exit(102);
      }//if
      T* tmp_ptr = &(ptr->data);
      ptr = ptr->parent;
      return *tmp_ptr;
   }


   /* This next one should add a child to the first of the children
      of the Tree2Node pointed to by the current TreeCell.
      A pointer to the just inserted Tree2Node will be returned. */
   
   Tree2Node<T>* Push_Child(T& dat) const {
      Tree2Node<T>* tmp, *tmp_par;
      
      if (!ptr) {
         //log("TRACK:  ERROR:  Tree2Cell is NULL in Push_Child()\n");
         return NULL;
      }//if
      else if (!ptr->prev && !ptr->next) { //if empty tree
         //log("TRACK:  inserting in an empty tree.\n");
         ptr->Insert_After(ptr, ptr->level + 1, dat);
         ptr->first = ptr->next;
         return ptr->next;
      }//else
      else if (ptr->first) { //if has a first child
         ptr->first->Insert_Before(ptr, ptr->level + 1, dat);
         ptr->first = ptr->first->prev; //new one is now first
         return ptr->first;
      }//if
      else { //no immediate children of this node,
         /* If previous sibs have children, put it after them,
            else put it after last sibling */
         /* first, check for previous sibs with children */
         
         tmp = ptr;// tmp points to current tree node
         
         while (TRUE) {
	    if (tmp->prev->level != tmp->level) { //left most end, no dice
               break;
            }//if
	    if (tmp->first) { //found a child, good to go
               tmp_par = tmp;
               tmp = tmp->first;
               while (TRUE) {
                  if (!tmp->next) { // end of tree, good do it here
                     break;
                  }//if
                  if (tmp->next->parent != tmp_par) { //also good, end of 
                     //tmp_par's children
                     break;
                  }//if
                  tmp = tmp->next;  //keep walking foward through children
               }//while
               /* now we are at posn */
               tmp->Insert_After(ptr, ptr->level + 1, dat);
               ptr->first = tmp->next;
               return ptr->first;
	    }//if
            tmp = tmp->prev; //keep walking left through cibs
         }//while
         
         /* if got to here, then at left most cib, no children.
            Must now find right most cib and place the new node
            after it, with 'ptr' as its parent. */
         
         while (TRUE) {
            if (!tmp->next) { //if last one then done
               break;
            }//if
            if (tmp->level != tmp->next->level) { //at end of level, done
               break;
            }//if
            tmp = tmp->next; //walk on down cibs
         }//while
         /* ok, good to go, insert after tmp */
         tmp->Insert_After(ptr, ptr->level + 1, dat);
         ptr->first = tmp->next; //original ptr gets child
         return ptr->first;
      }//else no immediate children
   }//Push_Child()		  
};//Tree2Cell


template <class T> class Tree2Node {

   friend class Tree2Cell<T>;
   friend class Tree2<T>;

private:
   short 	level;
   Tree2Node<T>* first;
   Tree2Node<T>* parent;
   T 	data;
   Tree2Node<T>* next;
   Tree2Node<T>* prev;
   
public:
   Tree2Node(int lvl, Tree2Node<T>* frst, Tree2Node<T>* par, T& dat,
             Tree2Node<T>* nxt, Tree2Node<T>* prv) { 
      level = lvl;
      first = frst; 
      parent = par;
      data = dat;
      next = nxt;
      prev = prv; 
   }
   
   Tree2Node() { parent = first = next = prev = NULL; level = 0; }
   
   
   ~Tree2Node() {
      delete next;
      next = prev = first = parent = NULL;
   }//destructor
   
   T& Data() { return data; }
   
   void Insert_Before(Tree2Node<T>* par, short lvl, T& data) {
      Tree2Node<T>* nn = new Tree2Node<T>(lvl, NULL, par,
                                          data, NULL, NULL);
      if (this->prev) {
         nn->prev = this->prev;
         this->prev = nn;
         nn->prev->next = nn;
         nn->next = this;
      }//if
      else { //new beginning of list
         nn->next = this;
         this->prev = nn;
      }//else
   }//Insert_Before
   
   
   void Insert_After(Tree2Node<T>* par, short lvl, T& data) {
      Tree2Node<T>* nn = new Tree2Node<T>(lvl, NULL, 
                                          par, data, NULL, NULL);
      if (this->next) {
         nn->prev = this;
         nn->next = this->next;
         nn->next->prev = nn;
         this->next = nn;
      }//if
      else { //new end
         nn->prev = this;
         this->next = nn;
      }//else
   }//Insert_After

}; //Tree2Node



template <class T> class Tree2 {

   friend class Tree2Node<T>;
   friend class Tree2Cell<T>;

private:
   Tree2Node<T>* root;
   
public:
   
   Tree2(T& data) { 
      root = new Tree2Node<T>();
      root->data = data;
   }
   
   ~Tree2() { Clear(); root = NULL; }
   
   
   void Clear() {
      delete root; //should fire destructors
      root = NULL;
   }//if
   
   void Log() { //write to logfile
      String buf(100);
      
      //log("TRACK:  Tree2 Log.\n"); //what other kind can there be?? :)
      
      Tree2Cell<T> cll(*this);
      if (!cll.ptr) {
         //log("TRACK:  cll.ptr is NULL.\n");
      }//if
      while (cll) {
         Sprintf(buf, 
                 "TRACK: this: %i, prv: %i, nxt: %i, par: %i, frst: %i, data: %i, lvl: %i",
                 (int)(cll.ptr), (int)(cll.ptr->prev), 
                 (int)(cll.ptr->next), (int)(cll.ptr->parent),
                 (int)(cll.ptr->first), (int)(cll.ptr->data),
                 (int)(cll.ptr->level));
         //log(buf);
         cll.Next_Breadth();
      }//while
   }//log
}; //Tree2


#endif