/****
 BpmDj: Free Dj Tools
 Copyright (C) 1995-2007 Werner Van Belle

 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
****/

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "avltree.h"

#define LEFT_NODE(watte) (watte->left)
#define RIGHT_NODE(watte) (watte->right)
#define SET_LEFT_NODE(watte,to) (watte->left=to)
#define SET_RIGHT_NODE(watte,to) (watte->right=to)
#define POSITIVE_FLAG(watte) (watte->flag == 1)
#define NEGATIVE_FLAG(watte) (watte->flag == -1)
#define ZERO_FLAG(watte) (watte->flag == 0)
#define SET_ZERO_FLAG(watte) (watte->flag = 0)
#define SET_POSITIVE_FLAG(watte) (watte->flag = 1)
#define SET_NEGATIVE_FLAG(watte) (watte->flag = -1)
#define NULL_NODE Node<Key>::Null

template <class Key> Sentinel<Key> * Node<Key>::Null = new Sentinel<Key>();

//---------------------------------------------------------
//   The Sentinel
//---------------------------------------------------------
template <class Key> class Sentinel: public Node<Key>
{
public:
  virtual int compareAddData(Node<Key>*) {assert(0); return 0;};
  virtual int compareSearchData(Key)     {assert(0); return 0;};
  virtual void       print()             {assert(0); return;};
  virtual void       print(int)          { return; };
  virtual int        depth()             { return 0; };
  virtual int        count()             { return 0; };
  virtual bool       isNull()            { return true; };
  virtual bool       valid()             { return true; };
  virtual Node<Key>* search(Key)         { return this; };
  virtual Node<Key>* RotateLeft(int&)    {assert(0); return 0;};  
  virtual Node<Key>* RotateRight(int&)   {assert(0); return 0;};
  virtual Node<Key>* LeftFreedom(Node<Key>* &, int&)      {assert(0); return 0;};
  virtual Node<Key>* RightFreedom(Node<Key>* &, int&)     {assert(0); return 0;};
  virtual Node<Key>* GetLeftFreedom(Node<Key>* &, int&)   {assert(0); return 0;};
  virtual Node<Key>* GetRightFreedom(Node<Key>* &, int&)  {assert(0); return 0;};
  virtual Node<Key>* DeleteAvlNode(Key, int&)             { return this; };
  virtual Node<Key>* AddAvlNode(Node<Key>* who, int& depthchanged) { depthchanged=1; return who; };

};

//---------------------------------------------------------
//   Count calculation
//---------------------------------------------------------
template <class Key> int Node<Key>::count()
{
  return 1 + left->count() + right->count();
}

//---------------------------------------------------------
//   Depth calculation
//---------------------------------------------------------
template <class Key> int Node<Key>::depth()
{
  int l = left->depth();
  int r = right->depth();
  if (l>r) return l + 1;
  return r + 1;
}

//---------------------------------------------------------
//   Printing
//---------------------------------------------------------
template <class Key> void Node<Key>::print(int prefix)
{
  right->print(prefix + 1);
  for( int t = prefix; t > 0; t--) printf(".");
  print();
  int l = left->depth();
  int r = right->depth();
  printf(" left=%d, right=%d, count=%d ",l,r,count());
  // SANITY CHECK !!!
  if ( abs(l-r)>1
       || (l <  r  && ! flag >  0 ) 
       || (l >  r  && ! flag <  0 ) 
       || (l == r  && ! flag == 0 ) )
    printf("*********");
  printf("\n");
  left->print(prefix + 1);
}

//---------------------------------------------------------
//   Consistency validation
//---------------------------------------------------------
template <class Key> bool Node<Key>::valid()
{
  if (!left->valid()) return false;
  if (!right->valid()) return false;
  if (POSITIVE_FLAG(this))
    return left->depth() == right->depth() - 1 ;
  if (NEGATIVE_FLAG(this))
    return left->depth() == right->depth() + 1 ;
  return left->depth() == right->depth();
}


//---------------------------------------------------------
//   Search
//---------------------------------------------------------
template <class Key> Node<Key>* Node<Key>::search(Key watte)
{
  int compareResult = compareSearchData(watte);
  if (compareResult == 0 ) return this;
  if (compareResult == 1 ) return left->search(watte);
  if (compareResult == -1) return right->search(watte);
  return NULL_NODE;
}

//---------------------------------------------------------
//   Add
//---------------------------------------------------------

#define LEFT(WHO) WHO(Left,Right,LEFT_NODE,RIGHT_NODE,SET_LEFT_NODE,SET_RIGHT_NODE,\
              NEGATIVE_FLAG,POSITIVE_FLAG,SET_NEGATIVE_FLAG,SET_POSITIVE_FLAG)
#define RIGHT(WHO) WHO(Right,Left,RIGHT_NODE,LEFT_NODE,SET_RIGHT_NODE,SET_LEFT_NODE,\
              POSITIVE_FLAG,NEGATIVE_FLAG,SET_POSITIVE_FLAG,SET_NEGATIVE_FLAG)
#define CREATE_ROTATE(lname,rname,LN,RN,SLN,SRN,NF,PF,SNF,SPF)\
template <class Key> Node<Key>* Node<Key>::Rotate##lname(int& depthchanged)\
        {\
        Node<Key>* sec;\
        sec=RN(this);\
        assert(PF(this));\
        if (!(NF(sec)))\
          {\
             SRN(this,LN(sec));\
             SLN(sec,this);\
             if (PF(sec))\
               {\
                  SET_ZERO_FLAG(this);\
                  SET_ZERO_FLAG(sec);\
                  depthchanged=1;\
                  return sec;\
               }\
             SPF(this);\
             SNF(sec);\
             return sec;\
          }\
          {\
             Node<Key>* third=LN(sec);\
             SLN(sec,RN(third));\
             SRN(this,LN(third));\
             SRN(third,sec);\
             SLN(third,this);\
             depthchanged=1;\
             if (NF(third))\
               {\
                  SPF(sec);\
                  SET_ZERO_FLAG(this);\
                  SET_ZERO_FLAG(third);\
                  return third;\
               }\
             if (ZERO_FLAG(third))\
               {\
                  SET_ZERO_FLAG(sec);\
                  SET_ZERO_FLAG(third);\
                  SET_ZERO_FLAG(this);\
                  return third;\
               }\
             SET_ZERO_FLAG(sec);\
             SNF(this);\
             SET_ZERO_FLAG(third);\
             return third;\
          }\
     }

LEFT(CREATE_ROTATE);
RIGHT(CREATE_ROTATE);

#define CREATE_HANG(lname,rname,LN,RN,SLN,SRN,NF,PF,SNF,SPF) {\
        SLN(this,LN(this)->AddAvlNode(who,heightchanged));\
        if (heightchanged) {\
             if (ZERO_FLAG(this)) {\
                  SNF(this);\
                  depthchanged=1;\
                  return this; }\
             if (PF(this)) {\
                  SET_ZERO_FLAG(this);\
                  return this; }\
             heightchanged=0;\
             Node<Key> *tmp = Rotate##rname(heightchanged);\
             if (!heightchanged) depthchanged=1;\
             return tmp; }\
        return this; }

template <class Key> Node<Key>* Node<Key>::AddAvlNode(Node<Key>* who, int& depthchanged)
{
  int heightchanged=0;
  int CompareResult=compareAddData(who);
  assert(CompareResult); // this means 'no duplicates'
  if (CompareResult > 0) LEFT(CREATE_HANG);
  RIGHT(CREATE_HANG);
}


//---------------------------------------------------------
//   Deletion
//---------------------------------------------------------
#define CREATE_FREEDOM(lname,rname,LN,RN,SLN,SRN,NF,PF,SNF,SPF)\
template <class Key> Node<Key>* Node<Key>::lname##Freedom (Node<Key>* &placetostorefreedom,int &heightchanged) {\
        if (RN(this)->isNull()) \
           {\
             if ((LN(this))->isNull()) {\
                  placetostorefreedom=this;\
                  heightchanged=1;\
                  return NULL_NODE; }\
             heightchanged=1;\
             placetostorefreedom=this;\
             return LN(this); \
           }\
           {\
             int takverkleind=0;\
             SRN(this, RN(this) -> lname##Freedom (placetostorefreedom,takverkleind));\
             if (takverkleind) \
               {\
                  if (NF(this)) return Rotate##rname (heightchanged);\
                  if (PF(this))\
                    {\
                       SET_ZERO_FLAG(this);\
                       heightchanged=1;\
                       return this;\
                    }\
                  SNF(this);\
                  return this;\
               }\
             return this;\
          }\
     }\
\
template <class Key> Node<Key>* Node<Key>::Get##lname##Freedom(Node<Key>* &placetostorefreedom,int &heightchanged)\
     {\
        Node<Key>* lname;\
        assert(LN(this));\
        lname = LN(this);\
        if (RN( lname ))\
          return lname -> lname##Freedom (placetostorefreedom, heightchanged);\
        heightchanged=1;\
        placetostorefreedom= lname;\
        return LN( lname );\
     }

LEFT(CREATE_FREEDOM)
RIGHT(CREATE_FREEDOM)

#define CREATE_ZAK(lname,rname,LN,RN,SLN,SRN,NF,PF,SNF,SPF)\
SLN(this,LN(this)->DeleteAvlNode(wie,takkleiner));\
if (takkleiner) {\
        if (NF(this)) {\
             SET_ZERO_FLAG(this);\
             heightchanged=1;\
             return this; }\
        if (ZERO_FLAG(this)) {\
             SPF(this);\
             return this; }\
        return Rotate##lname (heightchanged); }\
return this;
          
template <class Key> Node<Key>* Node<Key>::DeleteAvlNode(Key wie, int& heightchanged)
{
  int CompareResult,takkleiner=0;
  CompareResult=this->compareSearchData(wie);
  switch (CompareResult)
    {
    case -1: /* this<wie */ RIGHT(CREATE_ZAK);
    case 1: /* this>wie */ LEFT(CREATE_ZAK);
    case 0: /* this==wie */
      /* nu een opnderscheid maken voor welke kinderen de 
       * this heeft */
      if (LEFT_NODE(this)->isNull() && RIGHT_NODE(this)->isNull())
        {
          heightchanged=1;
          delete this;  // WVB !! Dangerours ???
          return NULL_NODE;
        }
      if (LEFT_NODE(this)->isNull())
        {
          Node<Key>* rechter;
          rechter=RIGHT_NODE(this);
          assert(POSITIVE_FLAG(this));
          assert(rechter);
          assert(LEFT_NODE(rechter)->isNull());
          assert(RIGHT_NODE(rechter)->isNull());
          heightchanged=1;
          delete this; // WVB -- dangerous
          return rechter;
        }
      if (RIGHT_NODE(this)->isNull())
        {
          Node<Key>* linker;
          linker=LEFT_NODE(this);
          assert(NEGATIVE_FLAG(this));
          assert(linker);
          assert(LEFT_NODE(linker)->isNull());
          assert(RIGHT_NODE(linker)->isNull());
          heightchanged=1;
          delete this;  // WVB -- dangerours ???
          return linker;
        }
      if (POSITIVE_FLAG(this))
        {
          Node<Key>* freedom;
          SET_RIGHT_NODE(this,GetRightFreedom(freedom,heightchanged));
          SET_LEFT_NODE(freedom,LEFT_NODE(this));
          SET_RIGHT_NODE(freedom,RIGHT_NODE(this));
          if (heightchanged) SET_ZERO_FLAG(freedom);
          else SET_POSITIVE_FLAG(freedom);
          delete this;   // WVB -- dangerous ???
          return freedom;
        }
      if (NEGATIVE_FLAG(this))
        {
          Node<Key>* freedom;
          SET_LEFT_NODE(this,GetLeftFreedom(freedom,heightchanged));
          SET_LEFT_NODE(freedom,LEFT_NODE(this));
          SET_RIGHT_NODE(freedom,RIGHT_NODE(this));
          if (heightchanged) SET_ZERO_FLAG(freedom);
          else SET_NEGATIVE_FLAG(freedom);
          delete this;  // WVB -- dangerours ??
          return freedom;
        }
      if (ZERO_FLAG(this))
        {
          Node<Key>* freedom;
          int takverkleind=0;
          SET_LEFT_NODE(this,GetLeftFreedom(freedom,takverkleind));
          SET_LEFT_NODE(freedom,LEFT_NODE(this));
          SET_RIGHT_NODE(freedom,RIGHT_NODE(this));
          if (takverkleind) SET_POSITIVE_FLAG(freedom);
          else  SET_ZERO_FLAG(freedom);
          delete this;   // WVB -- dangerours
          return freedom;
        }
    default: exit(57);
    }
}

//---------------------------------------------------------
//   Constructor and Wrappers
//---------------------------------------------------------

template <class Key> Node<Key>::Node()
{
  left = NULL;
  right = NULL;
}

template <class Key> AvlTree<Key>::AvlTree()
{
  init(); 
};

template <class Key> void AvlTree<Key>::init()
{
  root = Node<Key>::Null; 
};

template <class Key> void AvlTree<Key>::PurgeAll(Node<Key>* root)
{
  if (root && !root->isNull())
    {
      PurgeAll(root->left);
      PurgeAll(root->right);
      delete(root);
    }
}

template <class Key> AvlTree<Key>::~AvlTree()
{
  purge();
};

template <class Key> Node<Key>* AvlTree<Key>::AddAvlNode(Node<Key>* root, Node<Key>* who)
{
  if (who->isNull()) return root;
  who->left = NULL_NODE;
  who->right = NULL_NODE;
  who->flag = 0;
  int depthchanged=0;
  return root->AddAvlNode(who,depthchanged);
}

template <class Key> Node<Key>* AvlTree<Key>::DeleteAvlNode(Node<Key>* root, Key wie)
{
  int heightchanged=0;
  return root->DeleteAvlNode(wie,heightchanged);
}