#include "config.h"

#include "player.hpp"

#include "audio.hpp"
#include "audio_s.hpp"

#include "dbaudiofile.hpp"

#include "common.hpp"
#include "rand.hpp"
#include "gettext.hpp"

#include <vector>
#include <string>
#include <fstream>

using std::vector;
using std::string;

Player::Player(const string& t, const string& art, 
	       const string& al, int ct, int tt, int bs) :
  buffering_state(bs), title(t), artist(art), album(al), 
  cur_time(ct), total_time(tt), old_volume(0), play_next_track(false)
{
  conf = Config::get_instance();
}

void Player::next_helper()
{
  Audio *audio = Audio::get_instance();

  if (audio->playlist_size() == 0) {
    Simplefile s;
    cur_nr = s;
    return;
  }

  Audio_s *audio_state = Audio_s::get_instance();
  Rand &rand = Rand::get_instance();

#ifdef use_imms
  vector<Dbaudiofile>::iterator last_element = audio->playlist.end();
  vector<Dbaudiofile>::iterator j = audio->playlist.begin();
#else
  vector<Simplefile>::iterator last_element = audio->playlist.end();
  vector<Simplefile>::iterator j = audio->playlist.begin();
#endif  

  --last_element;

  if (audio_state->queue_size() != 0) {
    
    cur_nr = audio_state->next_in_queue();

  } else if (audio->opts.shuffle() == gettext("real random")) {

    if (audio->playlist.size() > 1) {
      int r = rand.number(audio->playlist.size());

      while (cur_nr == vector_lookup(audio->playlist, r))
	r = rand.number(audio->playlist.size());

      cur_nr = vector_lookup(audio->playlist, r);
      audio_state->direction = Audio_s::ADDED;
    }

  } else if (audio->opts.shuffle() == gettext("winamp random")) {

    Simplefile new_nr;
    while ((new_nr = audio->shuffle_list.next_track()) == cur_nr && audio->playlist.size() != 1);
    cur_nr = new_nr;

  } else if (audio->opts.shuffle() == gettext("intelligent")) {

#ifdef use_imms
    audio->imms_mut.enterMutex();

    int time_left =  p_total_time() - p_cur_time();

    if (time_left < 3)
      time_left = 0;

    bool forced = time_left;

    if (audio_state->imms_cur_path != cur_nr.path) {
      // FIXME: it should probably end the old song if it is playing
      for (int i = 0, end = audio->playlist.size(); i < end; ++i)
	if (vector_lookup(audio->playlist, i).id == cur_nr.id) {
	  audio_state->imms->start_song(i, cur_nr.path);
	  break;
	}
    }

    audio_state->imms->end_song(!time_left, forced, false);

    int r = audio_state->imms->select_next();

    cur_nr = vector_lookup(audio->playlist, r);

    audio_state->imms_cur_path = cur_nr.path;

    audio_state->imms->start_song(r, audio_state->imms_cur_path);

    audio_state->direction = Audio_s::ADDED;

    audio->imms_mut.leaveMutex();
#endif

  } else {
      
    if (cur_nr != (*last_element) || conv::stob(audio->opts.repeat()) && !conv::stob(audio->opts.shutdown())) {

      // the currently selected track was deleted
      if (cur_nr.id == 0) {
	int p = audio->playlist_pos_int;
	if (audio->playlist_pos_int >= audio->playlist_size()-1)
	  p = 0;
	cur_nr = vector_lookup(audio->playlist, p);
	return;
      }

      Simplefile c = cur_nr;

      if (!(c == (*last_element) && conv::stob(audio->opts.repeat()) && !conv::stob(audio->opts.shutdown()))) {
      
	while (j != audio->playlist.end()) {

	  if (j->id == c.id)
	    break;
	  else
	    j++;
	}
      
	j++;
      }
    }
    cur_nr = *j;
  }

  if (cur_nr.id != 0) // deleted track
    audio_state->add_track_to_played(cur_nr);
}

void Player::prev_helper()
{
  Audio *audio = Audio::get_instance();

  if (audio->playlist_size() == 0) {
    Simplefile s;
    cur_nr = s;
    return;
  }

  Audio_s *audio_state = Audio_s::get_instance();
  Rand &rand = Rand::get_instance();

#ifdef use_imms
  vector<Dbaudiofile>::iterator j = audio->playlist.begin();
#else
  vector<Simplefile>::iterator j = audio->playlist.begin();
#endif  

  if (audio->opts.shuffle() == gettext("real random")) {
      
    Simplefile prev_track = audio_state->prev_track_played();

    if (audio_state->direction == Audio_s::ADDED && prev_track.id != 0) {
      prev_track = audio_state->prev_track_played();
      audio_state->direction = Audio_s::TAKEN;
    }

    if (prev_track.id != 0) {
	
      cur_nr = prev_track;

    } else {

      if (audio->playlist.size() > 1) {
	// empty
	int r = rand.number(audio->playlist.size());
	
	while (cur_nr == vector_lookup(audio->playlist, r))
	  r = rand.number(audio->playlist.size());

	cur_nr = vector_lookup(audio->playlist, r);
	audio_state->direction = Audio_s::ADDED;
      }
    }
      
  } else if (audio->opts.shuffle() == gettext("winamp random")) {

    Simplefile prev_nr;
    while ((prev_nr = audio->shuffle_list.prev_track()) == cur_nr && audio->playlist.size() != 1);
    cur_nr = prev_nr;

  } else if (audio->opts.shuffle() == gettext("intelligent")) {

    Simplefile prev_track = audio_state->prev_track_played();

    if (audio_state->direction == Audio_s::ADDED && prev_track.id != 0) {
      prev_track = audio_state->prev_track_played();
      audio_state->direction = Audio_s::TAKEN;
    }

    if (prev_track.id != 0) {
	
      cur_nr = prev_track;

    } else {

#ifdef use_imms
      audio->imms_mut.enterMutex();
	
      int time_left = p_total_time() - p_cur_time();

      if (time_left < 3)
	time_left = 0;

      bool forced = time_left;

      if (audio_state->imms_cur_path != cur_nr.path) {
	// FIXME: it should probably end the old song if it is playing
	for (int i = 0, end = audio->playlist.size(); i < end; ++i)
	  if (vector_lookup(audio->playlist, i).id == cur_nr.id) {
	    audio_state->imms->start_song(i, cur_nr.path);
	    break;
	  }
      }
      
      audio_state->imms->end_song(!time_left, forced, false);

      int r = audio_state->imms->select_next();

      cur_nr = vector_lookup(audio->playlist, r);

      audio_state->imms_cur_path = cur_nr.path;
	
      audio_state->imms->start_song(r, audio_state->imms_cur_path);
	
      audio_state->direction = Audio_s::ADDED;
	
      audio->imms_mut.leaveMutex();
#endif
    }
      
  } else {
      
    Simplefile c = cur_nr;
    
    while (j != audio->playlist.end()) {

      if (j->id == c.id)
	break;
      else
	++j;
    }
    
    if (cur_nr == (*audio->playlist.begin()))
      j = audio->playlist.end();

    --j;

    cur_nr = *j;
  }

  audio_state->add_track_to_played(cur_nr);
}

void Player::stop()
{
  Audio_s *audio_state = Audio_s::get_instance();
  audio_state->set_pause(false);

  stop_player();

#ifdef use_media
  sleep(1);
  Audio *audio = Audio::get_instance();
  audio->pos_umount();
#endif
}

void Player::next()
{
  Audio_s *audio_state = Audio_s::get_instance();

  if (!audio_state->p_playing())
    return;
    
  if (!audio_state->check_repeat()) 
    audio_state->set_playing(false);
  
  if (audio_state->p_playing()) {

#ifdef music_radio_bttv
    Bttv *bttv = Bttv::get_instance();

    if (cur_nr.type == "bttvradio")
      bttv->stop();
#endif

    next_helper();

#ifdef music_radio_bttv
    if (cur_nr.type == "bttvradio")
      bttv->play(cur_nr.path);
    else {
#endif

#ifdef use_media
    Audio *audio = Audio::get_instance();
    audio->check_mount_before(cur_nr);
#endif
    addfile(cur_nr);
#ifdef use_media
    audio->check_mount_after(cur_nr);
#endif

#ifdef music_radio_bttv
    }
#endif
  } else
    stop();
}

void Player::prev()
{
  Audio_s *audio_state = Audio_s::get_instance();
  Audio *audio = Audio::get_instance();

  if (!audio_state->p_playing())
    return;

  if (audio_state->p_playing()) {

#ifdef music_radio_bttv
    Bttv *bttv = Bttv::get_instance();

    if (cur_nr.type == "bttvradio")
      bttv->stop();
#endif

    prev_helper();
  
#ifdef music_radio_bttv
    if (cur_nr.type == "bttvradio")
      bttv->play(cur_nr.path);
    else
#endif

#ifdef use_media
    audio->check_mount_before(cur_nr);
#endif
    addfile(cur_nr);
#ifdef use_media
    audio->check_mount_after(cur_nr);
#endif
  } else
    stop();
}

std::pair<int, bool> Player::load_saved_values()
{
  Config *conf = Config::get_instance();

  // sane default
  int volume = 52, playlist_pos = 0;
  bool play_now_warning = true;

  std::string path = conf->p_var_data_dir() + "options";

  std::ifstream in;
  in.open(path.c_str(), std::ios::in);
  
  if (!in.is_open()) {
    DebugPrint perror(gettext("Could not open options file ") + path,
		      Print::DEBUGGING, DebugPrint::CRITICAL, "THEME");
    ::exit(1);
  } else {
   
    string name, value, str;
    
    while (getline(in, str)) {

      string::size_type comma = str.find(",");

      if (comma == string::npos)
	continue;
      
      name = str.substr(0,comma);
      value = str.substr(comma+1);

      if (name == "volume")
 	volume = conv::atoi(value);
      else if (name == "playlist_pos")
	playlist_pos = conv::atoi(value);
      else if (name == "play_now_warning")
	play_now_warning = conv::stob(value);
    }
    in.close();
  }

  setvol(volume);

  return std::make_pair(playlist_pos, play_now_warning);
}
