



/*
 *
 *          Copyright (C) 1995, M. A. Sridhar
 *  
 *
 *     This software is Copyright M. A. Sridhar, 1995. You are free
 *     to copy, modify or distribute this software  as you see fit,
 *     and to use  it  for  any  purpose, provided   this copyright
 *     notice and the following   disclaimer are included  with all
 *     copies.
 *
 *                        DISCLAIMER
 *
 *     The author makes no warranties, either expressed or implied,
 *     with respect  to  this  software, its  quality, performance,
 *     merchantability, or fitness for any particular purpose. This
 *     software is distributed  AS IS.  The  user of this  software
 *     assumes all risks  as to its quality  and performance. In no
 *     event shall the author be liable for any direct, indirect or
 *     consequential damages, even if the  author has been  advised
 *     as to the possibility of such damages.
 *
 */






#ifndef _treeimp_cxx_
#define _treeimp_cxx_

#ifdef __GNUC__
#pragma implementation
#endif

#if defined(__CFRONT__) && !defined(__CFRONT_TREE_IMPL__)
#include "base/tree.h"
#else

#define _no_cl_tree_typedefs_
#include "base/tree.h"
#include "base/treewalk.h"
#include "base/binding.h"
#include "base/basicops.h"


//
//---------------------------Node--------------------
//



template <class ItemType>
CL_TreeNode<ItemType>::CL_TreeNode (CL_TreeNodeLabel l,
                                    CL_Tree<ItemType>* ownerTree)
: _label (l), _parent (NULL),     _indexInParent (0),
  _content ((void*) 0), _tree (ownerTree)
{
}


// template <class ItemType>
// CL_TreeNode<ItemType>* CL_TreeNode<ItemType>::AddChild
//     (CL_TreeNodeLabel l, long leftSiblingIndex)
// {
//     CL_TreeNode<ItemType>* node = new CL_TreeNode<ItemType> (l);
//     if (node && AddChild (node, leftSiblingIndex))
//         return node;
//     }
//     return NULL;
// }




template <class ItemType>
CL_TreeNode<ItemType>* CL_TreeNode<ItemType>::Child (long index) const
{
    if (index < 0 || index >= _childPtrs.Size())
        return NULL;
    return (CL_TreeNode<ItemType>*) _childPtrs(index);
}
    

template <class ItemType>
CL_TreeNode<ItemType>::~CL_TreeNode ()
{
    CL_Basics<ItemType>::Destroy (_content);
}
    
template <class ItemType>
ItemType CL_TreeNode<ItemType>::Content ()
{
    return CL_Basics<ItemType>::Deref (_content);
}
    
template <class ItemType>
void CL_TreeNode<ItemType>::SetContent (const ItemType& t)
{
    CL_Basics<ItemType>::Deref (_content) = t;
    _tree->NodeContentChanged (this);
}




template <class ItemType>
CL_TreeNode<ItemType>* CL_TreeNode<ItemType>::AddChild
    (CL_TreeNode<ItemType>* node, long leftSiblingIndex)
{
    long n = ChildCount();
    if (leftSiblingIndex >= n)
        leftSiblingIndex = n - 1;
    if (! _childPtrs.Insert (node, leftSiblingIndex))
        return NULL;
    node->_indexInParent = leftSiblingIndex + 1;
    node->_parent = this;
    for (long i = _childPtrs.Size() - 1; i >= leftSiblingIndex + 2; i--) {
        CL_TreeNode<ItemType>* sibling = (CL_TreeNode<ItemType>*)
            _childPtrs(i);
        sibling->_indexInParent++;
    }
    return node;
}


template <class ItemType>
long CL_TreeNode<ItemType>::Depth () const
{
    CL_TreeNode<ItemType>* n = (CL_TreeNode<ItemType>*) this;
    long d = 0;
    while (n->_parent) {
        d++;
        n = n->_parent;
    }
    return d;
}

//
//-----------------CL_Tree ---------------------------------------
//

template <class ItemType>
CL_Tree<ItemType>::CL_Tree()
    : _nullValue (CL_Basics<ItemType>::NullValue())
{
    _root = NULL;
    
}

    
template <class ItemType>
CL_Tree<ItemType>::CL_Tree (CL_TreeNodeLabel rootLabel)
    : _nullValue (CL_Basics<ItemType>::NullValue())
{
    _root = new CL_TreeNode<ItemType> (rootLabel, this);
    _root->_content = CL_Basics<ItemType>::MakeCopy (_nullValue);
    _map.Add (rootLabel, _root);
}


template <class ItemType>
CL_Tree<ItemType>::CL_Tree (const CL_Tree<ItemType>& tree)
{
    *this = tree;
}


template <class ItemType>
CL_TreeNode<ItemType>*
CL_Tree<ItemType>::_MakeCopy (CL_TreeNode<ItemType>* subtreePtr,
                              CL_TreeNode<ItemType>* parentPtr)
{
    CL_TreeNode<ItemType>* copy = 0;
    if (subtreePtr) {
        copy = new CL_TreeNode<ItemType> (subtreePtr->_label, this);
        copy->_content       = CL_Basics<ItemType>::MakeCopy
            (CL_Basics<ItemType>::Deref (subtreePtr->_content));
        copy->_indexInParent = subtreePtr->_indexInParent;
        copy->_parent        = parentPtr;
        copy->_childPtrs.ChangeSize (subtreePtr->_childPtrs.Size());
        for (long i = subtreePtr->_childPtrs.Size() - 1; i >= 0; i--) {
            copy->_childPtrs(i) = _MakeCopy
                ((CL_TreeNode<ItemType>*) subtreePtr->_childPtrs(i), copy);
        }
    }
    return copy;
}



template <class ItemType>
CL_Tree<ItemType>& CL_Tree<ItemType>::operator=
    (const CL_Tree<ItemType>& tree)
{
    if (this == &tree || !PrepareToChange())
        return *this;
    _DeleteSubtree (_root);
    _root = _MakeCopy (tree._root, 0);
    _map  = tree._map;
    Notify();
    return *this;
}


template <class ItemType>
bool CL_Tree<ItemType>::GraftSubtree (CL_TreeNodeLabel lbl,
                                      CL_Tree<ItemType>& addedTree, long
                                      index)
{
    CL_TreeNode<ItemType>* node, *child;

    // Check if everything is ok
    if (!addedTree._root)
        return FALSE;
    node = Node (lbl);
    if (!node)
        return FALSE;
    CL_IntPtrMapIterator itr (addedTree._map);
    while (itr.More()) {
        if (_map.IncludesKey (itr.Next().key))
            return FALSE;
    }

    // Start modification
    if (!PrepareToChange())
        return FALSE;
    child = node->AddChild (addedTree._root, index);
    if (child) {
        itr.Reset();
        while (itr.More()) {
            CL_IntPtrAssoc a = itr.Next();
            _map.Add (a.key, a.value);
        }
        addedTree._root = NULL;
    }
    return TRUE;
}


template <class ItemType>
CL_TreeNode<ItemType>* CL_Tree<ItemType>::AddChild
    (CL_TreeNodeLabel obj, CL_TreeNodeLabel parent, long i)
{
    CL_TreeNode<ItemType>* node, *child;

    if (!PrepareToChange())
        return NULL;
    node = Node (parent);
    if (node == NULL)
        return NULL;
    if (_map.IncludesKey (obj))
        return NULL;
    CL_TreeNode<ItemType>* newNode = new CL_TreeNode<ItemType>
        (obj, this);
    newNode->_content = CL_Basics<ItemType>::MakeCopy (_nullValue);
    child = node->AddChild (newNode, i);
    if (child && _map.Add (obj, child)) {
        Notify();
        return child;
    }
    else
        return NULL;
}     


    

template <class ItemType>
CL_TreeNode<ItemType>* CL_Tree<ItemType>::NewRoot (CL_TreeNodeLabel l)
{
    if (!PrepareToChange())
        return NULL;
    CL_TreeNode<ItemType>* root = new CL_TreeNode<ItemType> (l, this);
    if (!root)
        return NULL;
    root->_content = CL_Basics<ItemType>::MakeCopy (_nullValue);
    if ( (_root == NULL || root->AddChild (_root)) &&  _map.Add (l, root)) {
        _root = root;
        _root->_indexInParent = 0;
        Notify();
        return _root;
    }
    return NULL;
}

    


template <class ItemType>
CL_Tree<ItemType>* CL_Tree<ItemType>::ExtractSubtree (CL_TreeNodeLabel obj)
{
    if (!PrepareToChange())
        return NULL;
    CL_TreeNode<ItemType>* node = Node (obj);
    if (node == NULL)
        return NULL;
    CL_TreeNode<ItemType>* parent = node->_parent;
    if (parent) {
        (parent->_childPtrs).Remove (node->_indexInParent);
        long n = parent->ChildCount();
        for (long i = node->_indexInParent; i < n; i++) {
            CL_TreeNode<ItemType>* sibling = parent->Child(i);
            sibling->_indexInParent--;
        }
    }
    CL_Tree<ItemType>* new_tree = new CL_Tree<ItemType>;
    new_tree->_root = node;
    node->_parent = NULL;
    node->_indexInParent = 0;
    new_tree->_BuildSubmap (new_tree->_root);

    // Fix for bug reported by Ludovic Brenta on May 27, 1997:
    CL_IntPtrMapIterator itr (new_tree->_map);
    while (itr.More()) {
        _map.Remove (itr.Next().key);
    }
    // End fix
    
    Notify();
    return new_tree;
}
    
template <class ItemType>
CL_TreeNode<ItemType>* CL_Tree<ItemType>::Node (CL_TreeNodeLabel l) const
{
    return (CL_TreeNode<ItemType> *) _map[l];
}


template <class ItemType>
bool CL_Tree<ItemType>::IsAncestor (CL_TreeNodeLabel n1,
                                    CL_TreeNodeLabel n2) const
{
    CL_TreeNode<ItemType>* node1 = (CL_TreeNode<ItemType> *) _map[n1];
    if (!node1)
        return FALSE;
    CL_TreeNode<ItemType>* node2 = (CL_TreeNode<ItemType> *) _map[n2];
    if (!node2)
        return FALSE;
    while (node2 != node1) {
        if (!node2)
            return FALSE;
        node2 = node2->Parent();
    }
    return TRUE;
}


template <class ItemType>
bool CL_Tree<ItemType>::DestroySubtree (CL_TreeNodeLabel l)
{
    if (!PrepareToChange())
        return FALSE;
    CL_TreeNode<ItemType>* node = Node (l);
    if (node == NULL)
        return FALSE;
    CL_TreeNode<ItemType>* parent = node->_parent;
    if (parent) {
        (parent->_childPtrs).Remove (node->_indexInParent);
        long n = parent->ChildCount();
        for (long i = node->_indexInParent; i < n; i++) {
            CL_TreeNode<ItemType>* sibling = parent->Child(i);
            sibling->_indexInParent--;
        }
    }
    else
        _root = NULL;
    _DeleteSubtree (node);
    Notify ();
    return TRUE;
}




template <class ItemType>
long CL_Tree<ItemType>::PostOrderWalk (CL_TreeNodeLabel l,
                                       const CL_AbstractBinding& bind) const
{
    long count = 0;
    CL_TreeNode<ItemType>* node = Node (l);
    if (node == NULL)
        return 0;
    CL_Binding0<CL_Object> nullBinding (0, 0);
    _Walk (node, nullBinding, bind, count);
    return count;
}



template <class ItemType>
long CL_Tree<ItemType>::Traverse (CL_TreeNodeLabel l,
                                  const CL_AbstractBinding& b1,
                                  const CL_AbstractBinding& b2) const
{
    long count = 0;
    CL_TreeNode<ItemType>* node = Node (l);
    if (node == NULL)
        return 0;
    _Walk (node, b1, b2, count);
    return count;
}


template <class ItemType>
CL_String CL_Tree<ItemType>::AsString () const
{
    CL_String s, t;
    CL_PreOrderWalker<ItemType> walker (Root());
    while (walker.More()) {
        CL_TreeNode<ItemType>* node = walker.Next();
        t.AssignWithFormat
            ("Label %d Content '%s'\n", node->Label(),
             CL_Basics<ItemType>::PrintableForm(node->Content()).AsPtr());
        s += CL_String (' ', 4 * node->Depth()) + t;
    }
    return s;
        
}


template <class ItemType>
void CL_Tree<ItemType>::NodeContentChanged (CL_TreeNode<ItemType>* )
{
    // Default action is to notify our dependents that we changed.
    Notify();
}


// Protected CL_Tree methods:

template <class ItemType>
void CL_Tree<ItemType>::_DeleteSubtree (CL_TreeNode<ItemType>* node)
{
    if (!node)
        return;
    long n = node->ChildCount ();
    for (long i = 0; i < n; i++) {
        _DeleteSubtree ((CL_TreeNode<ItemType>*) (node->_childPtrs)(i));
    }
    _map.Remove (node->_label);
    delete node;
}



template <class ItemType>
void CL_Tree<ItemType>::_BuildSubmap (CL_TreeNode<ItemType>* node)
{
    if (!node)
        return;
    long n = node->ChildCount ();
    for (long i = 0; i < n; i++) {
        _BuildSubmap ((CL_TreeNode<ItemType>*) (node->_childPtrs)(i));
    }
    _map.Add (node->_label, node);
}

template <class ItemType>
bool CL_Tree<ItemType>::_Walk (CL_TreeNode<ItemType>* node,
                               const CL_AbstractBinding& b1,
                               const CL_AbstractBinding& b2,
                               long& count) const
{
    if (!node)
        return TRUE;
    if (b1.Valid() && !b1.Execute (*node))
        return FALSE;
    long n = node->ChildCount ();
    count++;
    for (long i = 0; i < n; i++) {
        if (!_Walk (node->Child(i), b1, b2, count)) return FALSE;
    }
    return b2.Valid() ? b2.Execute (*node) : TRUE;
}




#endif /* CFRONT Stuff */

#endif  /* _treeimp_cxx_ */
