/*******************************************************************************************

Copyright (C) 2004,2005,2006,2007,2008 (Nuno A. Fonseca) <nuno.fonseca@gmail.com>

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., 675 Mass Ave, Cambridge, MA 02139, USA.


Last rev: $Id: range_list.c,v 1.1 2008-03-26 23:05:22 nunofonseca Exp $
**************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "range_list.h"

/*****************************************************************************/



void set_num_bit(unsigned int number,char* storage,STATUS status);
BOOLEAN is_num_bit(unsigned int number,char *storage,STATUS status);

static void set_quadrant(RL_Node* node,short quadrant,QUADRANT_STATUS status);
static QUADRANT_STATUS quadrant_status(RL_Node* node,short quadrant);

static void quadrant_interval(RL_Tree *tree,short quadrant,NUM interval,NUM *quad_interval);
static NUM get_quadrant_node(RL_Tree* tree,NUM node,short quadrant,NUM interval);
static unsigned int tree_size(RL_Tree *tree,NUM node,NUM);

int get_location(RL_Tree* tree,NUM node,short quadrant,NUM interval);

long set_in(NUM number,NUM node, NUM node_num, NUM interval,NUM max,RL_Tree* tree,STATUS status);
long compact_node(RL_Tree*,NUM node,NUM next_node,NUM node_interval,NUM next_node_interval,NUM next_node_num,short quadrant,NUM max);

BOOLEAN in_tree(NUM number,RL_Tree *tree,NUM node,NUM node_num,NUM interval);
void display_tree(RL_Tree *tree);
void idisplay_tree(RL_Tree *tree,NUM node,NUM node_num,NUM interval,NUM max);
static void display_leaf(RL_Tree* tree,NUM node,NUM node_num,NUM max);

NUM new_node(RL_Tree* tree,NUM node_father,short quadrant,NUM node_num,NUM quad_min,NUM quad_max,STATUS);
static void root_intervals(RL_Tree* tree);

NUM next_min(RL_Tree *tree,NUM node,NUM node_num,NUM interval,NUM max,NUM min);
NUM tree_minus(RL_Tree *r1,RL_Tree *r2,NUM node1,NUM node2,NUM node_num,NUM interval,NUM max);

RL_Tree* minus_rl(RL_Tree* range1,RL_Tree* range2);
void shift_right(RL_Tree *tree,const NUM idx,const long nnodes);
void shift_left(RL_Tree *tree,const NUM idx, const long nnodes);
void intersect_leafs(char *storage1,char *storage2);

static void print_nodes(RL_Tree* tree);

//
RL_Buffer* buffer=NULL;
unsigned int active_bits[16]={
  1,
  3,
  7,
  15,
  31,
  63,
  127,
  255,
  511,
  1023,
  2047,
  4095,
  8191,
  16383,
  32767,
  65535
};


/*****************************************************************************/
/*
 *
 *
 */
RL_Tree* new_rl(NUM max_size) {

  RL_Tree *new;
  RL_Node *buf_ptr;
  short q;
  NUM qi,tmp;
  
  if ( max_size <2 ) 
    max_size=2; 

  new=(RL_Tree*)malloc(sizeof(RL_Tree));
  if(new==NULL)
    return NULL;

  new->range_max=max_size;
  root_intervals(new);

  // alloc a block for the nodes
  new->root=(RL_Node*)calloc(1,NODE_SIZE);
  new->size=1;
  new->mem_alloc=NODE_SIZE; // memory allocated

  // reset buffer
  buf_ptr=new->root;//tree_buffer();
  ALL_OUT(&buf_ptr[0]); // Initialize all numbers as being out of the range/interval
  buf_ptr[0].i_node.num_subnodes=1;
  new->root=buf_ptr;// pointer to the buffer

  buf_ptr->i_node.num_subnodes=1;
  quadrant_interval(new,1,max_size,&qi);
  tmp=qi+1;
  for(q=2;q<=BRANCH_FACTOR;++q) {
    if ( max_size < qi*(q-1)+1 )  // 16 32 48 64 - 32
      set_quadrant(new->root,q,R_IGNORE);
    tmp+=qi;  // max_size=16  16+1
  }

  return new;
}
/*
 *
 *
 */
RL_Tree* copy_rl(RL_Tree *tree) {

  RL_Tree *new;
  RL_Node *buf_ptr;

  new=(RL_Tree*)malloc(sizeof(RL_Tree));
  buf_ptr=(RL_Node*)calloc(tree->size,NODE_SIZE);
  if( new==NULL ) {
    printf("new==NULL");
    return NULL;
  }
  if( buf_ptr==NULL ) {
    printf("buf_ptr==NULL---%lu",tree->size);
    return NULL;
  }
  memcpy(new,tree,sizeof(RL_Tree));
  memcpy(buf_ptr,&tree->root[0],tree->size*NODE_SIZE);
  new->root=buf_ptr;
  new->mem_alloc=tree->size*NODE_SIZE; 
  return new;
}
/*
 *
 *
 */
void free_rl(RL_Tree* range) {
  
  // free nodes block
  if(range->mem_alloc!=0)
    free(range->root);
  //
  free(range);
}
/*
 
 */
RL_Tree* set_in_rl(RL_Tree* tree,NUM number,STATUS status) {

  /* */
  if ( number >0 && number <=tree->range_max)
    set_in(number,ROOT(tree),1,ROOT_INTERVAL(tree),tree->range_max,tree,status);
#ifdef DEBUG
  printf("Setting: %d  size=%d\n",number,tree->size);
#endif
  /*if (status==IN && !in_rl(tree,number)) {
    fprintf(stderr,"Error adding %lu to tree: size=%lu max=%lu\n",number,tree->size,tree->range_max);
    display_tree(tree);
    exit(1);
    }*/
  return tree;
}
/*
 * Mark all examples in range IN/OUT
 */
void rl_all(RL_Tree* tree,STATUS status) {
  int i;

  for(i=1;i<=BRANCH_FACTOR;++i)
    if (quadrant_status(NODE(tree,ROOT(tree)),i)!=R_IGNORE) {
      if(status==IN)
	set_quadrant(NODE(tree,ROOT(tree)),i,R_TOTALLY_IN_INTERVAL);
      else
	set_quadrant(NODE(tree,ROOT(tree)),i,R_NOT_IN_INTERVAL);
    }
  tree->size=1;
}
/*
 *
 *
 */
BOOLEAN  in_rl(RL_Tree* tree,NUM number) { 
  if ( number <1 && number >tree->range_max)
    return FALSE;
  return in_tree(number,tree,ROOT(tree),1,ROOT_INTERVAL(tree));
}
/*
 *
 *
 */
BOOLEAN  freeze_rl(RL_Tree* range) {
  
  //  reduce memory usage if possible
  NUM s=range->size*NODE_SIZE;
  if ( s < range->mem_alloc) {
    range->root=(RL_Node*)realloc(range->root,s);
    range->mem_alloc=s;
  }
  return TRUE;
}
/*
 * Returns range1 without the numbers in range2
 * Constraint:range1->max==range2->max
 */
RL_Tree* minus_rl(RL_Tree* range1,RL_Tree* range2) {
  if (range1->range_max!=range1->range_max) 
    return NULL;
  //!!!!tree_minus(range1,range2,ROOT(range1),ROOT(range2),1,ROOT_INTERVAL(range1),range1->range_max);
  return range1;
}

/*
 * Returns next number in tree bigger than min 
 */
NUM rl_next_in_bigger(RL_Tree *tree,NUM min) {
  if ( tree==NULL ) {
    fprintf(stdout,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%lu\n",min);
  }
  return next_min(tree,ROOT(tree),1,ROOT_INTERVAL(tree),tree->range_max,min+1);
}
/* ****************************************************************************** 
   Private Functions
   ****************************************************************************** */
static void print_nodes(RL_Tree* tree) {
  RL_Node* nodes=tree->root;
  int j;
  
  for(j=0;j<tree->size;++j) 
    printf("[%d]=%lu\n",j,(unsigned long int)nodes[j].leaf);
  
}
// treeXquadrantXinterval->quadrant_minXquadrant_max
static void quadrant_interval(RL_Tree *tree,short quadrant,NUM interval,NUM *quad_interval) {
  
  if ( IS_ROOT(tree,interval) ) {
    *quad_interval=tree->root_i;
  } else {
    *quad_interval=NEXT_INTERVAL(interval);
  }
}

// numberXtreeXinterval->quadrantXquadrant_minXquadrant_max
static void number_quadrant(NUM number,RL_Tree *tree,NUM node_interval,NUM node_num,short *quadrant,NUM *quad_min,NUM *quad_max) {
  NUM tmp=node_num-1,quad_interval;
  int i;
  quadrant_interval(tree,1,node_interval,&quad_interval);
  i=(number-node_num)/quad_interval+1;
  tmp=node_num-1+quad_interval*i;
  *quad_max=tmp;
  *quadrant=i;
  *quad_min=tmp-quad_interval+1;
  //printf("number=%lu node num=%lu quad_interval=%lu-------> quadrant=%d   quad_max=%lu\n",number,node_num,quad_interval,i,tmp);
}

/*
 * returns the index to the quadrant "quadrant" node
 */
static NUM get_quadrant_node(RL_Tree* tree,NUM node,short quadrant,NUM interval) {
  int d=get_location(tree,node,quadrant,interval);
  return node+d;
}
/*                 src    s 
 *  src= 1 2 3 4 5 6 _ _
 *  offset= 2
 *  nbytes=6
 *  >>>src= 1 2 1 2 3 4 5 6 
 *                    src    s
 */
void shift_right(RL_Tree *tree,const NUM idx,const long nnodes){
  long n=idx+nnodes;
  RL_Node *s=tree->root;

  if (nnodes<=0) return;
  //print_nodes(tree);
  while(n>=idx) {
    s[n+1].leaf=s[n].leaf;
    --n;
  }
  //print_nodes(tree); 
  //printf(">>----------------\n");
}

void shift_left(RL_Tree *tree,const NUM idx, const long nnodes){
  long n=idx;
  RL_Node *s=tree->root;

  //printf("sfit left: idx=%u nnodes=%u max=%u\n",idx,nnodes,tree->size);
  if ( nnodes<=0 )  // last element
    return;
  
  //  print_nodes(tree);
  while(n<idx+nnodes) {
    s[n].leaf=s[n+1].leaf;
    ++n;;
  }
  //  print_nodes(tree);
  //printf("<<----------------\n");
}

/*
 *
 *
 */
NUM new_node(RL_Tree* tree,NUM node_father,short quadrant,NUM father_interval,NUM quad_min,NUM quad_max,STATUS status) {
  //RL_Node *new,*root_node=tree->root;
  NUM new_interval=+NEXT_INTERVAL(father_interval);
  NUM times;
  NUM new;
  RL_Node* ptr;
  new=get_quadrant_node(tree,node_father,quadrant,father_interval);
  
  if ( tree->mem_alloc!=0 ) {
    // increase array size and shift elements right
    if ( REALLOC_MEM(tree) ) {
      //printf("new node:resizing memory: current %lu -> new %lu  [%lu]\n",tree->mem_alloc,MEM_SIZE(tree),tree->size);
      ptr=(RL_Node*)realloc(tree->root,MEM_SIZE(tree));
      if ( ptr==NULL ) {
	fprintf(stderr,"Fatal error:range_list: Unable to allocate memory");
	exit(1);
      }
      tree->root=ptr;
      tree->mem_alloc=MEM_SIZE(tree);
    }
    // SHIFT elements at the right and including the current node one position
    times=tree->size-1-new;
    shift_right(tree,new,times);
      //      SHIFT_NODES((void*)new,times*NODE_SIZE);
  }
  // update father reference
  set_quadrant(NODE(tree,node_father),quadrant,R_PARCIALLY_IN_INTERVAL);
  // initialize node
  if ( status==IN) {
    ALL_OUT(NODE(tree,new));    // clear all bits
    if ( !IS_LEAF(new_interval) ) {
      short q;
      RL_Node* node_ptr=NODE(tree,new);
      node_ptr->i_node.num_subnodes=1;
      for(q=2;q<=BRANCH_FACTOR;++q) 
	if (  MIN(quad_max,tree->range_max) < quad_min+NEXT_INTERVAL(new_interval)*(q-1)  ) //QUADRANT_MAX_VALUE(
	  set_quadrant(NODE(tree,new),q,R_IGNORE);
    }
  } else {
    // status ==out
    //SET_LEAF_IN(tree->range_max,NODE(tree,new),quad_min);
    tree->root[new].leaf=ON_BITS(MIN(16,tree->range_max-quad_min+1));
    if ( !IS_LEAF(new_interval) ) {
      short q;
      RL_Node* node_ptr=NODE(tree,new);
      node_ptr->i_node.num_subnodes=1;
      node_ptr->i_node.quadrant_1=node_ptr->i_node.quadrant_2=node_ptr->i_node.quadrant_3=node_ptr->i_node.quadrant_4=R_TOTALLY_IN_INTERVAL;
      for(q=2;q<=BRANCH_FACTOR;++q) 
	if (  MIN(quad_max,tree->range_max) < quad_min+NEXT_INTERVAL(new_interval)*(q-1)  ) //QUADRANT_MAX_VALUE(
	  set_quadrant(NODE(tree,new),q,R_IGNORE);
    }
  }
  // update tree size
  tree->size++;
  return new;
}

/*
 * returns the offset
 *
 */
int get_location(RL_Tree* tree,NUM node,short quadrant,NUM node_interval) {
  int i,c=1,tmp;
  NUM next_node;
  NUM next_interval;

  if (quadrant==1 || IS_LEAF(node_interval)) return 1;

  //
  if ( LAST_LEVEL_INODE(node_interval) ) {
    // 1 node = current
    for(i=1;i<quadrant;++i) {
      if ( quadrant_status(NODE(tree,node),i)==R_PARCIALLY_IN_INTERVAL )
	++c;
    }
    return c;
  }
  
  //
  // internal range list nodes
  quadrant_interval(tree,quadrant,node_interval,&next_interval);
  i=1;
  next_node=node+1;
  while(i!=quadrant && i<=BRANCH_FACTOR) {
    if ( quadrant_status(NODE(tree,node),i)==R_PARCIALLY_IN_INTERVAL ) {
      tmp=tree_size(tree,next_node,next_interval);
      next_node+=tmp;
      c+=tmp;
    }
    ++i;
  }
  
  return c;
}
/*
 * Returns the number of nodes created/deleted.
 *
 * number: number to insert from the interval
 * node:   index of current node
 * node_num: number corresponding to the beginning o the interval represented by node
 * interval: size of the interval represented in the current node
 */
long set_in(NUM number,NUM node, NUM node_num, NUM node_interval,NUM max,RL_Tree* tree,STATUS status) {
  NUM next_node;
  long ret_val=tree->size,compacted;
  NUM interval=node_interval;
  NUM quad_min,quad_max;
  short quadrant;
  NUM size;
  /* */
  if ( IS_LEAF(interval) ) {
    // current node is a leaf
    set_num_bit(number-node_num,(char*)NODE(tree,node),status);
    return 0;
  }
  //
  number_quadrant(number,tree,node_interval,node_num,&quadrant,&quad_min,&quad_max);
  interval=quad_max-quad_min+1;
  // select next node
  switch(status) {
  case IN:
  // move pointer to next node
    if ( quadrant_status(NODE(tree,node),quadrant)==R_NOT_IN_INTERVAL ) {
      // new node
      //display_tree(tree);
      next_node=new_node(tree,node,quadrant,node_interval,quad_min,quad_max,status);
    }else if ( quadrant_status(NODE(tree,node),quadrant)==R_TOTALLY_IN_INTERVAL ) 
      return 0;
    else
      next_node=get_quadrant_node(tree,node,quadrant,node_interval);
    break;
  case OUT:
    if ( quadrant_status(NODE(tree,node),quadrant)==R_TOTALLY_IN_INTERVAL ) {
      // new node
      next_node=new_node(tree,node,quadrant,node_interval,quad_min,quad_max,status);
    } else if ( quadrant_status(NODE(tree,node),quadrant)==R_NOT_IN_INTERVAL ) 
      return 0;
    else
      next_node=get_quadrant_node(tree,node,quadrant,node_interval);
    break;
  default:
    printf("set_in: invalid number status %d\n",status);
    exit(1);
  }
  // insert in tree
  set_in(number,next_node,quad_min,interval,quad_max,tree,status);
  ret_val=tree->size-ret_val; // number of nodes added/removed
  // compact tree: only if we didn't create new nodes
  //compacted=compact_node(tree,node,next_node,node_interval,interval,quad_min,quadrant,MIN(quad_max,tree->range_max));
  compacted=0;
  if ( compacted==-1 ) {
    //NUM times=tree->size-1-next_node; // -1 because array position 0
    shift_left(tree,next_node,1);
    // update tree size
    tree->size+=compacted;
    ret_val+=compacted;
    //ret_val=0;//compacted;  
  }
  // update subnodes number
  if ( tree->root[node].i_node.num_subnodes ==255 ) 
    size=tree_size(tree,node,interval);
  else
    size=ret_val+tree->root[node].i_node.num_subnodes; // new subnodes value

  if ( size > 254 )
    tree->root[node].i_node.num_subnodes=255;
  else
    tree->root[node].i_node.num_subnodes=size;
  
  //  if (size <0 ) exit(1);
  return ret_val;
}
/*
 * Check if can change quadrant color of node. If it changes, the node is deleted and all nodes at right in the array are shifted one position.
 *
 */
long compact_node(RL_Tree *tree,NUM node,NUM next_node,NUM node_interval,NUM next_node_interval,NUM next_node_num,short quadrant,NUM max){
  unsigned int j;

  RL_Node* node_ptr=NODE(tree,next_node); // next node pointer
  
  // Try to compact a leaf
  if ( IS_LEAF(next_node_interval) ) {
#ifdef DEBUG
    fprintf(stderr,"compact_node: interval node\n");
#endif
    // ALL IN
    if ( LEAF_ALL_IN(node_ptr->leaf) ) {
      set_quadrant(NODE(tree,node),quadrant,R_TOTALLY_IN_INTERVAL);
      return -1;
    }
    // ALL IN: part II
    // The last node does not need to be all in
    if ( max-next_node_num+1 <= LEAF_SIZE ) {
      j=ON_BITS(max-next_node_num+1); //153,154,155,156,157,.,.,.,[158   -> valor do max=200 devia ser 158
      if ( node_ptr->leaf==j ) {
	set_quadrant(NODE(tree,node),quadrant,R_TOTALLY_IN_INTERVAL);
	return -1;
      }
    }
    // ALL OUT
    if ( LEAF_ALL_OUT(node_ptr->leaf) ) {
      set_quadrant(NODE(tree,node),quadrant,R_NOT_IN_INTERVAL);
#ifdef DEBUG
      printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>compacted leaf1\n");
#endif
      return -1;
    }
  } else {
#ifdef DEBUG
    fprintf(stderr,"compact_node:range node\n");
#endif
    // INODE - range list node
    if ( node_ptr->i_node.num_subnodes>1 ) // unable to compact
      return 0;
    // ALL IN
    for(j=1;j<=BRANCH_FACTOR;++j)
      if ( quadrant_status(NODE(tree,next_node),j)!=R_IGNORE && quadrant_status(NODE(tree,next_node),j)!=R_TOTALLY_IN_INTERVAL )
    	break;

    if (j>BRANCH_FACTOR) {
      set_quadrant(NODE(tree,node),quadrant,R_TOTALLY_IN_INTERVAL);
      return -1;
    }
    // ALL OUT
    for(j=1;j<=BRANCH_FACTOR;++j)
      if ( quadrant_status(NODE(tree,next_node),j)!=R_IGNORE && quadrant_status(NODE(tree,next_node),j)!=R_NOT_IN_INTERVAL )
    	break;

    if (j>BRANCH_FACTOR) {
      set_quadrant(NODE(tree,node),quadrant,R_NOT_IN_INTERVAL);
      return -1;
    }
  }
  return 0;
}

/*
 * interval: interval associated to the node
 */
static  unsigned int tree_size(RL_Tree *tree,NUM node,NUM interval) {
  unsigned int c=1,tmp;
  int i=1;
  short status;
  NUM next_interval;
  NUM next_node;
  RL_Node* node_ptr=NODE(tree,node);

  if ( IS_LEAF(interval)) return 1;

  if ( node_ptr->i_node.num_subnodes==255) {
    // compute the size of all subtrees
    next_interval=NEXT_INTERVAL(interval);
    for(i=1;i<=BRANCH_FACTOR;++i) {
      status=quadrant_status(NODE(tree,node),i);
      switch(status) {
      case R_PARCIALLY_IN_INTERVAL:
	next_node=node+c; //      
	tmp=tree_size(tree,next_node,next_interval);
	c+=tmp;
	//      default: 
      }
    }
  } 
  else c=node_ptr->i_node.num_subnodes;
  return c;
}
/*
 * number >=1 && number <=16
 */
void set_num_bit(unsigned int number,char *storage,STATUS status) {
  if ( number >= 8 ) {
    storage++;
    number=number-8; // =-8
  } 
  if ( status==IN )
    BITMAP_insert(*storage,number);
  else
    BITMAP_delete(*storage,number);
}
/*
 */
BOOLEAN is_num_bit(unsigned int number,char *storage,STATUS status) {
  if ( number >= 8 ) {
    storage++;
    number=number-8; // =-8
  } 
  if ( status==IN )
    return BITMAP_member(*storage,number);
  else
    return !BITMAP_member(*storage,number);
}
/*
 *
 */
static void set_quadrant(RL_Node *node,short quadrant,QUADRANT_STATUS status){

  switch(quadrant){
  case 1:
    node->i_node.quadrant_1=status;
    break;
  case 2:
    node->i_node.quadrant_2=status;
    break;
  case 3:
    node->i_node.quadrant_3=status;
    break;
  case 4:
    node->i_node.quadrant_4=status;
    break;
  default:
    fprintf(stderr,"ERROR: set_quadrant: invalid quadrant %d(%d)\n",quadrant,status);
  }
}
/*
 *
 */
static QUADRANT_STATUS quadrant_status(RL_Node *node,short  quadrant){

  switch(quadrant){
  case 1:
    return node->i_node.quadrant_1;
  case 2:
    return node->i_node.quadrant_2;
  case 3:
    return node->i_node.quadrant_3;
  case 4:
    return node->i_node.quadrant_4;
  default:
    fprintf(stderr,"ERROR: quadrant_status: invalid quadrant(%d)\n",quadrant);
  }
  return 0;
}
/*
 *
 *
 */
static BOOLEAN in_leaf(NUM number,RL_Tree *tree,NUM node,NUM node_num,NUM max) {

  if(is_num_bit(number-node_num,(char*)NODE(tree,node),IN))
      return TRUE;
  return FALSE;
}

/*
 *
 *
 */
BOOLEAN in_tree(NUM number,RL_Tree *tree,NUM node,NUM node_num,NUM node_interval) {
  NUM next_node;
  short quadrant;
  NUM interval=node_interval;
  NUM max=MIN(node_num+interval,tree->range_max);
  NUM quad_min,quad_max;

  /* */
  if ( IS_LEAF(interval))
    // current node is a leaf
    return in_leaf(number,tree,node,node_num,max);
    
  number_quadrant(number,tree,node_interval,node_num,&quadrant,&quad_min,&quad_max);
  interval=quad_max-quad_min+1;
  node_num=quad_min;
  
  if ( quadrant_status(NODE(tree,node),quadrant)==R_PARCIALLY_IN_INTERVAL ) {
    next_node=get_quadrant_node(tree,node,quadrant,node_interval);
    return in_tree(number,tree,next_node,node_num,interval);
  } 
  if ( quadrant_status(NODE(tree,node),quadrant)==R_TOTALLY_IN_INTERVAL ) 
    return TRUE;
  
  return FALSE;
}


/* ************************************************************************************************* */
/* I/O                                                                                               */
/* ************************************************************************************************* */

/*
 *
 */
static void display_leaf(RL_Tree *tree,NUM node,NUM node_num,NUM max) {
  int i;
  printf("|");
  //for(i=0;i<LEAF_SIZE && node_num+i<=max;++i)
  for(i=0;i<LEAF_SIZE ;++i)
    if(is_num_bit(i,(char*)NODE(tree,node),IN))
      printf(",%lu",node_num+i);
    else
      printf(",.");
  printf("|");
}
/*
 *
 */
void display_tree(RL_Tree *tree) {
    
  // root node
  NUM init,max;
  NUM next_node;
  int i;
  short status;

  NUM qi,tmp=0;
  next_node=0;//tree->root;

  printf("Size:%lu -[1,%lu]\n",tree->size,tree->range_max);
  qi=ROOT_INTERVAL(tree)/BRANCH_FACTOR;
  //quadrant_interval(tree,1,tree->range_max,&qi);
  for(i=1;i<=BRANCH_FACTOR;++i) {
    tmp+=qi;
    //
    init=tmp-qi+1;
    max=tmp;
    status=quadrant_status(NODE(tree,0),i);
    switch(status) {
    case R_PARCIALLY_IN_INTERVAL:
      next_node=get_quadrant_node(tree,ROOT(tree),i,qi*BRANCH_FACTOR);
      idisplay_tree(tree,next_node,init,qi,max);
      break;
    case R_TOTALLY_IN_INTERVAL:
      printf(",[%lu-%lu]",init,MIN(max,tree->range_max));
      break;
    case R_IGNORE: 
      break;
    default: 
      /*  not in */
      printf(",]%lu-%lu[",init,MIN(max,tree->range_max));
    }
  }
  printf("\n");
}
/*
 *
 *
 */
void idisplay_tree(RL_Tree *tree,NUM node,NUM node_num,NUM interval,NUM max) {
  NUM next_node;
  short quadrant;
  NUM interval2;
  NUM node_num2;
  NUM quadrant_max;
  short status;

  if ( IS_LEAF(interval) )
    return display_leaf(tree,node,node_num,MIN(max,tree->range_max));
   
  interval2=NEXT_INTERVAL(interval);
  //
  for(quadrant=1;quadrant<=BRANCH_FACTOR;++quadrant){
    node_num2=node_num+(quadrant-1)*interval2;
    quadrant_max=QUADRANT_MAX_VALUE(node_num,quadrant,interval2,max);
    status=quadrant_status(NODE(tree,node),quadrant);
    switch(status) {
    case R_PARCIALLY_IN_INTERVAL:
      next_node=get_quadrant_node(tree,node,quadrant,interval);
      if ( IS_LEAF(interval2) )
	display_leaf(tree,next_node,node_num2,MIN(quadrant_max,tree->range_max));
      else 
	idisplay_tree(tree,next_node,node_num2,interval2,quadrant_max);
      break;
    case R_TOTALLY_IN_INTERVAL:
      printf(",[%lu-%lu]",node_num2,MIN(node_num2+interval2-1,max));
      break;
    case R_IGNORE:
      break;
    default:
      printf(",]%lu-%lu[",node_num2,MIN(tree->range_max,node_num2+interval2-1));
    }
  }
}


/* *************************************************************************************************** */
static NUM next_in_leaf(RL_Tree *tree,NUM node,NUM node_num,NUM max,NUM min) {
  NUM number;
  number=node_num;
  if ( number<min) number=min;
  //fprintf(stderr,"next_in_leaf:[%lu,%lu]:min=%lu-->number=%lu\n",node_num,max,min,number);
  for (;number<=max;++number)
    if(is_num_bit(number-node_num,(char*)NODE(tree,node),IN)) {
      //fprintf(stdout,"next_in_leaf:[%lu,%lu]:min=%lu>>>>number=%lu\n",node_num,max,min,number);
      return number;
    }
  //fprintf(stderr,"!next_in_leaf:[%lu,%lu]:min=%lu-->number=%lu\n",node_num,max,min,number);
  return 0;
}

/*
 * Find next element bigger than min
 *
 */
NUM next_min(RL_Tree *tree,NUM node,NUM node_num,NUM interval,NUM max,NUM min) {
  NUM next_node;
  short quadrant;
  NUM interval2;
  NUM node_num2;
  NUM quadrant_max;
  short status;
  
  if ( min > tree->range_max ) return 0;
  if ( IS_LEAF(interval) )
    return next_in_leaf(tree,node,node_num,MIN(max,tree->range_max),min);
   
  interval2=NEXT_INTERVAL(interval);
  //
  for(quadrant=1;quadrant<=BRANCH_FACTOR;++quadrant){
    NUM found;
    node_num2=node_num+(quadrant-1)*interval2;
    quadrant_max=QUADRANT_MAX_VALUE(node_num,quadrant,interval2,max);
    //------------------------------------------
    status=quadrant_status(NODE(tree,node),quadrant);
    switch(status) {
    case R_PARCIALLY_IN_INTERVAL:
      next_node=get_quadrant_node(tree,node,quadrant,interval);
      found=next_min(tree,next_node,node_num2,interval2,quadrant_max,min);
      if ( found>0) return found;
      break;
    case R_TOTALLY_IN_INTERVAL:
      if (min<=quadrant_max && min>=node_num2)
	return min;
      if ( min < node_num2 ) return node_num2;
    }
    
  }
  return 0;
}

/* *******************************************************************************************************/
/*
 * 
 */
void intersect_leafs(char *storage1,char *storage2) {
  
  BITMAP_difference(*storage1,*storage1,*storage2);
  storage1++;  storage2++;
  BITMAP_difference(*storage1,*storage1,*storage2);
}
/*
 * Removes the elements in tree1 that are in tree2
 *
 */
/*NUM tree_minus(RL_Tree *tree1,RL_Tree *tree2,NUM node1,NUM node2,NUM node_num,NUM interval,NUM max) {
  NUM next_node1,next_node2;
  short quadrant;
  NUM interval2;
  NUM node_num2;
  NUM quadrant_max;
  short status1,status2;
  
  
  if ( IS_LEAF(interval) ) //
    return intersect_leafs((char*)NODE(tree1,node1),(char*)NODE(tree2,node2));
   
  interval2=NEXT_INTERVAL(interval);
  //
  for(quadrant=1;quadrant<=BRANCH_FACTOR;++quadrant){
    node_num2=node_num+(quadrant-1)*interval2;
    quadrant_max=QUADRANT_MAX_VALUE(node_num,quadrant,interval2,max);
    //------------------------------------------
    status1=quadrant_status(NODE(tree1,node1),quadrant);
    status2=quadrant_status(NODE(tree2,node2),quadrant);
    if (status2==R_IGNORE || status2==R_NOT_IN_INTERVAL) {
      // do nothing
    } else if ( status2==R_TOTALLY_IN_INTERVAL && (status1==R_IGNORE || status1==R_NOT_IN_INTERVAL )) {
      // do nothing
    } else if ( status2==R_TOTALLY_IN_INTERVAL && status1==R_TOTALLY_IN_INTERVAL ) {
      //  delete entire quadrant subtree in tree1
    } else if ( status2==R_PARTIALLY_IN_INTERVAL && status1==R_PARTIALLY_IN_INTERVAL){
      // call same function
      next_node1=get_quadrant_node(tree1,node1,quadrant,interval);
      next_node2=get_quadrant_node(tree1,node2,quadrant,interval);
      tree_minus(tree1,tree2,next_node1,next_node2,node_num2,interval2,quadrant_max);
    } else if ( status2==R_PARTIALLY_IN_INTERVAL && status1==R_TOTALLY_IN_INTERVAL) {
      // foreach element of tree2, remove it in tree1
      
    } else {
      // this should never happen!!!!
    }
    switch(status) {
    case R_PARCIALLY_IN_INTERVAL:
      next_node=get_quadrant_node(tree,node,quadrant,interval);
      found=next_min(tree,next_node,node_num2,interval2,quadrant_max,min);
      if ( found>0) return found;
      break;
    case R_TOTALLY_IN_INTERVAL:
      if (min<=quadrant_max && min>=node_num2)
	return min;
      if ( min < node_num2 ) return node_num2;
    }
    
  }
  return 0;
}*/
/* *************************************************************************************************** */
// root level
static NUM norm_tree_size(NUM interval){
  NUM tmp;
  NUM j=BRANCH_FACTOR;;

  if ( interval<= LEAF_SIZE*BRANCH_FACTOR) return LEAF_SIZE;
  while(1) {
    tmp=LEAF_SIZE*j;
    if ( tmp * BRANCH_FACTOR >= interval )break;
    j*=BRANCH_FACTOR;;
  }
  return tmp;
}
//
static void root_intervals(RL_Tree* tree) {
   NUM first_i;

  first_i=norm_tree_size(tree->range_max);
  //k=tree->range_max/first_i+1; // number of large intervals
  
  tree->root_i=first_i;

  if (   tree->root_i*BRANCH_FACTOR < tree->range_max ) {
    tree->root_i=tree->root_i*BRANCH_FACTOR;
    //printf("%lu---->>%lu\n",tree->range_max,tree->root_i);
  }
}


