#include "calc_stat.h"
#include "misc_utils.h"
#include <cstring>
#include <assert.h>

void CalcStat::pause() 
{
  pause_time = time(0);
};


void CalcStat::cont() {
  pause_time = time(NULL) - pause_time;
  session_start_time += pause_time;
  wav_start_time += pause_time;
  mp3_start_time += pause_time;
};

void CalcStat::init() 
{
  wav_ratio = config.wav_ratio;
  mp3_ratio = config.mp3_ratio;
  total_wav_length_remain = 0;
  total_mp3_length_remain = 0;
  length_first_track = 0;
  length_last_track = 0;
  first_track = -1;
  last_track = -1;
  first_track_time_remain = 0;
  last_track_time_remain = 0;
  /*
  session_start_time = 0;
  wav_start_time = 0;
  pause_time = 0;
  */
};
  

void CalcStat::start_session(const MainData *main_data, _stat *stat) 
{
  int track=-1;
  CommonEncoderType type=WAV;

  /* Reset stat structure */
  memset(stat, 0, sizeof(*stat));
  stat->wav.track = -1;
  stat->mp3.track = -1;
  stat->tracks_remain = 0;
  stat->wav.progress = 0;
  stat->mp3.progress = 0;
  stat->total_progress = 0;
  stat->ripping = FALSE;
  stat->encoding = FALSE;
  
  this->init();
  
  /* calculate total times */
  while(main_data->find_next_job(track, WAV, &track, &type) >= 0)
    {
      total_wav_length_remain += main_data->track[ track ].length;
      stat->tracks_remain++;
      
      if(length_first_track == 0)
	{
	  first_track = track;
	  length_first_track = main_data->track[ track ].length;
	}
      
      last_track = track;
      length_last_track = main_data->track[ track ].length;
    }
  
  first_track_time_remain = main_data->track[ first_track ].length * wav_ratio;
  last_track_time_remain = main_data->track[ last_track ].length * mp3_ratio;
  
  track = -1;
  type = MP3;
  
  while(main_data->find_next_job(track, MP3, &track, &type) >= 0)
    {
      total_mp3_length_remain += main_data->track[ track ].length;
    }
  
  total_wav_length = total_wav_length_remain;
  total_mp3_length = total_mp3_length_remain;
  saved_total_wav_length_remain = total_wav_length_remain;
  saved_total_mp3_length_remain = total_mp3_length_remain;
  session_start_time = time(NULL);
};


void CalcStat::start(const MainData *main_data, _stat *stat, int cur_track, CommonEncoderType cur_type) 
{
  create_file_names_for_track(
			      main_data, 
			      cur_track, 
			      &wav_file_path, 
			      &enc_file_path
			      );
  
  if(cur_type == WAV)
    {
      strcpy(stat->dest_file_name,
	     file_name_without_path(wav_file_path));
      wav_prev_length_processed = 0;
      stat->wav.time_elapsed = 0;
      stat->wav.track = cur_track;
      wav_start_time = time(NULL);
    }
  else
    {
      strcpy(stat->src_file_name,
	     file_name_without_path(wav_file_path));
      strcpy(stat->dest_file_name,
	     file_name_without_path(enc_file_path));
      mp3_prev_length_processed = 0;
      stat->mp3.time_elapsed = 0;
      stat->mp3.track = cur_track;
      mp3_start_time = time(NULL);
    }
  
  count = 0;
};

void CalcStat::update(const MainData *main_data, _stat *stat, unsigned int current, int cur_track, CommonEncoderType cur_type) 
{

  unsigned wav_length_processed;
  unsigned mp3_length_processed;
  int type;
  float total_time, temp;

  time_t cur_time = time(NULL);
  stat->total_time_elapsed = cur_time - session_start_time;
  
  assert (stat->total_time_elapsed > 0);
  
  /* avoid dividing by zero */
  if(current == 0)
    {
      current = 1;
    }
  
  if(cur_type == WAV)
    {
      stat->wav.time_elapsed = cur_time - wav_start_time;
      wav_length_processed = current;
      
      stat->wav.progress = (float) wav_length_processed / main_data->track[ cur_track ].length;
      wav_temp_ratio = (float)(stat->wav.time_elapsed) / wav_length_processed;
      
      if(count++ >= COUNT_BEFORE_GET_AVG)
	{
	  /* do not adjust ratio if length_processed is not 1 */
	  if(wav_length_processed != 1)
	    {
	      wav_ratio = (wav_temp_ratio + 2 * wav_ratio) / 3;
	    }
	}
      else
	{
	  wav_temp_ratio = wav_ratio;
	}
      
      stat->wav.time_remain =
	(main_data->track[ cur_track ].length - wav_length_processed) * wav_temp_ratio;
      total_wav_length_remain -= wav_length_processed - wav_prev_length_processed;
      wav_prev_length_processed = wav_length_processed;
      
      if(cur_track == first_track)
	{
	  first_track_time_remain = stat->wav.time_remain;
	}
    }
  else
    {
      stat->mp3.time_elapsed = cur_time - mp3_start_time;
      mp3_length_processed = current;
      
      stat->mp3.progress = (float) mp3_length_processed / main_data->track[ cur_track ].length;
      
      mp3_temp_ratio = (float)(stat->mp3.time_elapsed) / mp3_length_processed;
      
      if(count++ >= COUNT_BEFORE_GET_AVG)
	{
	  /* do not adjust ratio if length_processed is not 1 */
	  if(mp3_length_processed != 1)
	    {
	      mp3_ratio = (mp3_temp_ratio + 2 * mp3_ratio) / 3;
	    }
	}
      else
	{
	  mp3_temp_ratio = mp3_ratio;
	}
      
      stat->mp3.time_remain =
	(main_data->track[ cur_track ].length - mp3_length_processed) * mp3_temp_ratio;
      total_mp3_length_remain -= mp3_length_processed - mp3_prev_length_processed;
      mp3_prev_length_processed = mp3_length_processed;
      
      if(cur_track == last_track)
	{
	  last_track_time_remain = stat->mp3.time_remain;
	}
    }
  
  /* Total progress */
  if(main_data->track[ cur_track ].make_mp3)
    {
      /* for ripping and encoding. Assumption: Total time is equal to
	 time_to_rip_first_track + time_to_encode_all_tracks */
      
      if(mp3_ratio > wav_ratio)
	{
	  stat->total_time_remain = first_track_time_remain + total_mp3_length_remain * mp3_ratio;
	  total_time = length_first_track * wav_ratio + total_mp3_length * mp3_ratio;
	}
      else
	{
	  /* for rare case when ripping takes longer than encoding */
	  stat->total_time_remain = last_track_time_remain + total_wav_length_remain * wav_ratio;
	  total_time = length_last_track * mp3_ratio + total_wav_length * wav_ratio;
	}
    }
  else
    {
      /* if we are only ripping, only use the wav times */
      stat->total_time_remain = total_wav_length_remain * wav_ratio;
      total_time = total_wav_length * wav_ratio;
    }
  
  temp = (total_time - stat->total_time_remain) / total_time;
  
  if(temp >= stat->total_progress)
    {
      stat->total_progress = temp;
    }
  else if((temp - stat->total_progress) / temp >= 0.05)
    {
      stat->total_progress = temp;
    }
};

void CalcStat::stop (const MainData *main_data, _stat *stat, CommonEncoderType cur_type)
{
  if(cur_type == WAV)
    {
      saved_total_wav_length_remain -= main_data->track[ stat->wav.track ].length;
      total_wav_length_remain = saved_total_wav_length_remain;
    }
  else
    {
      saved_total_mp3_length_remain -= main_data->track[ stat->mp3.track ].length;
      total_mp3_length_remain = saved_total_mp3_length_remain;
    }
}

void CalcStat::stop_session (_stat *stat)
{
  stat->tracks_remain = 0;
  stat->tracks_done = 0;
  config.wav_ratio = wav_ratio;
  config.mp3_ratio = mp3_ratio;
};

