
/* TreeSize for Unix  http://treesize.sf.net/
 * Copyright (c) 2006-2007 Marcos Diez <marcos_AT_unitron.com.br>
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */

#include "BTbinaryTree.h"
#include "util.h"


#ifdef DEBUG_TREE
#include <stdio.h>

#endif

struct strNode{
  BTkey key;
  void *data;
  node left;
  node right;
};




BTree BTnewTree( BTkey BTkeyDup( const BTkey sourceKey ) ,
		 int   BTkeyCmp( const BTkey key1 , const BTkey key2 ) ,
		 void  BTfreeKey( BTkey key ) ,
		 void  BTfreeData( void *data ) ){
  
  BTree newTree;
  myMalloc( newTree );

  newTree->treeRoot = BT_NO_NODE ;
  newTree->BTkeyDup=BTkeyDup;
  newTree->BTkeyCmp=BTkeyCmp;
  newTree->BTfreeKey=BTfreeKey;
  newTree->BTfreeData=BTfreeData;
  
  return newTree;
}



int BTtreeAdder( BTkey key , void *data , node *myRoot , node left , node right , const int realocateKey , BTree myTree ){
  node thisNode;
  int cmpKey;
#ifdef DEBUG_TREE
  printf("%s(\"%s\" , data , %p , %p , %p , %d );\n" ,
	 __FUNCTION__ ,
	 key , myRoot , left , right ,realocateKey );
#endif
  while( 42 ){
    if( *myRoot == BT_NO_NODE ){		/* i found an empty place to store my key ! */
#ifdef DEBUG_TREE
      printf("I found a place where *myRoot==0\n");
#endif
      *myRoot = thisNode = (node) xMalloc( sizeof( *thisNode ) );
      if( realocateKey ) {
	thisNode->key= (myTree->BTkeyDup)( key );
      }      else{
	thisNode->key=key;
      }
      thisNode->data=data;
      thisNode->left=left;
      thisNode->right=right;
      return BT_KEY_ADDED_SUCESSFUL;
    }

    cmpKey = myTree->BTkeyCmp( (**myRoot).key , key );
    
    if( !cmpKey ) { 		/* the key already exists */
      return BT_KEY_ALREADY_EXISTS;
/*       thisNode= *myRoot; */
/*       thisNode->data=data; */
/*       if( left ){ */
/* 	BTtreeAdder( left->key , left->data , myRoot , left->left, left->right , BT_DONT_REALLOCATE_KEY ); */
/*       } */
/*       if( right ){ */
/* 	BTtreeAdder( right->key , right->data , myRoot , right->left, right->right , BT_DONT_REALLOCATE_KEY  ); */
/*       } */
/*       return; */
    }
    if( cmpKey > 0 ){/*  // left */
#ifdef DEBUG_TREE
      printf("I am going LEFT\n");
#endif
      myRoot=&(**myRoot).left;
    }else{ /* // right */
#ifdef DEBUG_TREE
      printf("I am going RIGHT\n");
#endif
      myRoot=&(**myRoot).right;
    }
  }
}


void BTdel( BTree myTree , const BTkey key ){
  node thisNode=myTree->treeRoot;
  node *pNode=&(myTree->treeRoot);
  int cmpKey;
  while( thisNode != BT_NO_NODE ){
    cmpKey = myTree->BTkeyCmp(  thisNode->key , key );
    if( !cmpKey ){ /* I found it */
      node rightNode;
      if( myTree->BTfreeKey ) myTree->BTfreeKey( thisNode->key );
      if( myTree->BTfreeData ) myTree->BTfreeData( thisNode->data );
      if( thisNode->left == (node) BT_NO_NODE  && thisNode->right != (node) BT_NO_NODE ){
	/* that means the left node is null, so i can replace myself with the right node */
	*pNode=thisNode->right;
	free(thisNode);
	return;
      }
      /* i might have to keep both */
      *pNode=thisNode->left;
      rightNode=thisNode->right;
      free(thisNode);
      if( rightNode != (node) BT_NO_NODE  ){		/* should I keep the right node ? */
	BTtreeAdder( rightNode->key , rightNode->data , pNode , rightNode->left , rightNode->right , BT_DONT_REALLOCATE_KEY , myTree );
	free( rightNode );
      }
      /*       free( rightNode ); */
      return;
    }
    if( cmpKey > 0 ) {
      pNode= &(thisNode->left );
      thisNode=thisNode->left;
    } else {			/* cmpKey < 0 */
      pNode= &(thisNode->right );
      thisNode=thisNode->right;
    }
  }
}


void *BTget( BTree myTree , const BTkey key ){
  node thisNode=myTree->treeRoot;
  int cmpKey;
  while( thisNode != (node) BT_NO_NODE ){
#ifdef DEBUG_TREE
    printf("treeGet: [%s][%s]\n" , thisNode->key , key );
#endif
    cmpKey = myTree->BTkeyCmp(  thisNode->key , key );
#ifdef DEBUG_TREE
    if( !cmpKey ) printf("achei\n");
/*     //    else printf(" [% */
#endif
    if( !cmpKey ) return thisNode->data;
    if( cmpKey > 0 ) thisNode=thisNode->left;
    else thisNode=thisNode->right;
  }
  return (node) BT_KEY_DOESNT_EXIST;
}

static void BTwipeTreeHelper( node myNode ,
			      void  BTfreeKey( BTkey key ) ,
			      void  BTfreeData( void *data ) ){

  if( BTfreeKey )  BTfreeKey(  myNode->key   );
  if( BTfreeData ) BTfreeData( myNode->data  );

  
  if( myNode->right != (node) BT_NO_NODE ) BTwipeTreeHelper( myNode->right , BTfreeKey , BTfreeData );
  if( myNode->left  != (node) BT_NO_NODE ) BTwipeTreeHelper( myNode->left  , BTfreeKey , BTfreeData );
  free( myNode );
}


void BTwipeTree( BTree myTree ){
  node myNode=myTree->treeRoot;

  if( myNode  != (node) BT_NO_NODE )   BTwipeTreeHelper( myNode , myTree->BTfreeKey , myTree->BTfreeData );

  free(myTree);
}


static void BTdelTreeHelper( node myNode ){
  if( myNode->right != (node ) BT_NO_NODE ) BTdelTreeHelper( myNode->right );
  if( myNode->left  != (node ) BT_NO_NODE ) BTdelTreeHelper( myNode->left );
  free( myNode );
}


void BTdelTree( BTree myTree ){
  node myNode=myTree->treeRoot;
  free(myTree);

  if( myNode  != (node) BT_NO_NODE )   BTdelTreeHelper( myNode );
}
