// file: itri_create_0.cc
//
// isip include files
//
#include "init_triphones.h"
#include "init_triphones_constants.h"
#include <string.h>

// method: create_triphones_cc
//
// arguments:
//  FILE* fp_in : (input) data file name
//  FILE* fp_model_a : (input) output model file
//  FILE* fp_state_a : (input) output state file
//  Hash_table* models : (input) context independent models
//  Hash_table* ci_table : (input) context independent model hash table
//  Hash_table* trans_map : (input) map of transition index and ci model name
//  int_4 num_ci : (input) number of contect independent models
//  int_4& new_num_states : (output) number of states in the context dependent
//                                   models
//  int_4& new_num_models : (output) number of physical context dependent
//                                   models
//
// return: a logical_1 indicating status
//
logical_1 create_triphones_cc(FILE* fp_in_a, FILE* fp_model_a,
			      FILE* fp_state_a, Train_Hash_table* models_a,
			      Train_Hash_table* ci_table_a,
			      Train_Hash_table* trans_map_a,
			      int_4 num_ci_a, int_4& new_num_states_a,
			      int_4& new_num_models_a) {

  // local variables
  //
  logical_1* done = new logical_1[ITRI_MAX_NUM_MODELS];
  for (int_4 i= 0; i < ITRI_MAX_NUM_MODELS; i++) {
    done[i] = ISIP_FALSE;
  }
  
  char_1* line = new char_1[ISIP_MAX_STRING_LENGTH];
  char_1* log_model = new char_1[ISIP_MAX_STRING_LENGTH];
  char_1** phy_model = new char_1*[ITRI_MAX_NUM_MODELS];
  memset((void*)phy_model, 0, ITRI_MAX_NUM_MODELS * sizeof(char_1*));
  char_1* ci_model = new char_1[ITRI_MAX_NUM_MODELS];
  char_1* temp_buf = (char_1*)NULL;
  Train_Hash_cell* hcell = (Train_Hash_cell*)NULL;
  Train_Model* temp_model = (Train_Model*)NULL;
  int_4 curr_num_states = 1;
  int_4 num_states = 0;
  int_4 trans_index = 0;
  int_4 phy_model_index = 0;
  int_4 feature_dim = 0;
  Train_State** states = (Train_State**)NULL;
  int_4* mono_state_indices = (int_4*)NULL;
  int_4* prev_state_indices = (int_4*)NULL;
  int_4 tri_state_index = (int_4)0;
  int_4 prev_num_states = (int_4)0;
  logical_1 tied_flag = ISIP_FALSE;

  // initialize number of states to account for the dummy 0'th state 
  //
  new_num_states_a = 1;
  new_num_models_a = 0;
  
  // read the cluster list
  //
  while (fscanf(fp_in_a, "%[^\n]", line) != EOF) {

    temp_buf = (char_1*)strtok((char*)line, (char*)" ");
    strcpy((char*)log_model, (char*)temp_buf);
    temp_buf = (char_1*)strtok((char*)NULL, (char*)"\n");
    
    // if physical and logical models specified
    //
    if ((char*)temp_buf != (char*)NULL) {
      phy_model[new_num_models_a] = new char_1[strlen((char*)temp_buf) + 1];
      strcpy((char*)phy_model[new_num_models_a], (char*)temp_buf);
    }

    //  if only physical model specified
    //
    else {
      phy_model[new_num_models_a] = new char_1[strlen((char*)log_model) + 1];
      strcpy((char*)phy_model[new_num_models_a], (char*)log_model);
    }
    
    phy_model_index = get_cimodel_cc(phy_model[new_num_models_a],
				     ci_table_a, num_ci_a, ci_model);
    
    // write into models file only if it is a physical model
    // (make sure it has not been written previously)
    //
    if (done[phy_model_index] == ISIP_FALSE) {

      // accumulate the number of new states for the triphones
      //
      hcell = models_a->hash_lookup_cc(ci_model);
      temp_model = (Train_Model*)hcell->get_item_cc();
      new_num_states_a += temp_model->get_num_states_cc() - 2;
      states = temp_model->get_states_cc();
      feature_dim = states[1]->get_num_features_cc();
      done[phy_model_index] = ISIP_TRUE;
      new_num_models_a++;      
    }

    else {
      delete [] phy_model[new_num_models_a];
      phy_model[new_num_models_a] = (char_1*)NULL;
    }
    fscanf(fp_in_a, "\n");      
  }

  // print model info into the models file
  //
  fprintf(fp_model_a, "num_models = %ld\n\n", new_num_models_a);

  // print the initial state information
  //
  fwrite((void*)&feature_dim, sizeof(int_4), 1, fp_state_a);
  fwrite((void*)&new_num_states_a, sizeof(int_4), 1, fp_state_a);

  // handle the dummy 0'th state
  //
  Train_State* temp_state = new Train_State;
  temp_state->set_num_mixtures_cc(0);
  print_state_cc(fp_state_a, temp_state);
  delete temp_state;
		      
  // print the non-dummy models
  //
  for (int_4 i = 0; i < new_num_models_a; i++) {

    phy_model_index = get_cimodel_cc(phy_model[i], ci_table_a,
				     num_ci_a, ci_model);
    hcell = trans_map_a->hash_lookup_cc(ci_model);
    trans_index = (int_4)hcell->get_item_cc();
    fprintf(fp_model_a, "index:  %ld\n", i);
    fprintf(fp_model_a, "phone:  %s\n", phy_model[i]);
    hcell = models_a->hash_lookup_cc(ci_model);
    temp_model = (Train_Model*)hcell->get_item_cc();    
    num_states = temp_model->get_num_states_cc();
    states = temp_model->get_states_cc();
    fprintf(fp_model_a, "num_states:  %ld\n", num_states);
    hcell = trans_map_a->hash_lookup_cc(ci_model);
    trans_index = (int_4)hcell->get_item_cc();
    fprintf(fp_model_a, "transitions:  %ld\n", trans_index);
    fprintf(fp_model_a, "states: 0");    

    // check if sp and sil in monophones list are tied 
    // tie sp and sil in triphones list if tied in monophones list
    //
    if ((strcmp((char*)phy_model[i], ITRI_SP_PHONE) == 0) ||
	(strcmp((char*)phy_model[i], ITRI_SIL_PHONE) == 0)) {

      // save the state index information of sp or sil whichever occurs first
      //
      if (mono_state_indices == (int_4*)NULL) {

	mono_state_indices = new int_4[num_states-2];
	memset((int_4*)mono_state_indices, 0, (num_states-2) * sizeof(int_4));
	prev_state_indices = new int_4[num_states-2];
	memset((int_4*)prev_state_indices, 0, (num_states-2) * sizeof(int_4));

	for (int_4 k = 1; k < num_states-1; k++) {
	  mono_state_indices[k-1] = states[k]->get_state_index_cc();
	  tri_state_index = curr_num_states;
	  prev_state_indices[k-1] = tri_state_index++;
	  prev_num_states = num_states;

	  // print sp or sil whichever occures first in triphone list file
	  //
	  fprintf(fp_model_a, " %ld", prev_state_indices[k-1]);
	  
	  // print state information to the states file
	  //
	  print_state_cc(fp_state_a, states[k]);
	  
	  // increment state count
	  //
	  curr_num_states++;  
	}
      }
      
      else {
	
	for (int_4 l = 1; l < num_states-1; l++) {
	  for(int_4 m = 1; m < prev_num_states-1; m++) {

	    // check if any state(s) of sp or sil are tied
	    //
	    if (states[l]->get_state_index_cc() == mono_state_indices[m-1]) {
	      
	      fprintf(fp_model_a, " %ld", prev_state_indices[m-1]);
	      
	      // print state information to the states file for tied states
	      //
	      print_state_cc(fp_state_a, states[l]);
	      tied_flag = ISIP_TRUE;

	      // increment state count
	      //
	      curr_num_states++;  
	    }
	  }  
 
	  if (tied_flag == ISIP_FALSE) {
	    fprintf(fp_model_a, " %ld", curr_num_states);
	    
	    // print state information to the states file for untied states
	    //
	    print_state_cc(fp_state_a, states[l]);
	    
	    // increment state count
	    //
	    curr_num_states++;
	  }	    

	  tied_flag = ISIP_FALSE;
	  
	  if(l == num_states-1) {

	    // clean up memory
	    //
	    delete [] mono_state_indices;
	    delete [] prev_state_indices;
	  }
	}
      }
    }

    // print all triphones other than sp and sil
    //
    else {
      for (int_4 j = 1; j < num_states-1; j++) {
	
	fprintf(fp_model_a, " %ld", curr_num_states);
	
	// print state information to the states file
	//
	print_state_cc(fp_state_a, states[j]);
	
	// increment state count
	//
	curr_num_states++;
      }
    }
      fprintf(fp_model_a, " 0\n\n");
  }
  
  // cleanup memory
  //
  delete [] mono_state_indices;
  delete [] prev_state_indices;
  delete [] log_model;
  delete [] ci_model;
  delete [] line;
  delete [] done;

  for (int_4 i = 0; i < ITRI_MAX_NUM_MODELS; i++) {
    if (phy_model[i] != (char_1*)NULL) {
      delete [] phy_model[i];
    }
  }
  delete [] phy_model;
  
  // exit gracefully
  //
  return ISIP_TRUE;
}
