// file: init_triphones.cc
//
// this program creates an initial set of triphones based on a clustered
// phone list
//

// isip include files
//
#include "init_triphones.h"
#include "init_triphones_constants.h"

// main program
//
int main(int_4 argc, char_1** argv) {

  // local variables
  //
  int_4 num_states;
  int_4 new_num_states = 0;
  int_4 num_models;
  int_4 new_num_models = 0;
  int_4 num_features;
  int_4 num_trans;
  int_4 num_ciphones = 0;
  
  // variables to hold commandline parameters
  //
  char_1* params_file = new char_1[ISIP_MAX_STRING_LENGTH];
  char_1* in_models_file = new char_1[ISIP_MAX_STRING_LENGTH];
  char_1* out_models_file = new char_1[ISIP_MAX_STRING_LENGTH];
  char_1* in_trans_file = new char_1[ISIP_MAX_STRING_LENGTH];
  char_1* out_trans_file = new char_1[ISIP_MAX_STRING_LENGTH];
  char_1* in_states_file = new char_1[ISIP_MAX_STRING_LENGTH];
  char_1* out_states_file = new char_1[ISIP_MAX_STRING_LENGTH];
  char_1* tri_clist_file = new char_1[ISIP_MAX_STRING_LENGTH];
  char_1* ciphones_file = new char_1[ISIP_MAX_STRING_LENGTH];
  
  // read the command line arguments
  //
  read_cmdline_cc(argc, argv, params_file);

  // read parameters
  //
  FILE* fp_in = fopen((char*)params_file, "r");
  read_params_cc(fp_in, in_models_file, out_models_file, in_trans_file,
		 out_trans_file, in_states_file, out_states_file,
		 tri_clist_file, ciphones_file);  
  delete [] params_file;
  fclose(fp_in);
  
  // read the input states file
  //
  fp_in = fopen((char*)in_states_file, "rb");
  if (fp_in == (FILE*)NULL) {
    fprintf(stdout, "Error : cannot open input file %s\n", in_states_file);
    exit(ISIP_PROTO_ERROR);
  }

  // read the context-independent state file
  //
  Train_State** states = read_states_cc(fp_in, num_states, num_features);
  delete [] in_states_file;
  fclose(fp_in);

  // read the input transitions file
  //
  fp_in = fopen((char*)in_trans_file, "r");
  if (fp_in == (FILE*)NULL) {
    fprintf(stdout, "Error : cannot open input file %s\n", in_trans_file);
    exit(ISIP_PROTO_ERROR);
  }

  // read the transitions data
  //
  int_4* trans_size = (int_4*)NULL;
  float_4*** transitions = read_trans_cc(fp_in, num_trans, trans_size);
  delete [] in_trans_file;
  fclose(fp_in);
  
  // read the input transitions file
  //
  fp_in = fopen((char*)in_models_file, "r");
  if (fp_in == (FILE*)NULL) {
    fprintf(stdout, "Error : cannot open input file %s\n", in_models_file);
    exit(ISIP_PROTO_ERROR);
  }

  // create a memory manager 
  //
  Train_Memory_manager* manager = new Train_Memory_manager(ITRI_MAX_NUM_MODELS,
							   ITRI_MAX_NUM_MODELS);
  Train_Link_list::set_manager_cc(manager);
  
  // read the base context independent HMM models
  //
  Train_Hash_table* trans_map = (Train_Hash_table*)NULL;
  Train_Hash_table* models = read_models_cc(fp_in, states, transitions, trans_map,
				      num_models);
  delete [] in_models_file;
  fclose(fp_in);

  // open the original phones file
  //
  fp_in = fopen((char*)ciphones_file, "r");
  if (fp_in == (FILE*)NULL) {
    fprintf(stdout, "Error : cannot open input file %s\n", ciphones_file);
    exit(ISIP_PROTO_ERROR);
  }
  delete [] ciphones_file;
  
  // read the ciphones and their indices
  //
  Train_Hash_table* ci_models = read_cimodels_cc(fp_in, num_ciphones);

  // open the clustered triphones list
  //
  fp_in = fopen((char*)tri_clist_file, "r");
  if (fp_in == (FILE*)NULL) {
    fprintf(stdout, "Error : cannot open input file %s\n", tri_clist_file);
    exit(ISIP_PROTO_ERROR);
  }
  delete [] tri_clist_file;

  // open the output models file
  //
  FILE* fp_model_out = fopen((char*)out_models_file, "w");
  if (fp_in == (FILE*)NULL) {
    fprintf(stdout, "Error : cannot open input file %s\n", out_models_file);
    exit(ISIP_PROTO_ERROR);
  }
  delete [] out_models_file;

  // open the output states file (binary output)
  //
  FILE* fp_state_out = fopen((char*)out_states_file, "wb");
  if (fp_state_out == (FILE*)NULL) {
    fprintf(stdout, "Error : cannot open input file %s\n", out_states_file);
    exit(ISIP_PROTO_ERROR);
  }
  delete [] out_states_file;
  
  // read the triphones cluster list (this function will also create the
  // new states and models for all the physical triphones in the cluster list)
  //
  create_triphones_cc(fp_in, fp_model_out, fp_state_out, models,
		      ci_models, trans_map, num_models, new_num_states,
		      new_num_models);
  fclose(fp_in);
  fclose(fp_model_out);
  fclose(fp_state_out);
  
  // clean up memory
  //

  // delete states
  //
  for (int_4 i = 0; i < num_states; i++) {
    delete states[i];
  }  
  delete [] states;
  
  // delete hash table of the ci models
  //
  Train_Model* ph = (Train_Model*)NULL;
  Train_Hash_cell* next = (Train_Hash_cell*)NULL;
  Train_Hash_cell** hash_cells = models->get_cells_cc();
  int_4 hash_size = models->get_size_cc();
  for (int_4 k = 0; k < hash_size; k++) {
    for (Train_Hash_cell* cell = hash_cells[k]; cell != (Train_Hash_cell*)NULL;
	 cell = next) {
      next = cell->get_next_cc();
      ph = (Train_Model*)(cell->get_item_cc());
      delete ph;
      manager->delete_cc(cell);
    }
    hash_cells[k] = (Train_Hash_cell*)NULL;
  }
  delete models;

  // delete hash table of the ci models
  //
  ph = (Train_Model*)NULL;
  next = (Train_Hash_cell*)NULL;
  hash_cells = ci_models->get_cells_cc();
  hash_size = ci_models->get_size_cc();
  for (int_4 k = 0; k < hash_size; k++) {
    for (Train_Hash_cell* cell = hash_cells[k]; cell != (Train_Hash_cell*)NULL;
	 cell = next) {
      next = cell->get_next_cc();
      manager->delete_cc(cell);
    }
    hash_cells[k] = (Train_Hash_cell*)NULL;
  }
  delete ci_models;

  // delete hash table of transitions
  //
  next = (Train_Hash_cell*)NULL;
  hash_cells = trans_map->get_cells_cc();
  hash_size = trans_map->get_size_cc();
  for (int_4 k = 0; k < hash_size; k++) {
    for (Train_Hash_cell* cell = hash_cells[k]; cell != (Train_Hash_cell*)NULL;
	 cell = next) {
      next = cell->get_next_cc();
      manager->delete_cc(cell);
    }
    hash_cells[k] = (Train_Hash_cell*)NULL;
  }
  delete trans_map;

  // delete transitions
  //
  for (int_4 i = 0; i < num_trans; i++) {
    for (int_4 j = 0; j < trans_size[i]; j++) {
      delete [] transitions[i][j];
    }
    delete [] transitions[i];
  }
  delete [] transitions;
  delete [] trans_size;
  // clean up
  //
  delete [] out_trans_file;
  delete manager;
  // exit gracefully
  //
  exit(ISIP_NO_ERROR);
}

