// used for #ifdef
#include "config.h"

#include "libfspp.hpp"

#include "game.hpp"

//Input
#include "input.hpp"

#include "common.hpp"
#include "gettext.hpp"
#include "graphics.hpp"

#include "startmenu.hpp"
#include "extra_menu.hpp"
#include "updater.hpp"
#include "busy_indicator.hpp"
#include "shutdown.hpp"

#ifdef c_music
#include "audio.hpp"
#endif

// ostringstream
#include <sstream>

#include <iostream>

#include <cassert>

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

Game::GameOpts::GameOpts() 
{
  // header
  header = gettext("Game Options");

  // values

  // reload
  vector<string> none;
  reload_p = new Option(false, gettext("reload"), "reload", 0, none, none);
  val.push_back(reload_p);

  // sorting order
  val.push_back(go->dir_order);
}

Game::GameOpts::~GameOpts() 
{
  delete reload_p;
}

void Game::GameOpts::read_dirs() 
{ 
  Game &game = Game::get_instance(); 
  game.read_dirs(); 
  game.reset();
}

Game& Game::get_instance() 
{
  static Game s;
  return s;
}

Game::Game() 
  : exit_loop(false)
{
#ifdef use_graphical_game
  if (conf->p_v_res() == 720)
    y_start = 85;
  else if (conf->p_v_res() == 800)
    y_start = 90;
  else if (conf->p_v_res() == 1024)
    y_start = 110;
  else if (conf->p_v_res() == 1280)
    y_start = 110;
  else
    y_start = 70; // default value

  if (conf->p_h_res() == 405)
    y_start = 70;

  image_width = 115;
  image_height = 120;

  if (conf->p_v_res() == 720)
    image_height = 105;

  if (conf->p_h_res() == 405) {
    image_width = 65;
    image_height = 67;
  }

  image_width_all = image_width+25;
  image_height_all = image_height+55;
  image_height_all_eks_text = image_height + 6;

  images_per_row = (conf->p_v_res()-2*25)/image_width_all;

  // lets make some more room for text 
  image_width_all += ((conf->p_v_res()-2*25)%image_width_all)/images_per_row;

  // + 20 is for the last row, since we don't need to add extra space
  rows = (conf->p_h_res()-2*y_start+20)/image_height_all;
  rows_search = (conf->p_h_res()-2*y_start+20-40)/image_height_all;

  image_height_all = (conf->p_h_res()-2*y_start+20)/rows;
  image_height_all_search = (conf->p_h_res()-2*y_start+20-40)/rows_search;

#endif

  reset();
}

void Game::reset()
{
  for (int i = 0, size = folders.size(); i < size; ++i)
    folders.pop();

  list<string> dirs = conf->p_game_dirs();

  folders.push(std::make_pair(dirs, 0));
}

bool Game::file_sort::operator()(const Entry& lhs, const Entry& rhs)
{
  return sort_order(lhs.lowercase_name, rhs.lowercase_name, !lhs.path.empty(), !rhs.path.empty());
}

// commands
void Game::action_play()
{
  Entry e = vector_lookup(files, folders.top().second);
  int nfiles = e.filenames.size();
  if (nfiles > 0)
    playgame(e);
}

void Game::go_back()
{
  if (!(folders.size() == 1)) {
    folders.pop();
    load_current_dirs();
  }
}

void Game::enter_dir()
{
  if (vector_lookup(files, folders.top().second).type != "file")
    {
      string temp_cur_dir = vector_lookup(files ,folders.top().second).path;
      vector<Entry> templist = rdir(temp_cur_dir);

      if (templist.size() != 0) {
	list<string> templs; templs.push_back(temp_cur_dir + "/");
	folders.push(std::make_pair(templs, 0));
	files = templist;
      } else {
	DialogWaitPrint pdialog(gettext("Folder is empty"), 1000);
      }
    }
}

void Game::load_current_dirs()
{
  files = parse_dir(folders.top().first);

  if (folders.top().first.size() > 1 && folders.size() == 1)
    std::sort(files.begin(), files.end(), file_sort());
}

void Game::options()
{
  BusyIndicator::get_instance().idle();
  
  if (opts.mainloop()) {
    // reload
    folders.top().second = 0;
  }
}

void Game::search_func()
{
  BusyIndicator::get_instance().idle();

#ifdef use_graphical_game
  TSpecificFunctor<Game, Entry> print_func(this, &Game::graphical_print);
#else
  TSpecificFunctor<Game, Entry> print_func(this, &Game::print);
#endif
  CompareFunctor<Game, Entry> compare_func(this, &Game::search_compare);
  RepFunctor<Game, Entry> rep_func(this, &Game::get_name_from_file);

  search(files, &folders.top().second, &print_func, &compare_func, &rep_func);
}

void Game::exit()
{
  exit_loop = true;
}

string Game::mainloop()
{
  Startmenu &startmenu = Startmenu::get_instance();
  startmenu.module = "game";
 
  BusyIndicator &busy_indicator = BusyIndicator::get_instance();
  Shutdown &sd = Shutdown::get_instance();
  
  Input input;

  bool update_needed = true;

  while (!exit_loop)
    {
      if (update_needed)
#ifdef use_graphical_game
	graphical_print(files);
#else
        print(files);
#endif

      busy_indicator.idle();

      input = input_master->device->get_input();

      busy_indicator.busy();

      if (sd.is_enabled()) {
      	sd.cancel();
      	continue;
      }

      update_needed = true;

#ifdef use_graphical_game
      if (input.command == "prev")
	{
	  if (files.size() > images_per_row) {
	    for (int i = 0; i < images_per_row; ++i) {
	      if (folders.top().second == 0) {
		folders.top().second = files.size()-1;
		i += images_per_row-files.size()%images_per_row;
	      }
	      else 
		folders.top().second -= 1;
	    }
	  }
 	}
      else if (input.command == "next")
 	{
	  if (files.size() > images_per_row) {
	    for (int i = 0; i < images_per_row; ++i) {
	      if (folders.top().second == files.size()-1 && i == 0) {
		folders.top().second = 0;
		break;
	      } else if (folders.top().second == files.size()-1) {
		break;
	      } else {
		folders.top().second += 1;
	      }
	    }
	  }
 	}
      else if (input.command == "left")
	{
	  if (folders.top().second != 0)
	    folders.top().second -= 1;
	  else
	    folders.top().second = files.size() - 1;
	}
      else if (input.command == "right")
 	{
	  folders.top().second = (folders.top().second+1)%files.size();
 	}
      else if (input.command == "back" && folders.size() > 1)
	{
	  go_back();
	}
      else if (input.command == "back" && folders.size() == 1)
	{
	  exit();
	}
      else if (input.command == "play_game")
	{
	  action_play();
	}
      else if (input.command == "action")
	{
	  if (vector_lookup(files, folders.top().second).type != "file")
	    enter_dir();
	  else
	    action_play();
	}
#else
      if (input.command == "prev")
 	{
	  if (folders.top().second != 0)
	    folders.top().second -= 1;
	  else
	    folders.top().second = files.size() - 1;
 	}
      else if (input.command == "next")
 	{
	  folders.top().second = (folders.top().second+1)%files.size();
 	}
      else if (input.command == "left")
	{
	  go_back();
	}
      else if (input.command == "right")
	{
	  enter_dir();
	}
      else if (input.command == "back" && input.mode == "general")
	{
	  exit();
	}
      else if (input.command == "action")
	{
	  action_play();
	}
#endif
      else if (input.command == "second_action")
	{
	  ExtraMenu em;

#ifdef use_graphical_game
	  if (vector_lookup(files, folders.top().second).type != "file") {
	    TimeFunctorv<Game> t_e = TimeFunctorv<Game>(this, &Game::enter_dir);
	    em.add_item(ExtraMenuItem(gettext("Enter directory"), input_master->find_shortcut("action"), &t_e));
	  } else {
	    TimeFunctorv<Game> t_ap = TimeFunctorv<Game>(this, &Game::action_play);
	    em.add_item(ExtraMenuItem(gettext("Play game"), input_master->find_shortcut("action"), &t_ap));
	  }
	  
	  TimeFunctorv<Game> t_gb = TimeFunctorv<Game>(this, &Game::go_back);
	  TimeFunctorv<Game> t_back = TimeFunctorv<Game>(this, &Game::exit);

#else
	  TimeFunctorv<Game> t_ap = TimeFunctorv<Game>(this, &Game::action_play);
	  em.add_item(ExtraMenuItem(gettext("Play game"), input_master->find_shortcut("action"), 
				    &t_ap));

	  TimeFunctorv<Game> t_e = TimeFunctorv<Game>(this, &Game::enter_dir);
	  if (vector_lookup(files, folders.top().second).type != "file")
	    em.add_item(ExtraMenuItem(gettext("Enter directory"), input_master->find_shortcut("right"), &t_e));
	  
	  TimeFunctorv<Game> t_gb = TimeFunctorv<Game>(this, &Game::go_back);
	  if (folders.size() > 1)
	    em.add_item(ExtraMenuItem(gettext("Go up one directory"), input_master->find_shortcut("left"), &t_gb));
#endif

	  TimeFunctorv<Game> t_sf = TimeFunctorv<Game>(this, &Game::search_func);
	  em.add_item(ExtraMenuItem(gettext("Search"), input_master->find_shortcut("search"), 
				    &t_sf));
	  TimeFunctorv<Game> t_o = TimeFunctorv<Game>(this, &Game::options);
	  em.add_item(ExtraMenuItem(gettext("Options"), input_master->find_shortcut("options"), 
				    &t_o));

#ifdef use_graphical_game
	  if (folders.size() > 1)
	    em.add_item(ExtraMenuItem(gettext("Go up one directory"), input_master->find_shortcut("back"), &t_gb));
	  else {
	    em.add_item(ExtraMenuItem(gettext("Return to startmenu"), 
				      input_master->find_shortcut("back"), 
				      &t_back));
	  }
#else
	  TimeFunctorv<Game> t_back = TimeFunctorv<Game>(this, &Game::exit);
	  em.add_item(ExtraMenuItem(gettext("Return to startmenu"), 
				    input_master->find_shortcut("back"), 
				    &t_back));
#endif

#ifdef c_music
	  TimeFunctorv<Audio> t_player = TimeFunctorv<Audio>(Audio::get_instance(), &Audio::playlist_commands);
	  em.add_item(ExtraMenuItem(gettext("Playlist commands"), input_master->find_shortcut("playlist_commands"), &t_player));
#endif
	  em.mainloop();
	} 
      else if (input.command == "page_up")
 	{
	  int jump = conf->p_jump();

#ifdef use_graphical_game
	  if (search_mode)
	    jump = images_per_row*rows_search;
	  else
	    jump = images_per_row*rows;
#endif

	  if (files.size() > jump) {
	    int diff = folders.top().second-jump;
	    if (folders.top().second == 0)
	      folders.top().second = (files.size()-1)+diff;
	    else if (diff < 0)
	      folders.top().second = 0;
	    else
	      folders.top().second = diff;
	  }
 	}
      else if (input.command == "page_down")
 	{
	  int jump = conf->p_jump();

#ifdef use_graphical_game
	  if (search_mode)
	    jump = images_per_row*rows_search;
	  else
	    jump = images_per_row*rows;
#endif

	  if (files.size() > jump) {
	    if (folders.top().second > (files.size() - jump) && folders.top().second != files.size()-1)
	      folders.top().second = files.size()-1;
	    else
	      folders.top().second = (folders.top().second+jump)%files.size();
	  }
 	}
      else if (input.command == "options")
	{
	  options();
	}
      else if (input.command == "search")
	{
	  search_func();
        }
      else
	update_needed = !general_loop_check(input);
    }

  exit_loop = false;

  return "";
}

string Game::get_name_from_file(const Entry& e)
{
  return e.name;
}

bool Game::search_compare(const Entry& s)
{
  return (s.lowercase_name.substr(0, search_str.size()) == lowercase_search_str);
}

// print a game element
void Game::print_game_element(const Entry& r, const Entry& position, int y)
{
  string name = r.name;

  if (r.type != "file")
    name += "/";

  string_format::format_to_size(name, "Vera/16", conf->p_v_res()-75-155, true);
  
  if (r == position) {
    render->current.add(new PObj(themes->game_marked_left, 70, y-1, 2, NOSCALING));
    render->current.add(new PObj(themes->game_marked, 70+25, y-1, conf->p_v_res()-(2*70)-50, 2));
    render->current.add(new PObj(themes->game_marked_right, 70+25+conf->p_v_res()-(2*70)-50, y-1, 2, NOSCALING));
  }
  
  std::ostringstream out; out << r.filenames.size();

  render->current.add(new TObj(name, "Vera/16", 75, y, 
			       themes->game_font1, themes->game_font2, 
			       themes->game_font3, 3));
  render->current.add(new TObj(r.filetype, "Vera/16", conf->p_v_res()-145, y, 
			       themes->game_font1, themes->game_font2, 
			       themes->game_font3, 3));
  render->current.add(new TObj(out.str(), "Vera/16", conf->p_v_res()-85, y, 
			       themes->game_font1, themes->game_font2, 
			       themes->game_font3, 3));
}

#ifdef use_graphical_game

string Game::get_cover(const std::string& s)
{
  string path = "";
   string test = "";
  string::size_type pos;

  if ((pos = s.rfind(".")) != string::npos) {
    path = s.substr(0, pos);
    test = (path + ".png").c_str();
    if (file_exists(test))
      return test;
    test = (path + ".jpg").c_str();
    if (file_exists(test)) 
      return test;
  }
  return "";
}

void Game::graphical_print(const vector<Entry>& cur_files)
{
  render->prepare_new_image();

  render->current.add(new PObj(themes->game_background, 0, 0, 0, SCALE_FULL));
  
  render->current.add(new PObj(themes->startmenu_game_dir, 25, 10, 2, NOSCALING));
  
  if (themes->show_header) {
    render->current.add(new TObj(gettext("Games"), "Vera/28", 100, 10, 
				 themes->game_header_font1, themes->game_header_font2, 
				 themes->game_header_font3, 2));
  }
  
  if (search_mode) {

    int y = 60;
    if (conf->p_v_res() == 720) {
      y -= 3;
    }

    render->current.add(new RObj(0, y, conf->p_v_res(), 45, 
				 themes->general_search_rectangle_color1, 
				 themes->general_search_rectangle_color2, 
				 themes->general_search_rectangle_color3, 
				 themes->general_search_rectangle_color4, 2));

    render->current.add(new PObj(themes->general_search, 47, y, 3, NOSCALING));

    render->current.add(new TObj(gettext("Search: ") + search_str, "Vera/22", 100, y+5, 
				 themes->game_font1, themes->game_font2, 
				 themes->game_font3, 3));
  }

  // print the range
  int pos, start, pos_in_list, cur_rows, cur_image_height_all;

  if (search_mode) {
    pos_in_list = offset;
    cur_rows = rows_search;
    cur_image_height_all = image_height_all_search;
  } else {
    pos_in_list = folders.top().second;
    cur_rows = rows;
    cur_image_height_all = image_height_all;
  }

  int nr_in_last_row = cur_files.size()%images_per_row;
  if (nr_in_last_row == 0)
    nr_in_last_row = images_per_row;

  if (cur_files.size() > cur_rows*images_per_row) {
    if (pos_in_list < std::ceil(double(cur_rows)/2.0)*images_per_row) {
      pos = pos_in_list;
      start = 0;
    } else if (pos_in_list >= cur_files.size() - (images_per_row+nr_in_last_row)) { // last two rows
      start = cur_files.size()-((cur_rows-1)*images_per_row+nr_in_last_row);
      pos = pos_in_list-start;
    } else {
      pos = pos_in_list%images_per_row+images_per_row;
      if (pos == images_per_row-1)
	pos = 2*images_per_row-1;
      start = pos_in_list-pos;
    }
  } else {
    pos = pos_in_list;
    start = 0;
  }

  int x_start, x = (conf->p_v_res()-images_per_row*image_width_all)/2, y = y_start;
  x_start = x;
  
  if (search_mode)
    y = y_start + 40;

  for (int j = 0; j < cur_rows*images_per_row && j < cur_files.size(); ++j) {

    Entry s = vector_lookup(cur_files, start);
    string name = s.name;

    if (s.type != "file") {

      PObj *p;
      
      if (pos == j)
	p = new PObj(themes->game_dir_marked, x, y, 3, NOSCALING);
      else
	p = new PObj(themes->game_dir, x, y, 3, NOSCALING);

      p->x = p->real_x = x + (image_width_all - p->w)/2;
      p->y = p->real_y = y + (image_height_all_eks_text - p->h)/2;
      
      render->current.add(p);

    } else {
    	string cover_name = "";
    	list<string>::const_iterator iter = (s.filenames).begin();
    	cover_name = get_cover(*iter);
    	 
      if (!file_exists(cover_name)) {
	PObj *p = new PObj(themes->game_mcover, x-5, y-5, 3, NOSCALING);
	p->x = p->real_x = x + (image_width_all - (p->w + 10))/2;
	p->y = p->real_y = y + (image_height_all_eks_text - (p->h + 10))/2;
	render->current.add(p);
      } else {

	bool border = false;
	
	if (pos == j)
	  border = true;

	if (!file_exists(render->image_get_fullpath(cover_name, image_width, 
						    image_height))) {
	  render->create_scaled_image_wrapper(cover_name, image_width, image_height);
	  // to insert the image into the transmap so that it won't fail when
	  // we draw the screen again
	  bool tmp;
	  render->image_dimensions(render->image_get_fullpath(cover_name, image_width, image_height), &tmp);
	}

	PFObj *p = new PFObj(cover_name, x, y, image_width, image_height, border, 3);
	
	p->x = p->real_x = x + (image_width_all - (p->w + 10))/2;
	p->y = p->real_y = y + (image_height_all_eks_text - (p->h + 10))/2;

	if (p->border) {
	  p->real_x -= 5;
	  p->real_y -= 5;
	} else {
	  p->real_x -= 1;
	  p->real_y -= 1;
	}

	render->current.add(p);
      }
    }

    string old_name = name;
    
    string_format::format_to_size(name, "Vera/13", image_width_all-10, false);

    string name_second_part = old_name.substr(name.size());

    if (name_second_part.size() > 0 && name_second_part[0] != ' ') {
      // splitting words
      string::size_type last_whole_word = name.rfind(' ');
      if (last_whole_word != string::npos) {
	name = name.substr(0, last_whole_word);
	name_second_part = old_name.substr(name.size());
      }
    }

    int x_size, y_size;
    string_format::calculate_string_size(name, "Vera/13", &x_size, &y_size);


    string_format::format_to_size(name_second_part, "Vera/13", image_width_all-10, false);

    int x_size2;
    string_format::calculate_string_size(name_second_part, "Vera/13", &x_size2, &y_size);

    if (pos == j) {
      render->current.add(new TObj(name, "Vera/13", x + (image_width_all-x_size)/2, y+image_height_all_eks_text, 
				   themes->game_marked_font1, themes->game_marked_font2, 
				   themes->game_marked_font3, 3));
      render->current.add(new TObj(name_second_part, "Vera/13", x + (image_width_all-x_size2)/2, y+image_height_all_eks_text+20, 
				   themes->game_marked_font1, themes->game_marked_font2, 
				   themes->game_marked_font3, 3));
    } else {
      render->current.add(new TObj(name, "Vera/13", x + (image_width_all-x_size)/2, y+image_height_all_eks_text, 
				   themes->game_font1, themes->game_font2, 
				   themes->game_font3, 3));
      render->current.add(new TObj(name_second_part, "Vera/13", x + (image_width_all-x_size2)/2, y+image_height_all_eks_text+20, 
				   themes->game_font1, themes->game_font2, 
				   themes->game_font3, 3));
    }
    
    x += image_width_all;

    if (start == cur_files.size()-1) {
      if ((j+1)%images_per_row != 0)
	j += (images_per_row-(j+1)%images_per_row);
      
      x = x_start;
      y += cur_image_height_all;

      start = 0;
      continue;
      
    } else
      ++start;
    
    if ((j+1)%images_per_row == 0) {
      y += image_height_all;
      x = x_start;
    }
  }

  std::ostringstream position;

  if (search_mode)
    if (cur_files.size() > 0)
      position << offset + 1 << "/" << cur_files.size();
    else
      position << "";
  else
    position << folders.top().second+1 << "/" << cur_files.size();
  
  int x_size, y_size;
  string_format::calculate_string_size(position.str(), "Vera/18", &x_size, &y_size);
    
  render->current.add(new TObj(position.str(), "Vera/18", conf->p_v_res()-(60+x_size), 20, 
			       themes->game_font1, themes->game_font2, 
			       themes->game_font3, 3));

  render->draw("game-graphical");

  render->image_mut.leaveMutex();
}
#endif

void Game::print(const vector<Entry>& cur_files)
{
  render->prepare_new_image();

  render->current.add(new PObj(themes->game_background, 0, 0, 0, SCALE_FULL));
  
  render->current.add(new PObj(themes->startmenu_game_dir, 25, 10, 2, NOSCALING));
  
  if (themes->show_header) {
    render->current.add(new TObj(gettext("Games"), "Vera/28", 100, 10, 
				 themes->game_header_font1, themes->game_header_font2, 
				 themes->game_header_font3, 2));
  }
  
  if (search_mode) {
    render->current.add(new RObj(0, 60, conf->p_v_res(), 45, 
				 themes->general_search_rectangle_color1, 
				 themes->general_search_rectangle_color2, 
				 themes->general_search_rectangle_color3, 
				 themes->general_search_rectangle_color4, 2));

    render->current.add(new PObj(themes->general_search, 47, 60, 3, NOSCALING));

    render->current.add(new TObj(gettext("Search: ") + search_str, "Vera/22", 100, 65, 
				 themes->game_font1, themes->game_font2, 
				 themes->game_font3, 3));
  }
  
  if (cur_files.size() > 0) {
    TPRMovieFunctor<Game> print_func(this, &Game::print_game_element);
    if (search_mode && cur_files.size() > 0)
      print_range(cur_files, vector_lookup(cur_files, offset), 
		  offset, &print_func);
    else
      print_range(cur_files, vector_lookup(cur_files, folders.top().second), 
		  folders.top().second, &print_func);
  }

  std::ostringstream pos;

  if (search_mode)
    if (cur_files.size() > 0)
      pos << offset + 1 << "/" << cur_files.size();
    else
      pos << "";
  else
    pos << folders.top().second+1 << "/" << cur_files.size();
  
  int x, y;
  string_format::calculate_string_size(pos.str(), "Vera/18", &x, &y);
    
  render->current.add(new TObj(pos.str(), "Vera/18", conf->p_v_res()-(60+x), 20, 
			       themes->game_font1, themes->game_font2, 
			       themes->game_font3, 3));

  render->draw("game");

  render->image_mut.leaveMutex();
}

void Game::playgame(const Entry file)
{
  DialogWaitPrint pdialog(gettext("Starting Game..."), 1000);

  string cur_files = "";
  
  for (list<string>::const_iterator iter = (file.filenames).begin(); iter != (file.filenames).end(); ++iter)
       cur_files += " \"" + (*iter) + "\"";

  string cur_dir = file.filenames.front().substr(0,file.filenames.front().rfind("/")+1);

  // support playlist files
  if (file.filetype == "mame" || file_exists(cur_dir + "mame_roms")) {
    run::my_system((conf->p_mame_path() + " " + conf->p_mame_opts() + ' ' + cur_files).c_str());
  } else if (file.filetype == "snes" || file_exists(cur_dir + "snes_roms")) {
    run::my_system((conf->p_snes_path() + " " + conf->p_snes_opts() + ' ' + cur_files).c_str());
  } else if (file.filetype == "nes" || file_exists(cur_dir + "nes_roms")) {
    run::my_system((conf->p_nes_path() + " " + conf->p_nes_opts() + ' ' + cur_files).c_str());
  } else if (file.filetype == "gens" || file_exists(cur_dir + "gens_roms")) {
    run::my_system((conf->p_gens_path() + " " + conf->p_gens_opts() + ' ' + cur_files).c_str());
  } else if (file.filetype == "sh" || file_exists(cur_dir + "sh_scripts")) {
    run::my_system((cur_files).c_str());
  }
}

#ifdef use_media
// play everything on a cd
void Game::showcd(int count)
{
    vector<Entry> backup_files;

    backup_files = files;

    std::stack<std::pair<list<string>, int > > backup_folders = folders;

    list<string> dirs;
    dirs.push_back(cd->get_mount_point());

    files = parse_dir(dirs);

    while (!folders.empty())
      folders.pop();

    folders.push(std::make_pair(dirs, 0));

    mainloop();

    files = backup_files;
    folders = backup_folders;

  //umount the disc
  run::my_system_no_kill(("umount " + cd->get_mount_point()).c_str());
}

void Game::playpsx()
{
  string device = cd->get_device();

  //play disc
  if (conf->p_psxemu_enable()) {
    run::my_system((conf->p_psxemu_path() + ' ' + conf->p_psxemu_opts()).c_str());
  } else {
    DebugPrint perror(gettext("No psx emulator enabled in config file"),
		      Print::DEBUGGING, DebugPrint::CRITICAL, "GAME");
    return;
  }
}
#endif


// ====================================================================
//
// dir
//
// ====================================================================

// Add a file to the list
Entry Game::addfile(const string& name, const MyPair& filetype)
{
  Entry r;
  r.id = ++id;
  r.filenames.push_back(name);
  string tempname = name.substr(0, name.size()-((filetype.first).size()+1));
  string::size_type pos = tempname.rfind("/");
  if (pos != string::npos)
    r.name = tempname.substr(pos+1);
  else
    r.name = tempname;
  if (conf->p_convert())
    r.name = string_format::convert(r.name);
  r.lowercase_name = string_format::lowercase(r.name);
  r.type = "file";
  r.filetype = filetype.second;

  return r;
}

// Add a game dir as "one file" to the game list
Entry Game::add_dir(const string& filename)
{
  Entry output;

  string type = "";

  vector<string> known_filetypes;

  for (file_iterator<file_t, default_order> i (filename); i != i.end (); i.advance(false))
    {
      string name = i->getName();
      
      if (check_type(name, conf->p_filetypes_g()) != emptyMyPair) {
	known_filetypes.push_back(name);
	type = "rom";
      }
    }

  if (!known_filetypes.empty()) {
    output.id = ++id; 
    string::size_type pos = filename.rfind("/");
    output.name = filename.substr(pos+1);
    output.path = filename;

    output.type = "dir-single";
    if (known_filetypes.size() > 1) {
      string first = known_filetypes.front();
      vector<string>::iterator i = known_filetypes.begin();
      ++i;
      for (vector<string>::iterator end = known_filetypes.end();
	   i != end; ++i) 
	if (string_format::difference(first, *i) > 1) {
	  output.type = "dir-multi";
	  break;
	}
    }

    if (conf->p_convert())
      output.name = string_format::convert(output.name);

    const MyPair filetype = check_type(known_filetypes.front(), conf->p_filetypes_g());
    output.filetype = filetype.second; 
    for (vector<string>::iterator i = known_filetypes.begin(), end = known_filetypes.end();
	 i != end; ++i)
      output.filenames.push_back(*i);

  } else {

    output.id = ++id;
    string::size_type pos = filename.rfind("/");
    output.name = filename.substr(pos+1);
    output.type = "dir"; 
    output.path = filename;
    output.filetype = "dir";

  } 

  output.lowercase_name = string_format::lowercase(output.name);

  return output;
}

// read a dir and spit out a list of files and dirs. For games.
vector<Entry> Game::rdir(const string& argv)
{
  vector<Entry> cur_files;
  
  for (file_iterator<file_t, default_order> i (argv); i != i.end (); i.advance(false))
    {
      string filename = filesystem::FExpand(i->getName());

      if (filename.rfind("neogeo.") != string::npos) // Ignoring rom not playable, only necesary for others roms
      	continue;

      if (isDirectory (filename)) { // dir
	Entry dir = add_dir(filename);
	if ((dir.filenames).size() != 0 || dir.filetype == "dir")
	  cur_files.push_back(dir);
      } else { // file
	MyPair filetype = check_type(filename, conf->p_filetypes_g());
	if (filetype != emptyMyPair)
	  cur_files.push_back(addfile(filename, filetype));
      }
    }
  return cur_files;
}

vector<Entry> Game::parse_dir(const list<string>& dirs)
{
  vector<Entry> vec_files;

  for (list<string>::const_iterator iter = dirs.begin(); iter != dirs.end(); ++iter)
    {
      vector<Entry> tempfiles = rdir(*iter);

      for (vector<Entry>::const_iterator iter2 = tempfiles.begin(); iter2 != tempfiles.end(); ++iter2)
	vec_files.push_back(*iter2);
    }

  return vec_files;
}

void Game::read_dirs() 
{
    // process game dir 
    files = parse_dir(conf->p_game_dirs());

    if (conf->p_game_dirs().size() > 1)
      std::sort(files.begin(), files.end(), file_sort());

}

#ifdef use_media

void Game::determine_media()
{
 bool data_disc = cd->data_disc();
  cd->close();

  if (data_disc) {
    //mount the disc
    run::my_system_no_kill(("mount " + cd->get_mount_point()).c_str());
  
    int count;
    string mediatype = testdir(&count); 

    if (mediatype == "empty" || (mediatype == "psx" && !conf->p_psxemu_enable()))
      Print pdialog(gettext("The disc does not contain any recognizable files"),
		    Print::SCREEN);
    else if (count < 2)
      DialogWaitPrint pdialog(gettext("Starting Playback..."), 1000);

    if (mediatype != "roms")
      //umount the disc
      run::my_system_no_kill(("umount " + cd->get_mount_point()).c_str()); 
    
    if (mediatype == "roms")
      showcd(count);
    else if (mediatype == "psx" && conf->p_psxemu_enable())
      playpsx();
  } else {
    Print pdialog(gettext("The disc does not contain any recognizable files"),
		  Print::SCREEN);
  }
	
}

// help function for determine_media
string Game::testdir(int *count)
{
  *count = 0;

  for (file_iterator<file_t, default_order> i (cd->get_mount_point()); i != i.end (); ++i) 
    {
      string filename = filesystem::FExpand(i->getName());
      string cur_dir = string_format::lowercase(filename.substr(filename.rfind("/")+1));
	  
      if (isDirectory (filename)) {
		//++(*count);
      } else if (cur_dir == "system.cnf") { 
      	return "psx";
      } else {
	MyPair filetype = check_type(filename, conf->p_filetypes_g());
	if (filetype != emptyMyPair)
	  ++(*count);
      }
    }

  if (*count == 0)
    return "empty";
  else
    // none of the above found, it must be a divx
    return "roms";
}
#endif
