/* Copyright (c) 1991-2002 Doshita Lab. Speech Group, Kyoto University */
/* Copyright (c) 2000-2002 Speech and Acoustics Processing Lab., NAIST */
/*   All rights reserved   */

/* aptree.c --- patricia tree functions for data index */
/*              data type: pointer */

/* $Id: aptree.c,v 1.4 2002/09/11 22:01:50 ri Exp $ */

#include <sent/stddefs.h>
#include <sent/ptree.h>

/* malloc and return a new node */
static APATNODE *
new_node()
{
  APATNODE *tmp;

  tmp = (APATNODE *)mymalloc(sizeof(APATNODE));
  tmp->left0 = NULL;
  tmp->right1 = NULL;

  return(tmp);
}

/* do search and return data (internal recursive) */
static void *
aptree_search_data_r(char *str, APATNODE *node)
{
  if (node->left0 == NULL && node->right1 == NULL) {
    return(node->value.data);
  } else {
    if (testbit(str, node->value.thres_bit) != 0) {
      return(aptree_search_data_r(str, node->right1));
    } else {
      return(aptree_search_data_r(str, node->left0));
    }
  }
}

/* do search and return data */
void *
aptree_search_data(char *str, APATNODE *node)
{
  if (node == NULL) {
    j_error("Error: aptree_search_data: no node, search for \"%s\" failed\n", str);
  }
  return(aptree_search_data_r(str, node));
}


/*******************************************************************/
/* add 1 node to given ptree */

/* first time when root node does not exist... */
APATNODE *
aptree_make_root_node(void *data)
{
  APATNODE *nnew;
  /* make new leaf node for newstr */
  nnew = new_node();
  nnew->value.data = data;
  return(nnew);
}

/* add node to the point */
static void
aptree_add_entry_at(char *str, int bitloc, void *data, APATNODE **parentlink)
{
  APATNODE *node;
  node = *parentlink;
  if (node->value.thres_bit > bitloc ||
      (node->left0 == NULL && node->right1 == NULL)) {
    APATNODE *newleaf, *newbranch;
    /* insert between [parent] and [node] */
    newleaf = new_node();
    newleaf->value.data = data;
    newbranch = new_node();
    newbranch->value.thres_bit = bitloc;
    *parentlink = newbranch;
    if (testbit(str, bitloc) ==0) {
      newbranch->left0  = newleaf;
      newbranch->right1 = node;
    } else {
      newbranch->left0  = node;
      newbranch->right1 = newleaf;
    }
    return;
  } else {
    if (testbit(str, node->value.thres_bit) != 0) {
      aptree_add_entry_at(str, bitloc, data, &(node->right1));
    } else {
      aptree_add_entry_at(str, bitloc, data, &(node->left0));
    }
  }
}

/* top routine to add entry */
void
aptree_add_entry(char *str, void *data, char *matchstr, APATNODE **rootnode)
{
  int bitloc;

  bitloc = where_the_bit_differ(str, matchstr);
  if (*rootnode == NULL) {
    *rootnode = aptree_make_root_node(data);
  } else {
    aptree_add_entry_at(str, bitloc, data, rootnode);
  }

}

/* sequencial access to all data:
   traverse tree and do callback() for each data */
void
aptree_traverse_and_do(APATNODE *node, void (*callback)(void *))
{
  if (node->left0 == NULL && node->right1 == NULL) {
    (*callback)(node->value.data);
  } else {
    if (node->left0 != NULL) {
      aptree_traverse_and_do(node->left0, callback);
    }
    if (node->right1 != NULL) {
      aptree_traverse_and_do(node->right1, callback);
    }
  }
}

/*** free all the sub nodes from specified node ****/
void
free_aptree(APATNODE *node)
{
  if (node->left0 != NULL) free_aptree(node->left0);
  if (node->right1 != NULL) free_aptree(node->right1);
  free(node);
}
