/****************************************************************************
 *
 *  Copyright (C) 2000-2001 RealNetworks, Inc. All rights reserved.
 *
 *  This program is free software.  It may be distributed under the terms
 *  in the file LICENSE, found in the top level of the source distribution.
 *
 */

#ifndef _TTREE_H
#define _TTREE_H

#include <assert.h>

#if 0

enum BalFactor { bfLEFT2=-2, bfLEFT=-1, bfBAL=0, bfRIGHT=1, bfRIGHT2=2 };

#define LEFT  0
#define RIGHT 1
#define OPPOSITE(d) (1-d)

template <class T>
class TAvlTree
{
private:
    TAvlTree( const TAvlTree& );
    TAvlTree& operator=( const TAvlTree& );

protected:
    class TAvlNode
    {
    public:
        TAvlNode( const T& Data ) :
            m_pNext(pNext),
            m_Data(Data)
        {
            // Empty
        }
        T& GetData( void ) { return m_Data; }
        const T& GetData( void ) const { return m_Data; }

        TAvlNode    m_kids[2];
        BalFactor   m_bal;
        T           m_Data;
    };
public:
    TAvlTree( void ) : m_pRoot(NULL), m_nCount(0) {}
    ~TAvlTree( void )
    {
    }

    bool IsEmpty( void ) const { return m_pRoot == NULL; }
    unsigned int GetCount( void ) const { return m_nCount; }
    bool Insert( const T& Data )
    {
        TNode* pNode = new TNode( Data );
        assert( pNode );
        if( !m_pRoot )
        {
            assert( 0 == m_nCount );
            m_pRoot = pNode;
            m_nCount++;
            return true;
        }
        return _Insert( pNode, m_pRoot );
    }

protected:
    bool _Insert( TNode* pNode, TNode* pRoot )
    {
        bool ret = false;
        if( !(pNode->m_Data == pRoot->m_Data) )
        {
            if( pNode->m_Data < pRoot->m_Data )
            {
                if( pRoot->m_pLeft )
                {
                    ret = _Insert( pNode, pRoot->m_pLeft );
                }
                else
                {
                    pRoot->m_pLeft = pNode;
                    ret = true;
                }
            }
            else
            {
                if( pRoot->m_pRight )
                {
                    ret = _Insert( pNode, pRoot->m_pRight );
                }
                else
                {
                    pRoot->m_pRight = pNode;
                    ret = true;
                }
            }
        }
        return ret;
    }
    bool _Remove( TNode* pNode, TNode* pRoot )
    {
        if( pNode->m_Data < pRoot->m_Data )
        {
        }
        else
        {
        }
    }


    bool RotateOnce( TNode*& rpRoot, int d )
    {
        int od = OPPOSITE(d);
        TNode* pOldRoot = rpRoot;
        bool bHeightChanged = (rpRoot->m_kids[od]->m_bal != 0);

        rpRoot = pOldRoot->m_kids[od];
        pOldRoot->m_kids[od] = rpRoot->m_kids[d];
        rpRoot->m_kids[d] = pOldRoot;

        rpRoot->m_bal += 2*d-1;
        pOldRoot->m_bal = -( rpRoot->mbal );

        return bHeightChanged;
    }

    bool RotateTwice( TNode*& rpRoot, int d )
    {
        int od = OPPOSITE(d);
        TNode* pOldRoot = rpRoot;
        TNode* pOldOther = rpRoot->m_kids[od];

        rpRoot = pOldRoot->m_kids[od]->m_kids[d];

        pOldRoot->m_kids[od] = rpRoot->m_kids[d];
        rpRoot->m_kids[d] = pOldRoot;

        pOldOther->m_kids[d] = rpRoot->m_kids[od];
        rpRoot->m_kids[od] = pOldOther;

        rpRoot->m_kids[LEFT]->m_bal  = -max( rpRoot->m_bal, 0 );
        rpRoot->m_kids[RIGHT]->m_bal = -min( rpRoot->m_bal, 0 );
        rpRoot->m_bal = 0;

        return true;
    }

    bool Rebalance( TNode*& rpRoot )
    {
        bool bHeightChanged = false;
        if( rpRoot->m_bal == bfLEFT2 )
        {
            if( rpRoot->m_kids[LEFT]->m_bal == bfRIGHT )
                bHeightChanged = RotateTwice( rpRoot, RIGHT );
            else
                bHeightChanged = RotateOnce( rpRoot, RIGHT );
        }
        else if( rpRoot->m_bal == bfRIGHT2 )
        {
            if( rpRoot->m_kids[RIGHT]->m_bal == bfLEFT )
                bHeightChanged = RotateTwice( rpRoot, LEFT );
            else
                bHeightChanged = RotateOnce( rpRoot, LEFT );
        }
        return bHeightChanged;
    }

    TNode* Insert( T* pData, TNode*& rpRoot, bool& rchanged )
    {
        if( !rpRoot )
        {
            rpRoot = new TNode( *pData );
            rchanged = true;
            return NULL;
        }

        T* found = NULL;
        int increase = 0;

        // Compare items and determine which direction to search
        cmp_t  result = root->Compare(item->Key());
        dir_t  dir = (result == MIN_CMP) ? LEFT : RIGHT;

        if (result != EQ_CMP) {
            // Insert into "dir" subtree 
            found = Insert(item, root->mySubtree[dir], change);
            if (found)  return  found;   // already here - dont insert
            increase = result * change;  // set balance factor increment
        } else  {   // key already in tree at this node
            increase = HEIGHT_NOCHANGE;
            return  root->myData;
        }

        rpRoot->m_bal += increase;
        rchanged = (increase && rpRoot->m_bal) ? !Rebalance(rpRoot) : false;

        return NULL;
    }
    
protected:
    TNode*       m_pRoot;
    unsigned int m_nCount;
};

#else

#include "Avl.h"

#endif

#endif //ndef _TTREE_H


syntax highlighted by Code2HTML, v. 0.9.1