// file: tp_comp_0.cc
//

// isip include files
//
#include "trace_projector.h"
#include "trace_projector_constants.h"
#include <time.h>

// method: compute_cc
//
// arguments: none
//
// return: a logical flag to indicate success
//
logical_1 Trace_projector::compute_cc() {

  // if this is lattice error rate mode, only need the lattice and
  // transcription files
  //
  if (function_mode_d == TP_LATTICE_WER_FUNCTION) {

    // read the lattice list file
    //
    if (lattice_file_d == (char_1*)NULL) {
      fprintf(stdout, "Error: input lattice list file not specified\n");
      exit(ISIP_PROTO_ERROR);
    }
    
    // open lattice file list
    //
    FILE* flat = (FILE*)NULL;
    open_file_cc(flat, lattice_file_d, (char_1*)"r");

    // read the utterance list file
    //
    if (forcealign_file_d == (char_1*)NULL) {
      fprintf(stdout, "Error: forced alignment file not specified\n");
      exit(ISIP_PROTO_ERROR);
    }
    
    // open transcription i.e. forced alignment file
    //
    FILE* fref = (FILE*)NULL;
    open_file_cc(fref, forcealign_file_d, (char_1*)"r");
    
    // open the output file
    //
    FILE* fout = (FILE*)NULL;
    open_file_cc(fout, latwer_file_d, (char_1*)"w");

    // compute the lattice wer
    //
    fprintf(stdout, "Computing lattice word error rates...\n");
    decoder_d->lattice_wer_cc(flat, fref, fout);

    // close files
    //
    if (flat != (FILE*)NULL) {
      fclose(flat);
    }
    if (fref != (FILE*)NULL) {
      fclose(fref);
    }
    if (fout != (FILE*)NULL) {
      fclose(fout);
    }
  }

  // otherwise this is decoding mode
  //
  else {
  
    // load acoustic model related data into the decoder and clean
    // related memory
    //
    fprintf(stdout, "Loading acoustic model data...\n");
    load_ac_models_cc();
    
    // if ngram required in the specified function mode, load the ngram
    // language model
    //
    if ((function_mode_d == TP_NGRAM_DECODE_FUNCTION) ||
	(function_mode_d == TP_LATTICE_GENERATE_FUNCTION) ||
	(function_mode_d == TP_LATTICE_VERIFY_FUNCTION)) {
      
      FILE* fp;

      // check if the ngram lm file exists
      //
      if (lm_file_d == (char_1*)NULL) {
	fprintf(stdout, "Error: language model file not specified\n");
	exit(ISIP_PROTO_ERROR);
      }
      open_file_cc(fp, lm_file_d, (char_1*)"r");
      
      // load the ngram
      //
      fprintf(stdout, "Reading language model data...\n");
      decoder_d->read_ngram_cc(fp);

      if (fp != (FILE*)NULL) {
	fclose(fp);
      }

      // check if the list of grammars is specified
      //
      if (gram_list_file_d != (char_1*)NULL) {

	// open file
	//
	open_file_cc(fp, gram_list_file_d, (char_1*)"r");

	// load the grammars for hierarchical grammar processing
	//
	decoder_d->read_gram_list_cc(fp);

	if (fp != (FILE*)NULL) {
	  fclose(fp);
	}
      }
    }

    // set the user specified lm scaling and word insertion values  
    //
    decoder_d->set_lmscale_cc(lm_scale_d);
    decoder_d->set_wdpenalty_cc(word_penalty_d);
    
    // set the acoustic context mode
    //
    decoder_d->set_context_mode_cc(context_mode_d);
    
    // set the pruning related parameters and clean related memory 
    //
    decoder_d->set_beams_cc(beam_width_d);
    decoder_d->set_mapmi_limit_cc(mapmi_limit_d);
    decoder_d->set_max_words_cc(num_wdcut_d);
    
    // set the nbest pruning related parameters
    //
    decoder_d->set_nbest_maxpaths_cc(nbest_max_paths_d);
    decoder_d->set_nbest_beam_cc(nbest_beam_d);

    // initialize the decoder for hypothesizing utterances
    //
    decoder_d->init_cc();

    // file pointers for processing lists of files
    //
    FILE* fpin_list = (FILE*)NULL;
    FILE* fpout_list = (FILE*)NULL;
    FILE* fpli_list = (FILE*)NULL;
    FILE* fplo_list = (FILE*)NULL;
    FILE* fpnbo_list = (FILE*)NULL;
    FILE* fpms_list = (FILE*)NULL;
    
    // open the file containing the list of input mfcc files
    //
    if (input_file_d == (char_1*)NULL) {
      fprintf(stdout, "Error: input mfcc file list not specified\n");
      exit(ISIP_PROTO_ERROR);
    }
    open_file_cc(fpin_list, input_file_d, (char_1*)"r");

    // open the file containing the list of output files
    //
    if (output_file_d == (char_1*)NULL) {
      fprintf(stdout, "Error: output file list not specified\n");
      exit(ISIP_PROTO_ERROR);
    }
    open_file_cc(fpout_list, output_file_d, (char_1*)"r");

    // open the file containing the list of model-level segment files
    //
    if (segment_mode_d == TP_MODEL_SEGMENT_MODE) {
      
      // check if file exists
      //
      if (model_segment_file_d == (char_1*)NULL) {
	fprintf(stdout, "Error: input model-level segment list file not specified\n");
	exit(ISIP_PROTO_ERROR);
      }
      
      // open model-level segment file list
      //
      open_file_cc(fpms_list, model_segment_file_d, (char_1*)"r");
    }
    
    // open the file containing the list of lattice files
    //
    if ((function_mode_d == TP_LATTICE_RESCORE_FUNCTION) ||
	(function_mode_d == TP_LATTICE_LATTICE_FUNCTION) ||
	(function_mode_d == TP_LATTICE_VERIFY_FUNCTION)) {
      
      // check if file exists
      //
      if (lattice_file_d == (char_1*)NULL) {
	fprintf(stdout, "Error: input lattice list file not specified\n");
	exit(ISIP_PROTO_ERROR);
      }
      
      // open lattice file list
      //
      open_file_cc(fpli_list, lattice_file_d, (char_1*)"r");
    }

    // if this is lattice generate mode there is a list of output
    // lattices
    //
    if ((function_mode_d == TP_LATTICE_GENERATE_FUNCTION) ||
	(function_mode_d == TP_LATTICE_LATTICE_FUNCTION)) {
      
      // check if file exists
      //
      if (outlat_file_d == (char_1*)NULL) {
	fprintf(stdout, "Error: output lattice list file not specified\n");
	exit(ISIP_PROTO_ERROR);
      }
      
      // open lattice file
      //
      open_file_cc(fplo_list, outlat_file_d, (char_1*)"r");
    }

    // open the output nbest list file
    //
    if (((function_mode_d == TP_LATTICE_RESCORE_FUNCTION) ||
	 (function_mode_d == TP_NGRAM_DECODE_FUNCTION) ||
	 (function_mode_d == TP_LATTICE_VERIFY_FUNCTION)) &&
	(num_nbest_d > 1)) {
      
      // check if file exists
      //
      if (outnbest_file_d == (char_1*)NULL) {
	fprintf(stdout, "Error: output nbest list file not specified\n");
	exit(ISIP_PROTO_ERROR);
      }
      
      // open lattice file
      //
      open_file_cc(fpnbo_list, outnbest_file_d, (char_1*)"r");
    }
    
    // open the file containing reference transcriptions for forced
    // alignment
    //
    if (function_mode_d == TP_FORCE_ALIGN_FUNCTION) {
      
      // check if file exists
      //
      if (forcealign_file_d == (char_1*)NULL) {
	fprintf(stdout, "Error: forced alignment file not specified\n");
	exit(ISIP_PROTO_ERROR);
      }
      
      // open forced alignment file
      //
      open_file_cc(fpli_list, forcealign_file_d, (char_1*)"r");
    }

    // define file pointers for data files
    //
    FILE* fpi = (FILE*)NULL;
    FILE* fpo = (FILE*)NULL;
    FILE* fpli = (FILE*)NULL;
    FILE* fplo = (FILE*)NULL;
    FILE* fpnbo = (FILE*)NULL;
    FILE* fpmsi = (FILE*)NULL;
    
    // allocate memory for individual mfcc, lattice and output files
    //
    char_1* feat_file = new char_1[ISIP_MAX_STRING_LENGTH];
    char_1* hyp_file = new char_1[ISIP_MAX_STRING_LENGTH];
    char_1* lattice_in = new char_1[ISIP_MAX_STRING_LENGTH];
    char_1* lattice_out = new char_1[ISIP_MAX_STRING_LENGTH];
    char_1* transcription = new char_1[ISIP_MAX_STRING_LENGTH];
    char_1* nbest_out = new char_1[ISIP_MAX_STRING_LENGTH];
    char_1* model_seg_in = new char_1[ISIP_MAX_STRING_LENGTH];

    // timiming information variable
    //
    float_8 dec_time = 0, tmp_dec_time;
    int_4 frame = 0, utterance = 0, tmp_frame;

    int_4 num_file = 1;
    
    // read the corresoponding data file from each list and process one
    // by one
    //
    while (fgets((char*)feat_file, ISIP_MAX_STRING_LENGTH, fpin_list) !=
	   (char*)NULL) {

      // skip the new line
      //    
      while (*feat_file == ISIP_NEWLINE) {
	while (fgets((char*)feat_file, ISIP_MAX_STRING_LENGTH, fpin_list) !=
	       (char*)NULL);
	  }
      
      // expand the input filename
      //
      Decoder::expand_filename_cc(feat_file);
      if (input_format_d == TP_ASCII_FORMAT) {
	open_file_cc(fpi, feat_file, (char_1*)"r");
      }
      else {
	open_file_cc(fpi, feat_file, (char_1*)"rb");
      }
      
      // print status message
      //
      fprintf(stdout, "processing file %ld: %s\n", num_file, feat_file);
      fflush(stdout);
      num_file++;
      
      
      // read the first file in the list
      //
      if (fgets((char*)hyp_file, ISIP_MAX_STRING_LENGTH, fpout_list) ==
	  (char*)NULL) {
	fprintf(stdout, "Error : mismatch in the number of ");
	fprintf(stdout, "input mfcc files and output files.\n");
	exit(ISIP_PROTO_ERROR);
      }
      
      // skip the newline
      //
      while (*hyp_file == ISIP_NEWLINE) {
	
	// make sure there is a corresponding output file for each input
	// file
	//
	if (fgets((char*)hyp_file, ISIP_MAX_STRING_LENGTH, fpout_list) ==
	    (char*)NULL) {
	  fprintf(stdout, "Error : mismatch in the number of ");
	  fprintf(stdout, "input mfcc files and output files.\n");
	  exit(ISIP_PROTO_ERROR);
	}
      }
      
      Decoder::expand_filename_cc(hyp_file);
      open_file_cc(fpo, hyp_file, (char_1*)"w");
      
      // read the nbest output file in the list
      //
      if (fpnbo_list != NULL) {
	if (fgets((char*)nbest_out, ISIP_MAX_STRING_LENGTH, fpnbo_list) ==
	    (char*)NULL) {
	  fprintf(stdout, "Error : mismatch in the number of ");
	  fprintf(stdout, "input mfcc files and nbest output files.\n");
	  exit(ISIP_PROTO_ERROR);
	}

	// skip the newline
	//
	while (*nbest_out == ISIP_NEWLINE) {
	
	  // make sure there is a corresponding output file for each input
	  // file
	  //
	  if (fgets((char*)nbest_out, ISIP_MAX_STRING_LENGTH, fpnbo_list) ==
	      (char*)NULL) {
	    fprintf(stdout, "Error : mismatch in the number of ");
	    fprintf(stdout, "input mfcc files and nbest output files.\n");
	    exit(ISIP_PROTO_ERROR);
	  }
	}
	
	Decoder::expand_filename_cc(nbest_out);
	open_file_cc(fpnbo, nbest_out, (char_1*)"w");
      }

      // if this is model-level segment mode
      //
      if (segment_mode_d == TP_MODEL_SEGMENT_MODE) {
	
	// read the first model-level segment file from the file list
	//
	if (fgets((char*)model_seg_in, ISIP_MAX_STRING_LENGTH, fpms_list) ==
	    (char*)NULL) {
	  fprintf(stdout, "Error : mismatch in the number of , ");
	  fprintf(stdout, "input mfcc files and input model-level segment files.\n");
	  exit(ISIP_PROTO_ERROR);
	}
	
	// skip the newline
	//
	while (*model_seg_in == ISIP_NEWLINE) {
	  
	  // make sure there is a corresponding mfcc file for each file
	  //
	  if (fgets((char*)model_seg_in, ISIP_MAX_STRING_LENGTH, fpli_list) ==
	      (char*)NULL) {
	    fprintf(stdout, "Error : mismatch in the number of , ");
	    fprintf(stdout, "input mfcc files and input model-level segment files.\n");
	    exit(ISIP_PROTO_ERROR);
	  }
	}
	Decoder::expand_filename_cc(model_seg_in);
	open_file_cc(fpmsi, model_seg_in, (char_1*)"r");
	
	// read lattice into the decoder and close file
	//
	decoder_d->read_model_segment_cc(fpmsi);

	if (fpmsi != (FILE*)NULL) {
	  fclose(fpmsi);
	}
      }
      
      // if this is lattice rescoring mode
      //
      if ((function_mode_d == TP_LATTICE_RESCORE_FUNCTION) ||
	  (function_mode_d == TP_LATTICE_LATTICE_FUNCTION) ||
	  (function_mode_d == TP_LATTICE_VERIFY_FUNCTION)) {
	
	// read the first lattice file from the file list
	//
	if (fgets((char*)lattice_in, ISIP_MAX_STRING_LENGTH, fpli_list) ==
	    (char*)NULL) {
	  fprintf(stdout, "Error : mismatch in the number of , ");
	  fprintf(stdout, "input mfcc files and input lattice files.\n");
	  exit(ISIP_PROTO_ERROR);
	}
	
	// skip the newline
	//
	while (*lattice_in == ISIP_NEWLINE) {
	  
	  // make sure there is a corresponding lattice file for each file
	  //
	  if (fgets((char*)lattice_in, ISIP_MAX_STRING_LENGTH, fpli_list) ==
	      (char*)NULL) {
	    fprintf(stdout, "Error : mismatch in the number of , ");
	    fprintf(stdout, "input mfcc files and input lattice files.\n");
	    exit(ISIP_PROTO_ERROR);
	  }
	}
	Decoder::expand_filename_cc(lattice_in);
	open_file_cc(fpli, lattice_in, (char_1*)"r");
	
	// read lattice into the decoder and close file
	//
	decoder_d->read_lattice_cc(fpli);

	if (fpli != (FILE*)NULL) {	  
	  fclose(fpli);
	}
      }
      
      // if this is lattice generation mode
      //
      if ((function_mode_d == TP_LATTICE_GENERATE_FUNCTION) ||
	  (function_mode_d == TP_LATTICE_LATTICE_FUNCTION)) {
	
	// read the first file from the lattice file list
	//
	if (fgets((char*)lattice_out, ISIP_MAX_STRING_LENGTH, fplo_list) ==
	    (char*)NULL) {
	  fprintf(stdout, "Error : mismatch in the number of , ");
	  fprintf(stdout, "input mfcc files and output lattice files.\n");
	  exit(ISIP_PROTO_ERROR);
	}
	
	// skip the newline
	//
	while (*lattice_out == ISIP_NEWLINE) {
	  
	  // make sure there is a corresponding lattice file for each file
	  //
	  if (fgets((char*)lattice_out, ISIP_MAX_STRING_LENGTH, fplo_list) ==
	      (char*)NULL) {
	    fprintf(stdout, "Error : mismatch in the number of , ");
	    fprintf(stdout, "input mfcc files and output lattice files.\n");
	    exit(ISIP_PROTO_ERROR);
	  }  
	}
	Decoder::expand_filename_cc(lattice_out);
	open_file_cc(fplo, lattice_out, (char_1*)"w");
      }
      
      // if this is force alignment mode convert transcription into lattice
      // format
      //
      if (function_mode_d == TP_FORCE_ALIGN_FUNCTION) {
	
	// read first transcription string from the transcription file
	//
	if (fgets((char*)transcription, ISIP_MAX_STRING_LENGTH, fpli_list) ==
	    (char*)NULL) {
	  fprintf(stdout, "Error : mismatch in the number of , ");
	  fprintf(stdout, "input mfcc files and reference transcriptions.\n");
	  exit(ISIP_PROTO_ERROR);
	}
	
	// skip the newline
	//
	while (*transcription == ISIP_NEWLINE) {
	  
	  // make sure there is a corresponding transcription string for
	  // each file
	  //
	  if (fgets((char*)transcription, ISIP_MAX_STRING_LENGTH, fpli_list) ==
	      (char*)NULL) {
	    fprintf(stdout, "Error : mismatch in the number of , ");
	    fprintf(stdout, "input mfcc files and reference transcriptions.\n");
	    exit(ISIP_PROTO_ERROR);
	  }
	}
	decoder_d->read_lattice_cc(transcription);
      }

      // perform viterbi search
      //
      decoder_d->decode_cc(fpi, fpo, fplo, fpnbo);
      
      // acumulate the overall decoding time
      //
      decoder_d->get_decode_time_cc(tmp_dec_time);
      decoder_d->get_frame_cc(tmp_frame);
      dec_time += tmp_dec_time;
      frame += tmp_frame;
      utterance++;

      // output cumulate decoding time information
      // assuming frame_duration = 10 msec
      //
      fprintf(stdout, "%ld) Processed total %ld frames, decoding time = %.1f seconds, %.2f xRT\n\n", utterance, frame, dec_time, dec_time*100/frame);
      fflush(stdout);
      
      // close the files
      //
      if (fpi != (FILE*)NULL) {
	fclose(fpi);
      }
      if (fpo != (FILE*)NULL) {
	fclose(fpo);
      }
      if (fplo != (FILE*)NULL) {
	fclose(fplo);
      }
      if (fpnbo != (FILE*)NULL) {
	fclose(fpnbo);
      }
    } // end while loop over all files

    // print the overall decoding time information
    //
    fprintf(stdout, "Finished decoding total %ld utterances:\n  total %ld frames\n  total decoding time = %.1f seconds, %.2f xRT\n", utterance, frame, dec_time, dec_time*100/frame);
    fflush(stdout);
      
    // close all files
    //
    if (fpin_list != (FILE*)NULL) {
      fclose(fpin_list);
    }
    if (fpout_list != (FILE*)NULL) {
      fclose(fpout_list);
    }
    
    if ((function_mode_d == TP_LATTICE_VERIFY_FUNCTION) ||
	(function_mode_d == TP_LATTICE_RESCORE_FUNCTION) ||
	(function_mode_d == TP_LATTICE_LATTICE_FUNCTION) ||
	(function_mode_d == TP_FORCE_ALIGN_FUNCTION)) {
      if (fpli_list != (FILE*)NULL) {
	fclose(fpli_list);
      }
    }
    
    if ((function_mode_d == TP_LATTICE_VERIFY_FUNCTION) ||
	(function_mode_d == TP_LATTICE_LATTICE_FUNCTION) ||
	(function_mode_d == TP_LATTICE_GENERATE_FUNCTION)) {
      if (fplo_list != (FILE*)NULL) {
	fclose(fplo_list);
      }
    }

    if ((function_mode_d == TP_LATTICE_RESCORE_FUNCTION) ||
	(function_mode_d == TP_NGRAM_DECODE_FUNCTION) ||
	(function_mode_d == TP_LATTICE_VERIFY_FUNCTION)) {
      if (fpnbo_list != (FILE*)NULL) {
	fclose(fpnbo_list);
      }
    }
    
    // free memory
    //
    if (feat_file != (char_1*)NULL) {
      delete [] feat_file;
      feat_file = (char_1*)NULL;
    }

    if (hyp_file != (char_1*)NULL) {
      delete [] hyp_file;
      hyp_file = (char_1*)NULL;
    }

    if (lattice_in != (char_1*)NULL) {
      delete [] lattice_in;
      lattice_in = (char_1*)NULL;
    }

    if (lattice_out != (char_1*)NULL) {
      delete [] lattice_out;
      lattice_out = (char_1*)NULL;
    }

    if (transcription != (char_1*)NULL) {
      delete [] transcription;
      transcription = (char_1*)NULL;
    }

    if (nbest_out != (char_1*)NULL) {
      delete [] nbest_out;
      nbest_out = (char_1*)NULL;
    }
    
    if (model_seg_in != (char_1*)NULL) {
      delete [] model_seg_in;
      model_seg_in = (char_1*)NULL;
    }
    
  } // end else if not lattice error rate mode

  // exit gracefully
  //
  return ISIP_TRUE;
}
