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

/* rdhmmdef_state.c --- read in hmmdefs (state) */

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

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

extern char *rdhmmdef_token;	/* defined in rdhmmdef.c */

/* malloc new */
static HTK_HMM_State *
state_new()
{
  HTK_HMM_State *new;

  new = (HTK_HMM_State *)mybmalloc(sizeof(HTK_HMM_State));

  new->name = NULL;
  new->mix_num = 0;
  new->b = NULL;
  new->bweight = NULL;
  new->id = 0;
  new->next = NULL;

  return(new);
}

/* register */
static void
state_add(HTK_HMM_INFO *hmm, HTK_HMM_State *new)
{
  HTK_HMM_State *match;

  /* link data structure */
  new->next = hmm->ststart;
  hmm->ststart = new;

  if (new->name != NULL) {
    /* add index to search index tree */
    if (hmm->st_root == NULL) {
      hmm->st_root = aptree_make_root_node(new);
    } else {
      match = aptree_search_data(new->name, hmm->st_root);
      if (strmatch(match->name, new->name)) {
	j_printerr("Error: ~s \"%s\" is already defined\n", new->name);
	rderr(NULL);
      } else {
	aptree_add_entry(new->name, new, match->name, &(hmm->st_root));
      }
    }
  }
  
}

/* lookup by name */
HTK_HMM_State *
state_lookup(HTK_HMM_INFO *hmm, char *keyname)
{
  HTK_HMM_State *s;

  s = aptree_search_data(keyname, hmm->st_root);
  if (strmatch(s->name, keyname)) {
    return s;
  } else {
    return NULL;
  }
}

/* read in state data and return new (malloced) HTK_HMM_State */
static HTK_HMM_State *
state_read(FILE *fp, HTK_HMM_INFO *hmm)
{
  HTK_HMM_State *new;
  int mid;
  int i;
  boolean single_gaussian;

  new = state_new();

  if (currentis("NUMMIXES")) {
    read_token(fp);
    NoTokErr("missing NUMMIXES value");
    new->mix_num = atoi(rdhmmdef_token);
    read_token(fp);
    single_gaussian = FALSE;
  } else {
    new->mix_num = 1;
    single_gaussian = TRUE;
  }

  if (currentis("TMIX")) {
    read_token(fp);
    /* read in TMIX */
    tmix_read(fp, new, hmm);
  } else {
    
    new->b = (HTK_HMM_Dens **) mybmalloc(sizeof(HTK_HMM_Dens *) * new->mix_num);
    new->bweight = (PROB *) mybmalloc(sizeof(PROB) * new->mix_num);
    for (i=0;i<new->mix_num;i++) {
      new->b[i] = NULL;
      new->bweight[i] = LOG_ZERO;
    }

    if (single_gaussian) {
      mid = 0;
      new->bweight[mid] = 0.0;
      new->b[mid] = get_dens_data(fp, hmm);
    } else {
      for (;;) {
	if (!currentis("MIXTURE")) break;
	read_token(fp);
	NoTokErr("missing MIXTURE id");
	mid = atoi(rdhmmdef_token) - 1;
	read_token(fp);
	NoTokErr("missing MIXTURE weight");
	new->bweight[mid] = log(atof(rdhmmdef_token));
	read_token(fp);
	new->b[mid] = get_dens_data(fp, hmm);
      }
    }
  }

#if 0
  /* diabled */
  for (i=0;i<new->mix_num;i++) {
    /* make error if no mixture was associated */
    if (new->b[i] == NULL) {
      j_printerr("Warning: lack of mixture component found, use previous insted...\n");
      new->b[i] = new->b[i-1];
    }
  }
#endif
  
  
  return (new);
}

/* read in state data at the current point, and
   return pointer to the data */
HTK_HMM_State *
get_state_data(FILE *fp, HTK_HMM_INFO *hmm)
{
  HTK_HMM_State *tmp;

  if (currentis("NUMMIXES")||currentis("MEAN")||currentis("RCLASS")) {
    /* definition: define state data, and return the pointer */
    tmp = state_read(fp, hmm);
    tmp->name = NULL; /* no name */
    state_add(hmm, tmp);
    return tmp;
  } else if (currentis("~s")) {
    /* macro reference: lookup and return the pointer */
    read_token(fp);
    NoTokErr("missing state macro name");
    tmp = state_lookup(hmm, rdhmmdef_token);
    if (tmp == NULL) {
      j_printerr("Error: ~s \"%s\" not defined\n", rdhmmdef_token);
      rderr(NULL);
    }
    read_token(fp);
    return tmp;
  } else {
    rderr("no state data");
    return NULL;
  }
}



/* define state data */
void
def_state_macro(char *name, FILE *fp, HTK_HMM_INFO *hmm)
{
  HTK_HMM_State *new;

  /* read in data and return newly malloced data */ 
  new = state_read(fp, hmm);
 
  /* register it to the grobal HMM structure */
  new->name = name;
  state_add(hmm, new);
}
