#pragma once

#include "Array.h"

namespace Framework
{
    template< class T >
    class TreeIterator;

    template< class T >
    class Tree
    {
    private:
        T *value;
        RCArray< Tree > *subtrees;
        Tree *zParent;
        int ref;

    public:
        Tree()
        {
            value = 0;
            zParent = 0;
            subtrees = new RCArray< Tree >();
            ref = 1;
        }

        Tree( T *value )
        {
            zParent = 0;
            this->value = value;
            subtrees = new RCArray< Tree >();
            ref = 1;
        }

        ~Tree()
        {
            if( value )
                value->release();
            subtrees->release();
        }

        TreeIterator<T> getIterator()
        {
            return TreeIterator( this );
        }

        void leeren()
        {
            if( value )
                value->release();
            value = 0;
            subtrees->leeren();
        }

        void addSubtree( Tree *t )
        {
            t->zParent = this;
            subtrees->add( t );
        }

        void setValue( T *v )
        {
            if( value )
                value->release();
            value = v;
        }

        T *getValue()
        {
            return value ? value->getThis() : 0;
        }

        T *zValue()
        {
            return value;
        }

        Tree *getParent()
        {
            return zParent ? zParent->getThis() : 0;
        }

        Tree *zParent()
        {
            return zParent;
        }

        Tree *getThis()
        {
            ref++;
            return this;
        }

        Tree *release()
        {
            if( !--ref )
                delete this;
            return 0;
        }
        friend TreeIterator;
    };

    template< class T >
    class TreeIterator
    {
    private:
        Tree *current;
        int nextSub;

    public:
        TreeIterator( Tree *tree )
        {
            current = tree;
            nextSub = 0;
        }

        TreeIterator( const TreeIterator &it )
        {
            current = it.current;
            nextSub = it.nextSub;
        }

        TreeIterator< T > &operator=( TreeIterator< T > &r )
        {
            current = r.current;
            nextSub = it.nextSub;
            return *this;
        }

        bool hasNext()
        {
            if( current->subtrees->getEintragAnzahl() >= nextSub )
                return 1;
            Tree<T> *c = current;
            while( true )
            {
                Tree<T> *p = c->zParent();
                if( !p )
                {
                    return 0;
                }
                for( auto i = p->subtrees->getIterator(); i; i++ )
                {
                    if( i._ == c )
                    {
                        i++;
                        if( i )
                            return 1;
                        else
                        {
                            c = p;
                            break;
                        }
                    }
                }
            }
        }

        TreeIterator< T > next()
        {
            if( current->subtrees->getEintragAnzahl() >= nextSub )
                return TreeIterator( current->subtrees->z( nextSub++ ) );
            Tree<T> *c = current;
            while( true )
            {
                Tree<T> *p = c->zParent();
                if( !p )
                    return TreeIterator<T>( 0 );
                for( auto i = p->subtrees->getIterator(); i; i++ )
                {
                    if( i._ == c )
                    {
                        i++;
                        if( i )
                            return TreeIterator<T>( i._ );
                        else
                        {
                            c = p;
                            break;
                        }
                    }
                }
            }
        }

        operator bool()
        {
            return current != 0;
        }

        operator T*()
        {
            return current->zValue();
        }

        TreeIterator< T > &operator++() // prefix
        {
            TreeIterator< T > temp( *this );
            *this = next();
            return temp;
        }

        TreeIterator< T > &operator++( int ) // postfix
        {
            *this = next();
            return *this;
        }

        T *operator->()
        {
            return current->zValue();
        }

        T val()
        {
            return current->zValue();
        }
    };
}