// file: ih_comp_0.cc
//

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

// isip include files
//
#include "init_hmm.h"
#include "init_hmm_constants.h"

// method: compute_cc
//
// arguments:
//  FILE* fin : (input) the input feature list file
//  float_4* means : (output) the computed mean array
//  float_4** covar: (output) the computed covariance metrix
//  int_4 num_feat : (input) the number of the features in a vector
//  int_4 mode     : (input) input feature file mode
//  logical_1 delta : (input) delta coeff. computations
//  logical_1 acc : (input) acceleration coeff. computations
//  int_4 delta_win : (input) window size
//  logical_1 feature_format : (input) input feature file format
//
// return: a logical_1 flag indication success
//
// this method read the feature file from the input list and compute the
// the mean and the covariance metrix of the feature vectors in all
// feature files
//
logical_1 compute_cc(FILE* fin_a, float_4* means_a,
		     float_4** covar_a, int_4 num_feat_a, int_4 mode_a,
		     logical_1 delta_a, logical_1 acc_a, int_4 delta_win_a,
		     logical_1 feature_format_a) {
  
  // variables
  //
  int_4 num_feat = 0;
  int_4 num_vect = 0;
  int_4 total_num_vect = 0;
  int_4 num_file = 0;
  int_4 n_samples;
  int_4 samp_period;
  int_2 samp_size;
  int_2 samp_kind;
  int_4 flag = ISIP_TRUE;
  int_4 total_bytes = (int_4)0;
  int_4 header_bytes = (int_4)0;
  int_4 temp_num_feat = (int_4)0;
  float_8** data = (float_8**)NULL;
  float_4* temp_data = (float_4*)NULL;
 
  float_8* feature = new float_8[num_feat_a];
  memset(feature, 0, num_feat_a * sizeof(float_8));
   
  char_1* input_file = new char_1[ISIP_MAX_STRING_LENGTH];
  char_1* buffer = new char_1[ISIP_MAX_STRING_LENGTH];
  FILE* fpi = (FILE*)NULL;
  
  // read the corresponding data file from feature list and compute the
  // sum of the feature vectors
  //
  while (fgets((char*)input_file, ISIP_MAX_STRING_LENGTH, fin_a) !=
	 (char*)NULL) {

    // strip newline characters and expand the filenames
    //
    expand_filename_cc(input_file);
    
    // open the input feature file to read
    //
    if (mode_a == IH_ASCII_MODE) {
      fpi = fopen((char*)input_file, "r");
    }
    else {
      fpi = fopen((char*)input_file, "rb");
    }
    if (fpi == (FILE*)NULL) {
      fprintf(stdout, "Warning : cannot open feature file %s\n", input_file);
      continue;
    }
    else {
      num_file++;
    }

    // loop all the feature vectors in the current feature file
    //

    // if input mode is ascii
    //
    if (mode_a == IH_ASCII_MODE) {

      if (feature_format_a == IH_HTK_FORMAT) {
	 fprintf(stdout, "Warning: ASCII HTK input feature file not supported %s\n", input_file);
	flag = ISIP_FALSE;
       }
       
       while (fgets((char*)buffer, ISIP_MAX_STRING_LENGTH, fpi) !=
	     (char*)NULL) {

	
	// count the number of feature vector
	//
	total_num_vect++;
	
	// loop all the features in this feature vector
	//
	char* temp_buf = strtok((char*)buffer, " ");
	
	// loop all the features in the current feature vector
	//
	while ((temp_buf != (char*)NULL) && (num_feat < num_feat_a)) {
	  
	  // store the value of this feature into sum array
	  //
	  feature[num_feat] = (float_8)atof(temp_buf);

	  means_a[num_feat] += (float_4)(feature[num_feat]);

	  // count the features in this vector
	  //
	  num_feat++;
	  
	  // read the following feature
	  //
	  temp_buf = strtok((char*)NULL, " ");
	}

	// store product of features into covariance metrix
	//
	for (int_4 i = 0; i < num_feat_a; i++) {
	  for (int_4 j = 0; j < num_feat_a; j++) {

	    covar_a[i][j] += (float_4)(feature[i] * feature[j]);

	  }
	}

	// reset the count varable
	//
	num_feat = 0;
      }      
    }
    else {
      
      // read the htk header mfcc's and calculate the mfcc file size
      //
      if (feature_format_a == IH_HTK_FORMAT) {
	
	fseek (fpi, 0L, SEEK_SET);
	
	if (!fread (&n_samples, sizeof(int_4), 1, fpi)) {
	  fprintf(stdout, "Warning: No. of Samples not specified in HTK Header file %s\n", input_file);
	  flag = ISIP_FALSE;
	}
  
	if (!fread (&samp_period, sizeof(int_4), 1, fpi)) {
	  fprintf(stdout, "Warning: Sampling Period not specified in HTK Header file %s\n", input_file);
	  flag = ISIP_FALSE;
	}
	
	if (!fread (&samp_size, sizeof(int_2), 1, fpi)) {
	  fprintf(stdout, "Warning: Sampling size notspecified in HTK Header file %s\n", input_file);
	  flag = ISIP_FALSE;
	}
	
	if (!fread (&samp_kind, sizeof(int_2), 1, fpi)) {
	  fprintf(stdout, "Warning: Sampling kind not specified in HTK Header file %s\n", input_file);
	  flag = ISIP_FALSE;
	}
	
	header_bytes = ftell(fpi);
	fseek(fpi, 0, SEEK_END);
	total_bytes = ftell(fpi) - header_bytes;
      }
      
      else {
	fseek(fpi, 0, SEEK_END);
	total_bytes = ftell(fpi);
      }
      
 if (acc_a == ISIP_TRUE) {
   temp_num_feat = num_feat_a / (int_4)3;
 }
 
 else if (delta_a == ISIP_TRUE) {
   temp_num_feat = num_feat_a / (int_4)2;
 }
 
 else
   temp_num_feat = num_feat_a;
 
 // compute number of vectors in the input mfcc file
 //
 if (feature_format_a == IH_HTK_FORMAT) {
   num_vect = total_bytes / (temp_num_feat * sizeof(float_4));
 }

 else num_vect = total_bytes / (temp_num_feat * sizeof(float_8));
 
 total_num_vect += num_vect;
   
 // allocate memory
 //
 data = new float_8*[num_vect];
 rewind(fpi);

 if (feature_format_a == IH_HTK_FORMAT) {
   
   fseek (fpi, 0L, SEEK_SET);
   
   if (!fread (&n_samples, sizeof(int_4), 1, fpi)) {
     fprintf(stdout, "Warning: No. of Samples not specified in HTK Header file %s\n", input_file);
     flag = ISIP_FALSE;
   }
   
   if (!fread (&samp_period, sizeof(int_4), 1, fpi)) {
     fprintf(stdout, "Warning: Sampling Period not specified in HTK Header file %s\n", input_file);
     flag = ISIP_FALSE;
   }
   
   if (!fread (&samp_size, sizeof(int_2), 1, fpi)) {
     fprintf(stdout, "Warning: Sampling size notspecified in HTK Header file %s\n", input_file);
     flag = ISIP_FALSE;
   }
   
   if (!fread (&samp_kind, sizeof(int_2), 1, fpi)) {
     fprintf(stdout, "Warning: Sampling kind not specified in HTK Header file %s\n", input_file);
     flag = ISIP_FALSE;
   }

   // read the features as float and cast to double
   //
   temp_data = new float_4[num_feat_a];
   for (int_4 i = 0; i < num_vect; i++) {
     data[i] = new float_8[num_feat_a];
     if ((int_4)fread(temp_data, sizeof(float_4), temp_num_feat, fpi)
	 != temp_num_feat) {
       flag = ISIP_FALSE;
       break;
     }
     for ( int_4 j = 0; j < num_feat_a; j++) {
       data[i][j] = (float_8)temp_data[j];
     }
   }   
 }

 // read the features as doubles
 //
 else {
   for (int_4 i = 0; i < num_vect; i++) {
     data[i] = new float_8[num_feat_a];
     if ((int_4)fread(data[i], sizeof(float_8), temp_num_feat, fpi)
	 != temp_num_feat) {
       flag = ISIP_FALSE;
       break;
     }
   }
 }
 
 // compute the deltas and accelerations
 //
 if (delta_a == ISIP_TRUE) {
   Extract_feature::compute_delta_cc(data, num_vect, 0, temp_num_feat,
				     delta_win_a);
 }
 
 if (acc_a == ISIP_TRUE) {
   Extract_feature::compute_delta_cc(data, num_vect, temp_num_feat,
				     temp_num_feat, delta_win_a);
 }
 
 // compute the means and the variances
 //
 for (int_4 i = 0; i < num_vect; i++) {
   
   for (int_4 j = 0; j < num_feat_a; j++) {
     
     // add the feature values to the mean
     //
     means_a[j] += (float_4)(data[i][j]);
     
     // store product of features into covariance metrix
     //
     for (int_4 k = 0; k < num_feat_a; k++) {
       
       // increment the covariance
       covar_a[j][k] += (float_4)(data[i][j] * data[i][k]);
     }
   }
 }
 
 // free memory
 //
 if (temp_data != (float_4*)NULL) {
   delete [] temp_data;
 }
 
 if (data != (float_8**)NULL) {
   for (int_4 i = 0; i < num_vect; i++) {
     if (data[i] != (float_8*)NULL) {
       delete [] data[i];
     }
   }
   delete [] data;
 }
  
    } // end else binary mode
    
    // close the current feature file
    //
    fclose(fpi);      
    
  } // end loop over all feature files
  
  // print number of feature files read
  //
  fprintf(stdout, "Number of feature files read:\t%ld\n", num_file);

  // compute the mean for each feature in feature vector
  //
  for (int_4 i = 0; i < num_feat_a; i++) {
    means_a[i] /= (float_4)(total_num_vect);
  }
  
  // compute the covariance matrix for the feature vectors
  //
  for (int_4 l = 0; l < num_feat_a; l++) {
    for (int_4 k = 0; k < num_feat_a; k++) {
      covar_a[l][k] /= (float_4)(total_num_vect-1);
      covar_a[l][k] -= (means_a[l] * means_a[k]);
    }
  }

  // free memory
  //
  delete [] buffer;
  delete [] input_file;
  delete [] feature;

  fpi = (FILE*)NULL;
  
  // exit gracefully
  //
  return flag;
}
