#include "config.h"

#include "libfspp.hpp"

#include "module.hpp"

#include "input.hpp"
#include "config.hpp"
#include "common.hpp"
#include "renderer.hpp"
#include "movie.hpp"

#include "updater.hpp"

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

#ifdef c_game
#include "game.hpp"
#endif

#include <iostream>

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

Module::Module() 
  : id(1), search_str(""), offset(0), search_mode(false)
{
  input_master = Input_master::get_instance();
  themes = Themes::get_instance();
  render = Render::get_instance();
  conf = Config::get_instance();
#ifdef use_media
  cd = Cd::get_instance();
#endif
}

string Module::greatest_common_substring(const string& lhs, const string& rhs)
{
  const int shortest = std::min(lhs.size(), rhs.size());

  string result = "";
  
  for (int i = 0; i < shortest; ++i)
    if (lhs[i] == rhs[i])
      result += lhs[i];
    else
      break;
  
  return result;
}

list<string> Module::keyboard_not_accepted()
{
  list<string> not_accepted_chars;
  not_accepted_chars.push_back("DEL");
  not_accepted_chars.push_back("INS");
  not_accepted_chars.push_back("TAB");
  not_accepted_chars.push_back("HOME");
  not_accepted_chars.push_back("END");
  not_accepted_chars.push_back("PGUP");
  not_accepted_chars.push_back("PGDOWN");
  not_accepted_chars.push_back("ESC");
  not_accepted_chars.push_back("RIGHT");
  not_accepted_chars.push_back("LEFT");
  not_accepted_chars.push_back("DOWN");
  not_accepted_chars.push_back("UP");
  not_accepted_chars.push_back("RSHIFT");
  not_accepted_chars.push_back("LSHIFT");
  not_accepted_chars.push_back("RCTRL");
  not_accepted_chars.push_back("LCTRL");
  not_accepted_chars.push_back("RALT");
  not_accepted_chars.push_back("LALT");
  not_accepted_chars.push_back("F1");
  not_accepted_chars.push_back("F2");
  not_accepted_chars.push_back("F3");
  not_accepted_chars.push_back("F4");
  not_accepted_chars.push_back("F5");
  not_accepted_chars.push_back("F6");
  not_accepted_chars.push_back("F7");
  not_accepted_chars.push_back("F8");
  not_accepted_chars.push_back("F9");
  not_accepted_chars.push_back("F10");
  not_accepted_chars.push_back("F11");
  not_accepted_chars.push_back("F12");
  return not_accepted_chars;
}

vector<vector<string> > Module::lirc_keys()
{
  string all_chars;

  if (conf->p_remote_layout() == MOBILE)
    all_chars = "1|abc2|def3|ghi4|jkl5|mno6|pqrs7|tuv8|wxyz9| 0";
  else
    all_chars = "ab1|cd2|ef3|ghi4|jkl5|mno6|pqr7|stu8|vwx9|yz 0";

  return parse_string(all_chars);
}

vector<vector<string> > Module::parse_string(string all_chars)
{
  vector<vector<string> > keys;
  
  string::size_type seperator_pos = 0;

  do {
    seperator_pos = all_chars.find('|');
    
    string chars = all_chars.substr(0, seperator_pos);

    vector<string> tmp;

    for (int i = 0; i < chars.size(); ++i)
      tmp.push_back(chars.substr(i, 1));

    keys.push_back(tmp);

    if (seperator_pos != string::npos)
      all_chars = all_chars.substr(seperator_pos+1);

  } while (seperator_pos != string::npos);

  return keys;
}

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

// check if the current file matches one of the types defined 
// in the configuration file pairs
MyPair Module::check_type(const string& s, const list<MyPair>& temp)
{
  for (list<MyPair>::const_iterator iter = temp.begin(); iter != temp.end(); ++iter)
    if (string_format::lowercase(s.substr(s.size() - (iter->first.size() + 1))) == "." + iter->first)
      return (*iter);
  return emptyMyPair;
}

// Add a file to the list
Simplefile Module::addsimplefile(const string& name, const MyPair& filetype, bool from_media)
{
  Simplefile r;
  r.id = ++id;
  r.path = name;

  string::size_type pos = name.rfind("/");
  if (pos != string::npos)
    r.name = name.substr(pos+1, name.size()-((pos+1)+(filetype.first.size()+1)));
  else
    r.name = name.substr(0, name.size()-(filetype.first.size()+1));

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

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

  if (from_media)
    r.type = "media-file";
  else
    r.type = filetype.second;

  return r;
}

string Module::get_cover_from_filename(const Simplefile& s)
{
  return get_cover(s.path);
}

string Module::get_cover(const std::string& s)
{
  string pic = "";

  string::size_type pos;

  if ((pos = s.rfind("/")) != string::npos)
    pic = get_cover_from_dir(s.substr(0, pos));

  return pic;
}

string Module::get_cover_from_dir(const string& dir)
{
  // check if we have already looked in folder
  std::map<std::string, string>::iterator cm_iter = cover_map.find(dir);
  if (cm_iter != cover_map.end())
    return cm_iter->second;

  string pic = "";

  vector<string> pictures_found;

  MyPair filetype;

  // determine if there is a picture in this dir...
  for (file_iterator<file_t, default_order> i (dir); i != i.end (); i.advance(false))
    {
      filetype = check_type(i->getName(), conf->p_filetypes_p());
      
      if (filetype != emptyMyPair)
	pictures_found.push_back(i->getName());
    }

  if (!pictures_found.empty()) {
    pic = pictures_found.front();
    if (pictures_found.size() > 1) {
      for (vector<string>::iterator iter = pictures_found.begin(); iter 
	     != pictures_found.end(); ++iter)
	if (string_format::lowercase(*iter).rfind("front") != string::npos) {
	  pic = *iter;
	  break;
	}
    }
  }

  cover_map.insert(std::make_pair(dir, pic));

  return pic;
}
