// file: ts_model_1.cc
//

// system include files
//
#include <string.h>

// isip include files
//
#include "tie_state.h"
#include "tie_state_constants.h"

// method: set_models_cc
//
// arguments:
//   FILE* fp_phlist     : (input)  file pointer to phone list file
//   char_1** mono       : (input)  monophone list
//   int_4 num_mono      : (input)  number of monophones
//   int_4& num_cd_models : (output) number of Cd_models
//   Cd_model** cd_models: (output) a set of cd_models
//   Decision_trees** trees:  (input) pointers to all decision trees
//   char_1** special_ph   :  (input) special phone list
//   int_4 ph_size         :  (input) phone size
//   int_4 num_states      :  (input) number of states in common Cd_models
//   int_4 num_special_model : (input)  number of special models
//   char_1** special_models : (input) phones name in special models
//   Hash_table* answers   :  (input) answers to questions in decision trees
//
// return: a logical_1 showing status
//
// this method finds the position of each state of triphone models in
// the corresponding decision trees, according to the model and the state
// position in the model
//
logical_1 pool_phones_cc(FILE* fp_phlist_a, char_1** mono_a, int_4 num_mono_a,
			 int_4& num_cd_models_a, Cd_model**& cd_models_a,
			 Decision_tree** trees_a, char_1** special_ph_a,
			 int_4 ph_size_a, int_4 num_states_a,
			 int_4 num_special_model_a, char_1** special_models_a,
			 Hash_table* answers_a) {
  
  // variables to read data
  //
  char_1* tmp = new char_1[ISIP_MAX_STRING_LENGTH];
  char_1* temp_str = (char_1*)NULL;

  // the num_cd_models_a is from pool_states, in test node, it gives the
  // number of special models
  //
  Cd_model** spe_cd_models = new Cd_model*[num_cd_models_a];
  int_4 num_spe_cd_models = num_cd_models_a;

  // tag testing if it's special model
  //
  logical_1 tag_special_model = ISIP_FALSE;

  for(int i = 0;i < num_spe_cd_models; i++) {
    spe_cd_models[i] = new Cd_model(*cd_models_a[i]);
    delete cd_models_a[i];
  }
  delete [] cd_models_a;
  
  int_4 st_pos;
  int_4 tree_index;
  int_4 state_index;
  logical_1 result;
  logical_1 leaf_flag;
  Dt_node* curr_dt_node;
  
  int_4 i;
  int_4 j;
  
  char_1* lph ; 
  char_1* cph ; 
  char_1* rph ;  
  int_4 n_lph = 0;
  int_4 n_cph = 0;
  int_4 n_rph = 0;
  char_1** phn = new char_1*[ph_size_a];
  
  // read data from file
  //
  while (fscanf(fp_phlist_a, "%s", tmp) != EOF) {

    // ignore comment lines
    //
    if (tmp[0] == (char_1)'#') {
      
      // do nothing
      //
      fscanf(fp_phlist_a, "%[^\n]", tmp);
      fscanf(fp_phlist_a, "%[\n]", tmp);
    }
    
    // read the model data
    //
    else if (strcmp((char*)tmp, "num_phones") == 0) {
      
      // read the number of models and allocate memory for number of states
      //
      fscanf(fp_phlist_a, "%s%ld", tmp, &num_cd_models_a);
      num_cd_models_a += num_spe_cd_models;
      cd_models_a = new Cd_model*[num_cd_models_a];      
      
      // allocate memory for special models
      //
      for(j = 0; j < num_spe_cd_models;j++) {
	cd_models_a[j] = new Cd_model(*spe_cd_models[j]);
	delete  spe_cd_models[j];
	cd_models_a[j]->set_yesphy_cc(ISIP_FALSE);
      }

      delete [] spe_cd_models;
            
      for(i = num_spe_cd_models;i<num_cd_models_a;i++) {
       	cd_models_a[i] = new Cd_model(num_states_a);
        cd_models_a[i]->set_yesphy_cc(ISIP_TRUE);
      }
  
      // now read the model data
      //
      for (int_4 i = num_spe_cd_models; i < num_cd_models_a; i++) {
	
	// read the model index, phone name, number of states
	//
	fscanf(fp_phlist_a, "%s", tmp);
	
	// if it's a special phone, ignore it
	//
	for(int k = 0; k < num_special_model_a; k++) {
	  if(strcmp((char*)tmp, (char*)special_models_a[k]) == 0) {
	    tag_special_model = ISIP_TRUE;
	    break;
	  }
	}

	if (tag_special_model == ISIP_TRUE) {
	  tag_special_model = ISIP_FALSE;
	  i--;
	  delete cd_models_a[num_cd_models_a-1];
	  num_cd_models_a--;		  
	  
	  for(int k=0;k<num_spe_cd_models;k++) {
	    
	    char_1** phones = cd_models_a[k]->get_phones_cc();
	    if(strcmp((char*)tmp,(char*)phones[1]) == 0) {
	      cd_models_a[k]->set_yesphy_cc(ISIP_TRUE);
	    }
	  }
	  continue;
	}

	// check if the left context exist
	//
	temp_str = (char_1*)strstr((char*)tmp, "-");
	
	// if not
	//
	if(temp_str == (char_1*)NULL) {
	  lph = (char_1*)NULL;
	  
	  // check if right context exist
	  //
	  temp_str = (char_1*)strstr((char*)tmp, "+");
	  if(temp_str == (char_1*)NULL) {
	    cph = tmp ;
	    rph = (char_1*)NULL;
	  }
	  else {
	    cph = (char_1*)strtok((char*)tmp, "+");
	    rph = (char_1*)strtok((char*)NULL, ISIP_STRING_SPACE);
	  } 
	}
	
	// if left context exist
	//
	else {
	  
	  // check if right context exist
	  //
	  temp_str = (char_1*)strstr((char*)tmp, "+");
	  lph = (char_1*)strtok((char*)tmp, "-");
	  
	  if(temp_str == (char_1*)NULL) {
	    cph = (char_1*)strtok((char*)NULL, ISIP_STRING_SPACE);
	    rph = (char_1*)NULL;
	  }
	  else {
	    cph = (char_1*)strtok((char*)NULL, "+");
	    rph = (char_1*)strtok((char*)NULL, ISIP_STRING_SPACE);
	  } 
	}
	
	// get the left context index
	//
	if(lph!=(char_1*)NULL) {
	  for(j=0; j<num_mono_a; j++) {
	    if(strcmp((char*)lph, (char*)mono_a[j])==0) {
	      n_lph = j;
	      break;
	    }
	  }
	}
	else {
	  n_lph = TS_EMPTY_PHN;
	}
	
	// get the central phone index
	//
	if(cph!=(char_1*)NULL) {
	  
	  for(j=0;j<num_mono_a;j++) {  
	    if(strcmp((char*)cph, (char*)mono_a[j])==0) {
	      n_cph = j;
	      break;
	    }
	  }
	}
	else {
	  n_cph = TS_EMPTY_PHN;
	}
	
	// get the right context index
	//
	if(rph!=(char_1*)NULL) {
	  
	  for(j=0; j<num_mono_a; j++) {	    
	    if(strcmp((char*)rph, (char*)mono_a[j])==0) {
	      n_rph = j;
	      break;
	    }
	  }
	}
	else {
	  n_rph = TS_EMPTY_PHN;
	}

	phn[0] = lph;
	phn[1] = cph;
	phn[2] = rph;
	cd_models_a[i] ->set_phones_cc(phn);
	
	// loop the states of the current phone
	//
	for(st_pos = 1; st_pos<4; st_pos++) {
	  tree_index = map_tr_index_cc(n_cph, num_special_model_a, st_pos);
	  curr_dt_node = trees_a[tree_index]->get_root_cc();
	  leaf_flag = curr_dt_node->get_leaf_flag_cc();

	  if(leaf_flag == ISIP_TRUE) {
	    state_index = curr_dt_node->get_label_cc();
	    cd_models_a[i] ->set_state_ind_cc(state_index, st_pos);
	  }
	  else {
	    while(leaf_flag != ISIP_TRUE) {
	      result = curr_dt_node->ask_opt_question_cc(answers_a,
							 n_lph, n_rph);
	      if(result == ISIP_TRUE) {
		curr_dt_node = curr_dt_node->get_l_child_cc();
	      }
	      else {
		curr_dt_node = curr_dt_node->get_r_child_cc();
	      }
	      leaf_flag = curr_dt_node->get_leaf_flag_cc();
	    }
	    state_index = curr_dt_node->get_label_cc();
	    cd_models_a[i] ->set_state_ind_cc(state_index, st_pos);
	  }
	}
	
      } // end looping the phone list
    }
  }

  // free memory
  //
  delete [] phn;
  delete [] tmp;
  
  // exist gracefully
  //
  return ISIP_TRUE;
  
}

