// -*- c++ -*- (enables emacs c++ mode)
//===========================================================================
//
// Copyright (C) 1995-2008 Yves Renard
//
// This file is a part of GETFEM++
//
// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
// under  the  terms  of the  GNU  Lesser General Public License as published
// by  the  Free Software Foundation;  either version 2.1 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 Lesser General Public
// License for more details.
// You  should  have received a copy of the GNU Lesser General Public License
// along  with  this program;  if not, write to the Free Software Foundation,
// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
//
// As a special exception, you  may use  this file  as it is a part of a free
// software  library  without  restriction.  Specifically,  if   other  files
// instantiate  templates  or  use macros or inline functions from this file,
// or  you compile this  file  and  link  it  with other files  to produce an
// executable, this file  does  not  by itself cause the resulting executable
// to be covered  by the GNU Lesser General Public License.  This   exception
// does not  however  invalidate  any  other  reasons why the executable file
// might be covered by the GNU Lesser General Public License.
//
//===========================================================================

/**@file dal_tree_sorted.h
   @author Yves Renard <Yves.Renard@insa-lyon.fr>
   @date June 01, 1995
   @brief a balanced tree stored in a dal::dynamic_array

   Oneday this will be replaced with a std::map.
*/
#ifndef DAL_TREE_SORTED_H__
#define DAL_TREE_SORTED_H__

#include "dal_tas.h"

namespace dal {

  /* ********************************************************************* */
  /* Definitition des iterateurs.                                          */
  /* ********************************************************************* */
  /* Attention, l'iterateur n'est plus valide apres une operation          */
  /* d'insertion ou de suppression.                                        */
  /* ********************************************************************* */

  static const size_t DEPTHMAX__ = size_t(CHAR_BIT*sizeof(size_t)*3) / 2;
  static const size_t ST_NIL = size_t(-1);

  template<typename T, typename COMP = gmm::less<T>, int pks = 5>
    class dynamic_tree_sorted;

  template<typename T, typename COMP, int pks> struct tsa_iterator {
    typedef T                value_type;
    typedef value_type&      reference;
    typedef value_type*      pointer;
    typedef size_t           size_type;
    typedef ptrdiff_t        difference_type;
    typedef std::bidirectional_iterator_tag iterator_category;
    typedef gmm::int8_type short_type;

    dynamic_tree_sorted<T, COMP, pks> *p;
    size_type path[DEPTHMAX__];
    short_type dir[DEPTHMAX__];
    size_type depth;

    tsa_iterator(void) {}
    tsa_iterator(dynamic_tree_sorted<T, COMP, pks> &tsa)
    { p = &tsa; depth = 0; }
    void copy(const tsa_iterator<T, COMP, pks> &it);
    tsa_iterator(const tsa_iterator &it) { copy(it); }
    tsa_iterator &operator =(const tsa_iterator &it)
    { copy(it); return *this;}

    inline size_type index(void) const
    { return (depth==0) ? ST_NIL : path[depth-1];}
    inline size_type father(void) const
    { return (depth<=1) ? ST_NIL : path[depth-2];}
    inline size_type index_(void) const
    { return path[depth-1]; }
    inline short_type direction(void) const
    { return (depth==0) ? 0 : dir[depth-1];}
    inline void up(void) { if (depth > 0) depth--; }
    void down_left(void);
    void down_right(void);
    void down_left_all(void);
    void down_right_all(void);
    void root(void) { path[0] = p->root_elt(); dir[0] = 0; depth = 1; }
    void first(void) { root(); down_left_all(); }
    void last(void) { root(); down_right_all(); }
    void end(void) { depth = 0; }

    tsa_iterator &operator ++();
    tsa_iterator &operator --();
    tsa_iterator operator ++(int)
    { tsa_iterator tmp = *this; ++(*this); return tmp; }
    tsa_iterator operator --(int)
    { tsa_iterator tmp = *this; --(*this); return tmp; }
   
    reference operator *() const { return (*p)[index()]; }
    pointer operator->() const { return &(operator*()); }
    
    bool operator ==(const tsa_iterator &i) const
    { return ((i.depth == 0 && depth == 0) || (i.index_() == index_())); }
    bool operator !=(const tsa_iterator &i) const
    { return !((i.depth == 0 && depth == 0) || (i.index_() == index_())); }
  };

  template<typename T, typename COMP, int pks> 
  void tsa_iterator<T, COMP, pks>::copy(const tsa_iterator<T, COMP, pks> &it) {
    p = it.p; depth = it.depth;
    size_type *p1it=&(path[0]), *pend=&path[depth];
    const size_type *p2it=&(it.path[0]);
    short_type *d1it=&(dir[0]);
    const short_type *d2it=&(it.dir[0]);
    while (p1it != pend) { *p1it++ = *p2it++; *d1it++ = *d2it++; }
  }
  
  template<typename T, typename COMP, int pks> 
    void tsa_iterator<T, COMP, pks>::down_left(void) {
    GMM_ASSERT3(depth > 0 && depth < DEPTHMAX__ && index() != ST_NIL,
		"internal error");
    path[depth] = p->left_elt(index_()); dir[depth++] = -1;
  }

  template<typename T, typename COMP, int pks> 
    void tsa_iterator<T, COMP, pks>::down_right(void) { 
    GMM_ASSERT3(depth > 0 && depth < DEPTHMAX__ && index() != ST_NIL,
		"internal error");
    path[depth] = p->right_elt(index_()); dir[depth++] = 1;
  }

  template<typename T, typename COMP, int pks> 
    void tsa_iterator<T, COMP, pks>::down_left_all(void)
  { while (index_() != ST_NIL) down_left(); up(); }

  template<typename T, typename COMP, int pks> 
    void tsa_iterator<T, COMP, pks>::down_right_all(void)
  { while (index_() != ST_NIL) down_right(); up();}
   
  template<typename T, typename COMP, int pks>
    tsa_iterator<T, COMP, pks> &tsa_iterator<T, COMP, pks>::operator ++() {
    if (depth == 0) first();
    if (p->right_elt(index_()) != ST_NIL) { down_right(); down_left_all(); }
    else                { up(); while (dir[depth] == 1) up(); }
    return *this;
  }
  
  template<typename T, typename COMP, int pks>
    tsa_iterator<T, COMP, pks> &tsa_iterator<T, COMP, pks>::operator --() {
    if (depth == 0) last();
    if (p->left_elt(index_()) != ST_NIL) { down_left(); down_right_all(); }
    else               { up(); while (dir[depth] == -1) up(); }
    return *this;
  }


  template<typename T, typename COMP, int pks> struct const_tsa_iterator {
    typedef T                  value_type;
    typedef const value_type&  reference;
    typedef const value_type*  pointer;
    typedef size_t             size_type;
    typedef ptrdiff_t          difference_type;
    typedef std::bidirectional_iterator_tag iterator_category;
    typedef gmm::int8_type short_type;

    const dynamic_tree_sorted<T, COMP, pks> *p;
    size_type path[DEPTHMAX__];
    short_type dir[DEPTHMAX__];
    size_type depth;

    const_tsa_iterator(void) {}
    const_tsa_iterator(const dynamic_tree_sorted<T, COMP, pks> &tsa)
    { p = &tsa; depth = 0; }
    void copy(const const_tsa_iterator<T, COMP, pks> &it);
    const_tsa_iterator(const const_tsa_iterator &it) { this->copy(it); }
    const_tsa_iterator(const tsa_iterator<T, COMP, pks> &it);
    const_tsa_iterator &operator =(const const_tsa_iterator &it)
    { copy(it); return *this; }
    
    inline size_type index(void) const
    { return (depth==0) ? ST_NIL : path[depth-1];}
    inline size_type father(void) const
    { return (depth<=1) ? ST_NIL : path[depth-2];}
    inline size_type index_(void) const { return path[depth-1]; }
    inline short_type direction(void) const
    { return (depth==0) ? short_type(0) : dir[depth-1];}
    inline void up(void) { if (depth > 0) depth--; }
    void down_left(void);
    void down_right(void);
    void down_left_all(void);
    void down_right_all(void);
    void root(void) { path[0] = p->root_elt(); dir[0] = 0; depth = 1; }
    void first(void) { root(); down_left_all(); }
    void last(void) { root(); down_right_all(); }
    void end(void) { depth = 0; }

    const_tsa_iterator &operator ++();
    const_tsa_iterator &operator --();
    const_tsa_iterator operator ++(int)
    { const_tsa_iterator tmp = *this; ++(*this); return tmp; }
    const_tsa_iterator operator --(int)
    { const_tsa_iterator tmp = *this; --(*this); return tmp; }
   
    reference operator *() const { return (*p)[index()]; }
    pointer operator->() const { return &(operator*()); }
    
    bool operator ==(const const_tsa_iterator &i) const
    { return ((i.depth == 0 && depth == 0) || (i.index_() == index_())); }
    bool operator !=(const const_tsa_iterator &i) const
    { return !((i.depth == 0 && depth == 0) || (i.index_() == index_())); }
  };

  template<typename T, typename COMP, int pks>
  std::ostream& operator<<(std::ostream& o,
			   const const_tsa_iterator<T,COMP,pks>& it) {
    o << "const_tsa_iterator : depth=" << it.depth << ", path/dir=[";
    for (unsigned i=0; i < it.depth; ++i)
      o << "{" << it.path[i] << ", " << int(it.dir[i]) << "} ";
    o << "]";
    return o;
  }

  template<typename T, typename COMP, int pks> 
  void const_tsa_iterator<T, COMP, pks>::copy
  (const const_tsa_iterator<T, COMP, pks> &it) {
    p = it.p; depth = it.depth;
    size_type *p1it=&(path[0]), *pend=&path[depth];
    const size_type *p2it=&(it.path[0]);
    short_type *d1it=&(dir[0]);
    const short_type *d2it=&(it.dir[0]);
    while (p1it != pend) { *p1it++ = *p2it++; *d1it++ = *d2it++; }
  }
  
  template<typename T, typename COMP, int pks>
  const_tsa_iterator<T, COMP, pks>::const_tsa_iterator
  (const tsa_iterator<T, COMP, pks> &it) {
    p = it.p; depth = it.depth;
    size_type *p1it=&(path[0]), *pend=&path[depth];
    const size_type *p2it=&(it.path[0]);
    short_type *d1it=&(dir[0]);
    const short_type *d2it=&(it.dir[0]);
    while (p1it != pend) { *p1it++ = *p2it++; *d1it++ = *d2it++; }
  }

  template<typename T, typename COMP, int pks>
  void const_tsa_iterator<T, COMP, pks>::down_left(void) {
    GMM_ASSERT3(depth > 0 && depth < DEPTHMAX__ && index() != ST_NIL,
		"internal error");
    path[depth] = p->left_elt(index_()); dir[depth++] = -1;
  }
  
  template<typename T, typename COMP, int pks>
  void const_tsa_iterator<T, COMP, pks>::down_right(void) { 
    GMM_ASSERT3(depth > 0 && depth < DEPTHMAX__ && index() != ST_NIL,
		"internal error");
    path[depth] = p->right_elt(index_()); dir[depth++] = 1;
  }

  template<typename T, typename COMP, int pks>
  void const_tsa_iterator<T, COMP, pks>::down_left_all(void)
  { while (index_() != ST_NIL) down_left(); up(); }

  template<typename T, typename COMP, int pks> 
    void const_tsa_iterator<T, COMP, pks>::down_right_all(void) 
  { while (index_() != ST_NIL) down_right(); up();}
  
  template<typename T, typename COMP, int pks>
  const_tsa_iterator<T, COMP, pks> &
  const_tsa_iterator<T, COMP, pks>::operator ++() {  
    if (depth == 0) last();
    if (p->right_elt(index_()) != ST_NIL) { down_right(); down_left_all(); }
    else                { up(); while (dir[depth] == 1) up(); }
    return *this;
  }

  template<typename T, typename COMP, int pks>
  const_tsa_iterator<T, COMP, pks> &
  const_tsa_iterator<T, COMP, pks>::operator --() {
    if (depth == 0) last();
    if (p->left_elt(index_()) != ST_NIL) { down_left(); down_right_all(); }
    else               { up(); while (dir[depth] == -1) up(); }
    return *this;
  }
  
  /* ********************************************************************* */
  /* Definitition of dynamic_tree_sorted.                                  */
  /* ********************************************************************* */

  template<typename T, typename COMP, int pks>
    class dynamic_tree_sorted : public dynamic_tas<T, pks> {
    public :

      typedef typename dynamic_tas<T, pks>::tas_iterator tas_iterator;
      typedef typename dynamic_tas<T, pks>::const_tas_iterator const_tas_iterator;
      typedef typename dynamic_tas<T, pks>::iterator iterator;
      typedef typename dynamic_tas<T, pks>::const_iterator const_iterator;
      typedef typename dynamic_tas<T, pks>::size_type size_type;
                                                    
      typedef gmm::int8_type short_type;
      typedef tsa_iterator<T, COMP, pks> sorted_iterator;
      typedef const_tsa_iterator<T, COMP, pks> const_sorted_iterator;
      typedef std::reverse_iterator<const_iterator> const_reverse_sorted_iterator;
      typedef std::reverse_iterator<iterator> reverse_sorted_iterator;
      
    protected :

      COMP compar;
      struct tree_elt {
	size_type r, l;
	short_type eq;
	inline void init(void) { eq = 0; r = l = ST_NIL; }
	tree_elt(void) { init(); }
      };
      
      dynamic_array<tree_elt, pks> nodes;
      size_type first_node;

      size_type rotate_right(size_type i);
      size_type rotate_left(size_type i);
      size_type rotate_left_right(size_type i);
      size_type rotate_right_left(size_type i);
      size_type balance_again(size_type i);

      void add_index(size_type i, const_sorted_iterator &it);
      void sup_index(size_type i, const_sorted_iterator &it);

    public :

      int verify_balance(size_type i = size_type(-2)) const { // for debugging
	if (i == size_type(-2)) i = first_node;
	if (i == ST_NIL) return 0;
	int l = verify_balance(nodes[i].l);
	int r = verify_balance(nodes[i].r);
	GMM_ASSERT3(short_type(r - l) ==  nodes[i].eq && 
		    (nodes[i].eq <= 1 && nodes[i].eq>=-1), "internal error");
	return std::max(l,r) + 1;
      }
      
      void insert_path(const T &elt, const_sorted_iterator &it) const;
      void search_sorted_iterator(const T &elt, 
				  const_sorted_iterator &it) const;
      void find_sorted_iterator(size_type i, const_sorted_iterator &it) const;
      COMP &comparator(void) { return compar; }
      const COMP &comparator(void) const { return compar; }
      
      dynamic_tree_sorted(COMP cp = COMP()) 
      { first_node = ST_NIL; compar = cp; }

      size_type root_elt(void) const { return first_node; }
      size_type right_elt(size_type n) const { return nodes[n].r; }
      size_type left_elt(size_type n)  const { return nodes[n].l; }
      short_type balance(size_type n) const
      { return short_type((n == ST_NIL) ? 0 : nodes[n].eq); }
      size_type search(const T &elt) const {
	const_sorted_iterator it(*this);
	search_sorted_iterator(elt,it);
	return it.index();
      }
      size_type search_ge(const T &) const;
      size_type memsize(void) const;
      void clear(void)
      { first_node = ST_NIL; nodes.clear(); dynamic_tas<T,pks>::clear(); }
      size_type add(const T &);
      void add_to_index(size_type, const T &);
      size_type add_norepeat(const T &, bool replace = false,
			                bool *present = NULL);
      void resort(void);
      void sup(size_type);
      void swap(size_type, size_type);
      void compact(void);

      sorted_iterator sorted_begin(void)
      { sorted_iterator it(*this); it.first(); return it; }
      const_sorted_iterator sorted_begin(void) const
      { const_sorted_iterator it(*this); it.first(); return it; }
      sorted_iterator sorted_end(void)
      { sorted_iterator it(*this); it.end(); return it; }
      const_sorted_iterator sorted_end(void) const
      { const_sorted_iterator it(*this); it.end(); return it; }
      reverse_sorted_iterator rbegin(void)
	{ return reverse_sorted_iterator(this->end()); }
      const_reverse_sorted_iterator rbegin(void) const
      { return const_reverse_sorted_iterator(this->end()); }
      reverse_sorted_iterator rend(void)
	{ return reverse_sorted_iterator(this->begin()); }
      const_reverse_sorted_iterator rend(void) const
      { return const_reverse_sorted_iterator(this->begin()); }
      sorted_iterator sorted_first(void)
      { sorted_iterator it(*this); it.first(); return it; }
      const_sorted_iterator sorted_first(void) const
      { const_sorted_iterator it(*this); it.first(); return it; }
      sorted_iterator sorted_last(void)
      { sorted_iterator it(*this); it.last(); return it; }
      const_sorted_iterator sorted_last(void) const
      { const_sorted_iterator it(*this); it.last(); return it; }
//       sorted_iterator sorted_ge(const T &elt);
      const_sorted_iterator sorted_ge(const T &elt) const;
  }; 

  template<typename T, typename COMP, int pks>
  std::ostream& operator <<(std::ostream& o,
			    dynamic_tree_sorted<T, COMP, pks> &m) {
    o << "Nomber of elt :" << m.card() << '\n';
    o << "Index du noeud racine :" << m.root_elt() << '\n';
    for (size_t i = 0; i < m.size(); ++i)
      o << "elt " << i << "  left :" << int(m.left_elt(i)) << " right : "
	<< int(m.right_elt(i)) << " balance :" << int(m.balance(i)) << '\n';
    return o;
  }

  template<typename T, typename COMP, int pks>
    typename dynamic_tree_sorted<T, COMP, pks>::size_type
      dynamic_tree_sorted<T, COMP, pks>::rotate_right(size_type i) {
    tree_elt *pni = &(nodes[i]);
    size_type f = pni->l;
    tree_elt *pnf = &(nodes[f]);
    pni->l = pnf->r; pnf->r = i; pnf->eq = pni->eq = 0;
    return f;
  }

  template<typename T, typename COMP, int pks>
    typename dynamic_tree_sorted<T, COMP, pks>::size_type
      dynamic_tree_sorted<T, COMP, pks>::rotate_left(size_type i) {
    tree_elt *pni = &(nodes[i]);
    size_type f = pni->r;
    tree_elt *pnf = &(nodes[f]);
    pni->r = pnf->l; pnf->l = i; pnf->eq = pni->eq = 0;
    return f;
  }

  template<typename T, typename COMP, int pks>
    typename dynamic_tree_sorted<T, COMP, pks>::size_type
      dynamic_tree_sorted<T, COMP, pks>::rotate_left_right(size_type i) {
    tree_elt *pni = &(nodes[i]);
    size_type f = pni->l;
    tree_elt *pnf = &(nodes[f]);
    short_type uba = pnf->eq, ubb = nodes[pnf->r].eq;
    pni->l = rotate_left(f); f = rotate_right(i);
    pnf = &(nodes[f]);
    pnf->eq = short_type(uba - 1);
    nodes[pnf->l].eq = short_type(uba - 1 - ((ubb == 1) ? 1 : 0));
    nodes[pnf->r].eq = short_type(((ubb == -1) ? 1 : 0));

    if (uba == 0 && ubb == 1)
    { 
      pnf->l = balance_again(pnf->l);
      if (nodes[pnf->l].eq == 0) pnf->eq = 0;
    }
    return f;
  }

  template<typename T, typename COMP, int pks>
  typename dynamic_tree_sorted<T, COMP, pks>::size_type
  dynamic_tree_sorted<T, COMP, pks>::rotate_right_left(size_type i) {
    size_type f = nodes[i].r;
    short_type uba = nodes[f].eq, ubb = nodes[nodes[f].l].eq;
    nodes[i].r = rotate_right(f); f = rotate_left(i);
    nodes[f].eq = short_type(uba + 1);
    nodes[nodes[f].r].eq = short_type(uba + 1 + ((ubb == -1) ? 1 : 0));
    nodes[nodes[f].l].eq = short_type(((ubb == +1) ? -1 : 0));

    if (uba == 0 && ubb == -1) {
      nodes[f].r = balance_again(nodes[f].r);
      if (nodes[nodes[f].r].eq == 0) nodes[f].eq = 0;
    }
    return f;
  }

  template<typename T, typename COMP, int pks>
    typename dynamic_tree_sorted<T, COMP, pks>::size_type
      dynamic_tree_sorted<T, COMP, pks>::balance_again(size_type i) {
    tree_elt *pn = &(nodes[i]);
    switch (pn->eq) {
      case -2 : if (nodes[pn->l].eq == -1) return rotate_right(i);
                                      else return rotate_left_right(i);
      case +2 : if (nodes[pn->r].eq == 1) return rotate_left(i);
                                      else return rotate_right_left(i);
      case  0 : case -1 : case 1 : return i;
    default : GMM_ASSERT3(false, "internal error");
    }
    return ST_NIL;
  }

  template<typename T, typename COMP, int pks>
  void dynamic_tree_sorted<T, COMP, pks>::search_sorted_iterator
  (const T &elt, const_sorted_iterator &it) const{
    it.root();
    while (it.index() != ST_NIL) {
      int cp = compar(elt, (*this)[it.index()]);
      if (cp < 0) it.down_left();
      else if (cp > 0) it.down_right(); else break;
    }
  }

  template<typename T, typename COMP, int pks>
  void dynamic_tree_sorted<T, COMP, pks>::find_sorted_iterator
  (size_type i, const_sorted_iterator &it) const {
    const T *pelt = &((*this)[i]);
    it.root();
    while (it.index() != ST_NIL) {
      int cp = compar(*pelt, (*this)[it.index()]);
      if (cp == 0) { if (it.index() == i) break; else it.down_left(); }
      else if (cp < 0) it.down_left(); else it.down_right();
    }
    if (it.index() == ST_NIL) it.up();
    while (it.index() != i && it.index() != ST_NIL) ++it;
    /* peut etre il faudrait controler dans la boucle le depacement        */
    /* pour eviter de faire tout le tableau en cas de faux indice.         */
  }

  template<typename T, typename COMP, int pks>
  void dynamic_tree_sorted<T, COMP, pks>::insert_path
  (const T &elt, const_sorted_iterator &it) const {
    it.root();
    while (it.index() != ST_NIL) {
      int cp = compar(elt, (*this)[it.index()]);
      if (cp <= 0) it.down_left(); else it.down_right();
    }
  }

  template<typename T, typename COMP, int pks>
  typename dynamic_tree_sorted<T, COMP, pks>::size_type
  dynamic_tree_sorted<T, COMP, pks>::search_ge(const T &elt) const {
    const_sorted_iterator it(*this); insert_path(elt, it);
    short_type dir = it.direction();
    if (it.index() == ST_NIL)
      { it.up(); if (it.index() != ST_NIL && dir == +1) ++it; }
    return it.index();
  }
  
//   template<typename T, typename COMP, int pks>
//     typename dynamic_tree_sorted<T, COMP, pks>::sorted_iterator
//       dynamic_tree_sorted<T, COMP, pks>::sorted_ge(const T &elt)
//   {
//     sorted_iterator it(*this); insert_path(elt, it);
//     short_type dir = it.direction();
//     it.up(); if (it.index() != ST_NIL && dir == +1) ++it;
//     return it;
//   } 

  template<typename T, typename COMP, int pks>
  typename dynamic_tree_sorted<T, COMP, pks>::const_sorted_iterator
  dynamic_tree_sorted<T, COMP, pks>::sorted_ge(const T &elt) const {
    const_sorted_iterator it(*this); insert_path(elt, it);
    short_type dir = it.direction();
    it.up(); 
    if (it.index() != ST_NIL && dir == +1) ++it;
    return it;
  }
  

  template<typename T, typename COMP, int pks>
  typename dynamic_tree_sorted<T, COMP, pks>::size_type
  dynamic_tree_sorted<T, COMP, pks>::memsize(void) const {
    return dynamic_tas<T, pks>::memsize() + nodes.memsize()
      + sizeof(dynamic_tree_sorted<T, COMP, pks>);
  }

  template<typename T, typename COMP, int pks>
  void dynamic_tree_sorted<T, COMP, pks>::compact(void) {
    if (!this->empty())
      while (this->ind.last_true() >= this->ind.card())
	swap(this->ind.first_false(), this->ind.last_true());
  }
  
  template<typename T, typename COMP, int pks>
  void dynamic_tree_sorted<T, COMP, pks>::add_index
  (size_type i, const_sorted_iterator &it) {
    nodes[i].init();
    if (first_node == ST_NIL)
      first_node = i;
    else { 
      short_type dir = it.direction();
      it.up();
      if (dir == -1) nodes[it.index()].l = i; else nodes[it.index()].r = i;
      
      while(it.index() != ST_NIL) {
	short_type *peq = &(nodes[it.index()].eq);
	if (*peq == 0) *peq = short_type(*peq + dir);
	else { 
	  *peq = short_type(*peq + dir);
	  size_type f = balance_again(it.index());
	  dir = it.direction();
	  it.up();
	  switch (dir) {
	    case 0 : first_node = f; break;
	    case -1 : nodes[it.index()].l = f; break;
	    case +1 : nodes[it.index()].r = f; break;
	  }
	  break;
	}
	dir = it.direction();
	it.up();
      }
    }
  }

  template<typename T, typename COMP, int pks>
  typename dynamic_tree_sorted<T, COMP, pks>::size_type
  dynamic_tree_sorted<T, COMP, pks>::add(const T &f) {
    const_sorted_iterator it(*this); insert_path(f, it);
    size_type num = dynamic_tas<T,pks>::add(f);
    add_index(num, it);
    return num;
  }

  template<typename T, typename COMP, int pks> void
  dynamic_tree_sorted<T, COMP, pks>::add_to_index(size_type i,const T &f) {
    if (!(this->index_valid(i) && compar(f, (*this)[i]) == 0)) {
      if (this->index_valid(i)) sup(i);
      dynamic_tas<T,pks>::add_to_index(i, f);
      const_sorted_iterator it(*this); insert_path(f, it);
      add_index(i, it);
    }
  }

  template<typename T, typename COMP, int pks>
  typename dynamic_tree_sorted<T, COMP, pks>::size_type
  dynamic_tree_sorted<T, COMP, pks>::add_norepeat
  (const T &f, bool replace, bool *present) {
    const_sorted_iterator it(*this); search_sorted_iterator(f, it);
    size_type num = it.index();
    if (num == ST_NIL) { 
      if (present != NULL) *present = false;
      num = dynamic_tas<T,pks>::add(f); add_index(num, it);
    }
    else {
      if (present != NULL) *present = true;
      if (replace) (*this)[num] = f;
    }
    return num;
  }

  template<typename T, typename COMP, int pks> 
  void dynamic_tree_sorted<T, COMP, pks>::resort(void)  {
    const_tas_iterator itb
      = ((const dynamic_tree_sorted<T, COMP, pks> *)(this))->tas_begin();
    const_tas_iterator ite
      = ((const dynamic_tree_sorted<T, COMP, pks> *)(this))->tas_end();
    const_sorted_iterator it(*this);
    first_node = ST_NIL;
    while (itb != ite)
    { insert_path(*itb, it); add_index(itb.index(), it); ++itb; }
  }     

  template<typename T, typename COMP, int pks>
  void dynamic_tree_sorted<T, COMP, pks>::sup_index
  (size_type i, const_sorted_iterator &it) {
    size_type f, ni = i, ic;
    short_type dir;
    tree_elt *pni = &(nodes[i]), *pnc = 0;

    if (pni->l == ST_NIL || pni->r == ST_NIL) {
      f = (pni->l != ST_NIL) ? pni->l : pni->r;
      dir = it.direction(); it.up(); ic = it.index();
      if (ic != ST_NIL) pnc = &(nodes[ic]);
      switch (dir) {
        case 0 : first_node = f; break;
        case -1 : pnc->l = f; break;
        case +1 : pnc->r = f; break;
      }
    }
    else {
      f = it.father(); 
      dir = it.direction();
      it--; ni = it.index();
      switch (dir) {
        case 0 : first_node = ni; break;
        case -1 : nodes[f].l = ni; break;
        case +1 : nodes[f].r = ni; break;
      }
      pnc = &(nodes[ni]); f = pnc->l; *pnc = *pni;
      dir = it.direction();
      it.up(); ic = it.index(); if (ic == i) ic = ni; pnc = &(nodes[ic]);
      if (dir == -1) pnc->l = f; else pnc->r = f;
    }

    while (it.index() != ST_NIL) {
      short_type ub = pnc->eq;
      pnc->eq = short_type(pnc->eq - dir);
      if (ub == 0) break;
      f = balance_again(ic);
      ub = nodes[f].eq;
      dir = it.direction();
      it.up(); ic = it.index(); if (ic == i) ic = ni;
      if (ic != ST_NIL) pnc = &(nodes[ic]);
      switch (dir) {
        case 0 : first_node = f; break;
        case -1 : pnc->l = f; break;
        case +1 : pnc->r = f; break;
      }
      if (ub != 0) break;
    }
  }
  
  template<typename T, typename COMP, int pks>
  void dynamic_tree_sorted<T, COMP, pks>::sup(size_type i) {
    GMM_ASSERT2(i < INT_MAX, "out of range");
    const_sorted_iterator it(*this); find_sorted_iterator(i, it);
    if (it.index() != ST_NIL)
    { sup_index(i, it); dynamic_tas<T, pks>::sup(i); }
  }

  template<typename T, typename COMP, int pks>
  void dynamic_tree_sorted<T, COMP, pks>::swap(size_type i, size_type j) {
    GMM_ASSERT2(i < INT_MAX && j < INT_MAX, "out of range");

    if (i != j) {
      const_sorted_iterator it1(*this), it2(*this); it1.end(); it2.end();

      if (this->index_valid(i)) find_sorted_iterator(i, it1);
      if (this->index_valid(j)) find_sorted_iterator(j, it2);

      short_type dir1 = it1.direction(), dir2 = it2.direction();
      it1.up(); it2.up(); 
      size_type f1 = it1.index(), f2 = it2.index();

      if (f1!=ST_NIL) { if (dir1==-1) nodes[f1].l = j; else nodes[f1].r = j; }
      if (f2!=ST_NIL) { if (dir2==-1) nodes[f2].l = i; else nodes[f2].r = i; }
      if (first_node==i) first_node=j; else if (first_node==j) first_node=i;
      
      std::swap(nodes[i], nodes[j]);
      dynamic_tas<T,pks>::swap(i,j);
    }
  }

  /* ********************************************************************* */
  /* Definitition d'un dynamic_tree_sorted utilise comme index sur tableau.*/
  /* ********************************************************************* */
  /* pas completement satisfaisant. A utiliser avec precautions.           */

  template<typename T, typename TAB, typename COMP> struct less_index
    : public std::binary_function<size_t, size_t, int> {
    const TAB *tab;
    COMP compare;
    mutable const T *search_elt;
    
    int operator()(size_t i, size_t j) const { 
      return compare( (i == ST_NIL) ? *search_elt : (*tab)[i],
		      (j == ST_NIL) ? *search_elt : (*tab)[j] );
    }

    less_index(const TAB &t, const COMP &c)
    { compare = c; tab = &t; }
    less_index(void) {}

  };


  template<typename T, typename TAB, typename COMP = gmm::less<T>, int pks = 5>
  class dynamic_tree_sorted_index : public
  dynamic_tree_sorted<size_t, less_index<T,TAB,COMP>, pks> {
  public :
     
    typedef typename
    dynamic_tree_sorted<size_t, less_index<T,TAB,COMP>, pks>::size_type
    size_type;
  
  protected :
    
    typedef dynamic_tree_sorted<size_t, less_index<T,TAB,COMP>, pks> dts_type;
    
  public :
    
    dynamic_tree_sorted_index(TAB &t, COMP cp = COMP())
      : dts_type(less_index<T,TAB,COMP>(t, cp)) { }
    
    void change_tab(TAB &t, COMP cp = COMP())
    {  this->comparator() = less_index<T,TAB,COMP>(t, cp); }
    
    size_type search(const T &elt) const { 
      this->compar.search_elt = &elt;
      return dts_type::search(ST_NIL);
    }
    size_type search_ge(const T &elt) const {
      this->compar.search_elt = &elt;
      return dts_type::search_ge(ST_NIL);
    }
    size_type add(size_type i) {
      typename dts_type::const_sorted_iterator it(*this); (*this)[i] = i;
      this->ind[i] = true; insert_path(i, it); add_index(i, it); return i;
    }
    
  };
  
}

#endif /* DAL_TREE_SORTED_H__ */
